Skip to content

Added new DevTools #30870

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 39 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
03bc87f
Added new DevTools
mrdoob Apr 5, 2025
42cbb1f
Potential fix for code scanning alert no. 3463: Useless assignment to…
mrdoob Apr 5, 2025
676f7ad
Clean up.
mrdoob Apr 5, 2025
05b4f75
Clean up.
mrdoob Apr 5, 2025
9a7d001
Clean up.
mrdoob Apr 5, 2025
b77af0c
Clean up.
mrdoob Apr 5, 2025
1e071da
Clean up.
mrdoob Apr 5, 2025
25f8efe
Clean up.
mrdoob Apr 5, 2025
6783910
Clean up.
mrdoob Apr 5, 2025
09b6fd6
Fixed renderer parameters not updating.
mrdoob Apr 5, 2025
68bf958
Simplified code.
mrdoob Apr 5, 2025
af85042
Merge branch 'dev' into devtools
mrdoob Apr 5, 2025
09422b2
Optimized scene handling.
mrdoob Apr 5, 2025
d43d66a
Clean up.
mrdoob Apr 5, 2025
3cbd00d
Removed unused file.
mrdoob Apr 5, 2025
8605078
Robustness.
mrdoob Apr 5, 2025
ec6126d
Clean up.
mrdoob Apr 5, 2025
4bbab46
Removed premature caching.
mrdoob Apr 5, 2025
425407c
Refresh the scene graph once a second.
mrdoob Apr 6, 2025
d214ebe
Fixed object counts.
mrdoob Apr 6, 2025
be4c87d
Updated README.
mrdoob Apr 6, 2025
2dbc9e0
Added InstancedMesh support.
mrdoob Apr 6, 2025
dca9884
Improved InstancedMesh support.
mrdoob Apr 6, 2025
0c3e75b
Refactored renderers code.
mrdoob Apr 7, 2025
9dd8e82
Clean up.
mrdoob Apr 7, 2025
7ea0c29
Okay Copilot.
mrdoob Apr 7, 2025
e3ae7f2
Clean up.
mrdoob Apr 7, 2025
fde3409
Clean up.
mrdoob Apr 7, 2025
0cfc8ae
Clean up.
mrdoob Apr 7, 2025
ef72610
Clean up.
mrdoob Apr 7, 2025
898e1f2
Clean up.
mrdoob Apr 7, 2025
4d768a9
Merge branch 'dev' into devtools
mrdoob Apr 7, 2025
4ae168f
Bring back renderer properties.
mrdoob Apr 7, 2025
a00e667
Improved versionInfo section.
mrdoob Apr 7, 2025
8bcee5d
Merge branch 'dev' into devtools
mrdoob Apr 13, 2025
64b824a
Added WebGPURenderer support.
mrdoob Apr 13, 2025
46ab812
Fix devtools littering window object (#30950)
cesmoak Apr 18, 2025
dfbbe17
Add styles for dark mode theme (#30958)
Darkensses Apr 23, 2025
32b1bc3
Update version.
mrdoob Apr 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions devtools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Three.js DevTools Extension

This Chrome DevTools extension provides debugging capabilities for Three.js applications. It allows you to inspect scenes, objects, materials, and renderers.

## Installation

1. **Development Mode**:
- Open Chrome and navigate to `chrome://extensions/`
- Enable "Developer mode" (toggle in the top-right corner)
- Click "Load unpacked" and select the `devtools` directory
- The extension will now be available in Chrome DevTools when inspecting pages that use Three.js

2. **Usage**:
- Open Chrome DevTools on a page using Three.js (F12 or Right-click > Inspect)
- Click on the "Three.js" tab in DevTools
- The panel will automatically detect and display Three.js scenes and renderers found on the page.

## Code Flow Overview

### Extension Architecture

The extension follows a standard Chrome DevTools extension architecture:

1. **Background Script** (`background.js`): Manages the extension lifecycle and communication ports between the panel and content script.
2. **DevTools Script** (`devtools.js`): Creates the panel when the DevTools window opens.
3. **Panel UI** (`panel/panel.html`, `panel/panel.js`, `panel/panel.css`): The DevTools panel interface that displays the data.
4. **Content Script** (`content-script.js`): Injected into the web page. Relays messages between the background script and the bridge script.
5. **Bridge Script** (`bridge.js`): Injected into the page's context by the content script. Directly interacts with the Three.js instance, detects objects, gathers data, and communicates back via the content script.

### Initialization Flow

1. When a page loads, `content-script.js` injects `bridge.js` into the page.
2. `bridge.js` creates the `window.__THREE_DEVTOOLS__` global object.
3. When the DevTools panel is opened, `panel.js` connects to `background.js` (`init`) and immediately requests the current state (`request-state`).
4. `background.js` relays the state request to `content-script.js`, which posts it to `bridge.js`.
5. `bridge.js` responds by sending back observed renderer data (`renderer` message) and batched scene data (`scene` message).
6. Three.js detects `window.__THREE_DEVTOOLS__` and sends registration/observation events to the bridge script as objects are created or the library initializes.

### Bridge Operation (`bridge.js`)

The bridge acts as the communication layer between the Three.js instance on the page and the DevTools panel:

1. **Event Management**: Creates a custom event target (`DevToolsEventTarget`) to manage communication readiness and backlog events before the panel connects.
2. **Object Tracking**:
- `getObjectData()`: Extracts essential data (UUID, type, name, parent, children, etc.) from Three.js objects.
- Maintains a local map (`devTools.objects`) of all observed objects.

3. **Initial Observation & Batching**:
- When Three.js sends an `observe` event (via `window.__THREE_DEVTOOLS__.dispatchEvent`):
- If it's a renderer, its data is collected and sent immediately via a `'renderer'` message.
- If it's a scene, the bridge traverses the entire scene graph, collects data for the scene and all descendants, stores them locally, and sends them to the panel in a single `'scene'` batch message.

4. **State Request Handling**:
- When the panel sends `request-state` (on load/reload), the bridge iterates its known objects and sends back the current renderer data (`'renderer'`) and scene data (`'scene'` batch).

5. **Message Handling**:
- Listens for messages from the panel (relayed via content script) like `request-state`.

### Panel Interface (`panel/`)

The panel UI provides the visual representation of the Three.js objects:

1. **Tree View**: Displays hierarchical representation of scenes and objects.
2. **Renderer Details**: Shows properties and statistics for renderers in a collapsible section.

## Key Features

- **Scene Hierarchy Visualization**: Browse the complete scene graph.
- **Object Inspection**: View basic object properties (type, name).
- **Renderer Details**: View properties, render stats, and memory usage for `WebGLRenderer` instances.

## Communication Flow

1. **Panel ↔ Background ↔ Content Script**: Standard extension messaging for panel initialization and state requests (`init`, `request-state`).
2. **Three.js → Bridge**: Three.js detects `window.__THREE_DEVTOOLS__` and uses its `dispatchEvent` method (sending `'register'`, `'observe'`).
3. **Bridge → Content Script**: Bridge uses `window.postMessage` to send data (`'register'`, `'renderer'`, `'scene'`, `'update'`) to the content script.
4. **Content Script → Background**: Content script uses `chrome.runtime.sendMessage` to relay messages from the bridge to the background.
5. **Background → Panel**: Background script uses the established port connection (`port.postMessage`) to send data to the panel.

## Key Components

- **DevToolsEventTarget**: Custom event system with backlogging for async loading.
- **Object Observation & Batching**: Efficiently tracks and sends scene graph data.
- **Renderer Property Display**: Shows detailed statistics for renderers.

## Integration with Three.js

The extension relies on Three.js having built-in support for DevTools. When Three.js detects the presence of `window.__THREE_DEVTOOLS__`, it interacts with it, primarily by dispatching events.

The bridge script listens for these events, organizes the data, and provides it to the DevTools panel.

## Development

To modify the extension:

1. Edit the relevant files in the `devtools` directory.
2. Go to `chrome://extensions/`, find the unpacked extension, and click the reload icon.
3. Close and reopen DevTools on the inspected page to see your changes.
61 changes: 61 additions & 0 deletions devtools/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Map tab IDs to connections
const connections = new Map();

// Listen for connections from the devtools panel
chrome.runtime.onConnect.addListener(port => {
let tabId;

// Listen for messages from the devtools panel
port.onMessage.addListener(message => {
if (message.name === 'init') {
tabId = message.tabId;
connections.set(tabId, port);
} else if (message.name === 'request-state' && tabId) {
chrome.tabs.sendMessage(tabId, message);
} else if (tabId === undefined) {
console.warn('Background: Message received from panel before init:', message);
}
});

// Clean up when devtools is closed
port.onDisconnect.addListener(() => {
if (tabId) {
connections.delete(tabId);
}
});
});

// Listen for messages from the content script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (sender.tab) {
const tabId = sender.tab.id;
const port = connections.get(tabId);
if (port) {
// Forward the message to the devtools panel
try {
port.postMessage(message);
// Send immediate response to avoid "message channel closed" error
sendResponse({ received: true });
} catch (e) {
console.error('Error posting message to devtools:', e);
// If the port is broken, clean up the connection
connections.delete(tabId);
}
}
}
return false; // Return false to indicate synchronous handling
});

// Listen for page navigation events
chrome.webNavigation.onCommitted.addListener(details => {
const { tabId, frameId } = details;
const port = connections.get(tabId);

if (port) {
port.postMessage({
id: 'three-devtools',
type: 'committed',
frameId: frameId
});
}
});
Loading