threejs / three-devtools Goto Github PK
View Code? Open in Web Editor NEWthree.js devtools
Home Page: https://chrome.google.com/webstore/detail/threejs-developer-tools/ebpnegggocnnhleeicgljbedjkganaek
License: MIT License
three.js devtools
Home Page: https://chrome.google.com/webstore/detail/threejs-developer-tools/ebpnegggocnnhleeicgljbedjkganaek
License: MIT License
Essentially a tiny model-viewer for objects, and a preview for material and geometry and textures, possibly offering different views (e.g. like Unity, material previewed on several objects, projections)
Broadly this is unimplemented. We could should a preview of the mesh as well.
Reproducible on model-viewer examples: https://googlewebcomponents.github.io/model-viewer/examples/lighting-and-environment.html
This prevents loading additional scene content AFAICT and results in an inaccurate view of the scene.
5CD06464-8015-40EC-B682-7BD3368967A4 does not appear to be serializable. TypeError: this.background.toJSON is not a function
at ModelScene.toJSON (three.module.js:25345)
at Object.serializeEntity (<anonymous>:77:50)
at EventTarget.__requestEntity (<anonymous>:234:20)
at <anonymous>:1:15
We need to display a way (dropdown?) to select registered views as the current scene.
There should be an easy way to filter scene/resource views by name/type; a search against a handful of entity properties. Potentially its dependents as well, e.g. a "MeshStandardMaterial" search could reveal objects in the scene graph that use a standard material.
Adjacent to #16, any scene with an object that cannot be serialized (WebGLRenderTarget, DataTexture, InterleavedBufferAttribute) throws an error during serialization, preventing any information from the scene being parseable without reimplementing toJSON()
, which is something I'd like to avoid.
While a stretch goal would be to somehow interpret these dynamic objects, the minimum needed in order for a scene to be debugged would be for these unserializable objects to return stubs (e.g. { width, height, type }
for WebGLRenderTarget maybe), or less preferably, skipped during serialization (I'd rather be aware of the objects and not be able to represent them fully).
Requires a handful of fixes upstream:
In the Parameters view, geometry should show a preview(?) and click through to select the corresponding geometry. It does not have to update if the underlying geometry is updated. Upon object selection, the geometry will be fetched and accessible via ContentBridge.
Probably via element.scrollIntoView()
on new selection if necessary
When loading the extension as a developer in Chrome, as noted in DEVELOPMENT.md, the browser_specific_settings
key is unrecognized, even though it's a part of Web Extensions in use by Firefox and Edge.
No adverse affects other than being annoying and masking other potential issues. Building locally creates a version of the manifest for Chrome, stripping this key.
Probably needs to be added to three.js
More information on current injection mechanism and proposals documented in DEVELOPMENT.md:
Why is injection so weird?
Content scripts have access to the DOM, but cannot access any globals from user-land script (e.g. code from script elements on a page). In order to access the three.js entities on the page, an additional script needs to be injected as if it were regular user-land script, by literally injecting a
<script>
element with our injection code.
There are a few options to handle this.
- Synchronous injection at document_start
- This is the current implementation. Non-ideal as this is evaluated on every page load, and injecting content on every page load. This is what redux-devtools does, with a rather large content script. The challenge here is defining some object in the user context immediately (
window.ThreeDevTools
) so that content can access it, even if it's defined in the<head>
.- I attempted a system where opening devtools lands a cookie allowing that domain to inject content for the next few minutes, as cookies can be checked synchronously to determine if injection is needed. Was flaky, but due to extension confusion I think.
- The global indicates that the extension is installed, not open, if that matters to the content.
- Need to set text content rather than src of injection script to guarantee sync inject (#1).
- Port messaging
- Something like
window.postMessage({ type: 'three-devtools-connect' })
that doesn't need to exist in global space before content runs, so synchronous code injection no longer needed.- Could have a purely
postMessage
API and no global.- Less inspectable than a singleton
- Moves code from injected code to content script code -- could the extra content script be lazily brought in on first sign of a post message?
Opening this issue for discussion on alternatives to this injection mechanism, as well as API design.
Which results in looking at textures etc. and not finding the texture, even with a refresh. Ultimately a syncing issue, and an attempt to scope the resources used only for the current scene.
InstancedBufferGeometry's parameters default to an "Object3D" view rather than the geometry view. Easy fix here, just need to add IBG to src/app/data/geometry.js
It should be possible to manually refresh a view. Currently when opening a view of some entity, most views will request the latest data. If the object updates, the user should be able to manually request an update.
This could be helpful for the scene, resource and entity views
When selecting something from the resource view, and going back to the scene graph view for a selection, the selection gets out of sync.
What changes are needed here?
Currently resources will show all resources from all scenes, as entities can be shared across scenes. We could make resources a child of a scene, and possibly toggling between the 'graph' view and the 'resources' view.
Opening this issue for general discussion/ideas.
For me the link to the chrome web store is broken. I don't find the extension either by manually searching for "three.js".
src/extensions/contentScript.js:57 throws "Uncaught Error: Extension context invalidated." after the devtools are reloaded. Maybe a nice way to handle this other than wrap in a try/catch. Probably only happens to folks developing on the extension itself. But this pollutes up the console, as well as warnings in chrome://extensions
Please see mrdoob/three.js#18759 (comment)
TL;DR just by installing and enabling this tool AND NOT using API in the app code in any way memory leakage is created. That leads to false assumptions when developing app based on Three.js. My assumption was first that my code leaks, then that Three.js lib has bug - based on latest tests leakage occurs when this tool is installed in Chrome.
This broadly needs more investigation.
toJSON()
cycle in content, potentially causing large amounts of jank from serializing and sending giant strings of textures or bufferstoJSON
method for some type, like to only serialize the first n
children, is there a way to do that without having to duplicate/rewrite the serialization logic for objects, materials, textures, etc...An option for downloading objects or scenes for further inspection in the editor would be nice.
I'm currently using this snippet in the inspector that I run every time I want to download the scene.
let main = window.g_main || window.main;
let scene = main.game.scene;
scene.traverse(obj => obj.updateMatrix());
let str = JSON.stringify(scene.toJSON());
let aEl = document.createElement('a');
aEl.setAttribute("href", window.URL.createObjectURL(new Blob([str], {type: 'text/plain'})));
aEl.setAttribute("download", "scene.json");
aEl.click();
But it depends on g_main.game.scene existing. It would be nice to have a more general solution.
Right now this is not styled at all, and polls for data every second on the current renderer. Some things that are needed:
Reproducible on many model-viewer demos since everything is loaded magically, need to determine when to reserialize and flush new data. Right now, content can be stale.
The early abort in __requestEntity
in content is a part of the culprit at least.
We don't want to be over eager and push any changes, but it's easy to be in a scenario viewing a scene and something is added to it after the initial load. Adding a manual refresh would be great, but that seems like a bit much for some cases where it'll be the default. Maybe something like, for new scenes, we poll for changes for the first n
seconds? Changing the current scene for example will refresh.
Reloading is a part of the development cycle, requiring reloading the tools often. It should return to the previous layout, and attempt to select the previously selected entity.
Potential issues:
This is an important but tricky one.
Using composer/effects pass and other renders requires manually setting reset on renderer.info for accurate draw counts. It'd be useful to provide information pointing to that in the docs if the numbers don't look right, or maybe if there's only 2 triangles being rendered as a common pattern.
Right now it's being streamed during render, nonstop. Once moving renderer to a new view, this should only be pulled when in use (e.g. debugging rendering/perf, not viewing the scene graph)
Tool should allow resizing, and the remembering, of the main panels in the tool.
Currently the Object View supports values from Object3D and Mesh; Lights, lines, helpers, and skeleton/bones are not yet supported. Could possibly implement these as subclasses of the Object View, or pile it all in the view, like Material View.
By wrapping a helper (for Objects) or highlighting (material) for example
For example, here, the materials' wireframe property is not properly rendering as a boolean (checkbox) and other wireframe properties, but not limited to those. Same with environment values (which I know there were some changes recently, but these values are still supported in standard materials).
In the Parameters view, the material should show a preview and click through to select the corresponding material. It does not have to update if the underlying material is updated. Upon object selection, the material will be fetched and accessible via ContentBridge.
Vestigial MaterialValueElement lives at src/app/values/MaterialValueElement.js
.
Guessing it's being swallowed somewhere. It works when going from the three tools, to another panel, then back to three tools. Upon interaction, the event is swallowed somewhere (nothing immediately comes to mind).
If three.js registers all scenes/renderers automatically, or working with many scenes, it should be possible for content to define what the "primary" scene is, or a way to select a new scene, e.g.:
window.ThreeDevTools.select(scene);
Similarly, if I'm debugging some Object that's deeply nested, on page reload I want to select the same object on load. Remembering that object could be handled across page load (inconsistent UUIDs may make that a challenge, but should be doable), but that's a slightly different case of defining it via content, which resets to a specific state on reload, and also provides a way for devs to interface with the tools via console
window.ThreeDevTools.select(myObject);
I've successfully used webextension-polyfill in the past; I don't think we are using any unsupported/Chromium-only APIs.
In the Parameters view, the texture should show a preview and click through to select the corresponding texture. It does not have to update if the underlying texture is updated. Upon material (or object) selection containing the texture, the texture will be fetched and accessible via ContentBridge.
Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).
Because the contentScript.js injects a payload into the user-space to access the Three objects, CSP settings can prevent inline script injections. No immediately solutions come to mind for debugging arbitrary three scenes, although we might be able to tag the script such that site owners can make an exception to the injected code (maybe by not inlining it and instead reference the allowlisted extension source, maybe an SRI attribute although that'd change for every release).
There should be a data structure showing which properties of which types of entities to display. May need to use ObjectLoader, since the serialization process assumes use with ObjectLoader, and leaves out properties otherwise e.g. "foo" is 1 by default for ObjectType, so it's not in the JSON payload, but hydrated as "1" when going through the ObjectLoader.
Mostly refactoring, but will result in a more consistent parameter view since the individual views for these are pretty messy.
A handful of material types are not yet supported in MaterialView; they're displayed and showed, but any subclass material properties or defaults are not handled for the following types:
'MeshDistanceMaterial': 'distance',
'MeshMatcapMaterial': 'matcap',
'MeshNormalMaterial': 'normal',
'MeshPhongMaterial': 'phong',
'PointsMaterial': 'points',
'ShadowMaterial': 'shadow',
'SpriteMaterial': 'sprite',
'RawShaderMaterial': 'raw',
'ShaderMaterial': 'shader',
Right now there are a lot of logs everywhere. It's helpful getting some of that information, even in non-development, and could be helpful displaying some information in the main content window. Either way, the sporadic logging should be cleaned up, and a consistent, smart logging system should be put in its place.
Support LightProbe (and AmbientLightProbe, and HemisphereLightProbe), as well as a way to render SphericalHarmonics3
Until we're able to automatically notify the dev-tools when the scene graph changes it would be nice to have a refresh button to force re-serialisation.
When trying to inspect https://threejs.org/examples/webgl_animation_keyframes.html the scene is not ready by the time is being serialised and the dev-tools only show a couple of lights.
Serialization is what blocks rendering on the content (often twice: once for the toJSON()
call and once for the postMessage()
, which seems roughly about three times the size of the toJSON()
). This can be observed in Chromium's violation warnings. For example, this example with geometry with position, size, and color attributes results in the warning, where 'refresh' is the serialization and 'message' is passing that to the extension:
[Violation] 'refresh' handler took 179ms
[Violation] 'message' handler took 574ms
This may be a prereq for #33, since we'll be able to more aggressively sync with content without incurring long jank times.
With circumventing three's serialization in #31, a cache can be injected here for costly objects if the meta
object has some flag. That way, when serializing a scene for example, any 'expensive' objects will only return their basic structured data, minus expensive properties.
The objects can be fully serialized as needed when the corresponding object is being inspected.
Expensive items AFAIK:
Since textures aren't generally changing, especially when loaded from an image, we can also serialize these up front. Canvas, WebGLRenderTargets, data textures and video textures are a bit different, but for the most part, serializing once initially should be sufficient, and significantly decrease future serialization costs. For the special texture cases, they can be refreshed when that texture is being inspected. This gives the ability to render texture previews, for example, before a specific texture is inspected.
The "Value" type elements are inline elements that can display data, and optionally allow edits.
For example, on the right side there are value elements for uneditable strings, enums, boolean, color.
More complex data structures can be represented, like a Material (below) or textures. Note that plumbing exists so that the value elements can be used as a preview (e.g. Material right now displays as a block with whatever color the material has set)
There is a lot of styling love needed, as well as supporting more complex data structures, like vec2/vec3/vec4 and matrices.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.