Skip to content

Visual Editor

Purpose and Scope

The Visual Editor is a browser-based 3D scene creation and manipulation tool that provides a complete graphical interface for building Three.js scenes. It allows users to create, import, edit, and export 3D content without writing code, featuring real-time rendering, visual property editing, and comprehensive undo/redo functionality.

For information about the examples system that demonstrates Three.js features, see Examples Browser. For rendering architecture details, see WebGL Rendering Pipeline.

Architecture Overview

SVG
100%

The editor follows a hub-and-spoke architecture where the Editor class acts as the central state manager, coordinating UI components through a signal-based event system. UI components (Viewport, Sidebar, Menubar, Toolbar) interact with the Editor instance but do not directly communicate with each other.

Editor Core Class

The Editor class manages scene state, object hierarchy, and coordinates all editor subsystems through a signal-based publish-subscribe system.

Signal System

SVG
100%

The Editor class initializes 40+ signals in its constructor editor/js/Editor.js19-96 These signals enable decoupled communication between subsystems. For example, when an object is modified, signals.objectChanged.dispatch(object) notifies all registered listeners without tight coupling.

State Management

PropertyTypePurpose
sceneTHREE.SceneMain scene graph
sceneHelpersTHREE.SceneHelper objects (grids, light helpers)
cameraTHREE.PerspectiveCameraDefault editor camera
viewportCameraTHREE.CameraActive viewport camera
selectedObject3DCurrently selected object
geometriesObjectGeometry UUID → geometry mapping
materialsObjectMaterial UUID → material mapping
texturesObjectTexture UUID → texture mapping
scriptsObjectObject UUID → script array mapping
helpersObjectObject ID → helper mapping
camerasObjectCamera UUID → camera mapping
materialsRefCounterMapTracks material usage count

The Editor maintains dictionaries of all scene resources indexed by UUID, enabling efficient lookups and reference tracking. The materialsRefCounter tracks how many objects use each material, preventing premature disposal editor/js/Editor.js123

JSON Serialization

SVG
100%

The toJSON() method editor/js/Editor.js703-741 serializes the entire editor state including scene hierarchy, scripts, history, and project configuration. The fromJSON() method editor/js/Editor.js668-701 uses THREE.ObjectLoader to reconstruct the scene, preserving UUIDs and relationships.

UI Component Hierarchy

The editor interface consists of five main UI components arranged around a central viewport.

SVG
100%

Viewport Component

The Viewport class manages the 3D rendering surface and object manipulation controls.

SVG
100%

The Viewport component manages three rendering passes:

  1. Main scene rendering editor/js/Viewport.js891
  2. Grid helper rendering (if visible) editor/js/Viewport.js896
  3. Scene helpers rendering (lights, cameras, skeletons) editor/js/Viewport.js897

The TransformControls emit events when objects are manipulated editor/js/Viewport.js78-144 and the viewport creates corresponding command objects to enable undo/redo functionality.

Viewport Shading Modes

ModeImplementationPurpose
solidDefault renderingStandard material display
normalsscene.overrideMaterial = MeshNormalMaterialVisualize surface normals
wireframescene.overrideMaterial = MeshBasicMaterial({wireframe: true})Show mesh topology
realisticViewportPathtracer + three-gpu-pathtracerPhysically accurate rendering

Sources: editor/js/Viewport.js678-704

The Sidebar uses a tabbed panel structure with four main tabs.

SVG
100%

The UIOutliner component editor/js/Sidebar.Scene.js132 displays the scene hierarchy as a collapsible tree, supporting drag-and-drop reordering. Each node shows type icons and associated resources (geometry, material, scripts) editor/js/Sidebar.Scene.js100-128

SVG
100%

The MenubarFile component provides export functionality using dynamic imports of exporter modules editor/js/Menubar.File.js250-445 keeping the initial bundle size small while supporting multiple export formats.

Command Pattern for Undo/Redo

The editor implements a command pattern through the History class and command objects, enabling full undo/redo functionality.

SVG
100%

Command Classes

Command ClassPurposeKey Methods
AddObjectCommandAdd object to sceneexecute(): adds object, undo(): removes object
RemoveObjectCommandRemove object from sceneInverse of AddObjectCommand
SetPositionCommandChange object positionStores old/new positions
SetRotationCommandChange object rotationStores old/new rotations
SetScaleCommandChange object scaleStores old/new scales
SetGeometryCommandReplace object geometrySwaps geometry references
SetMaterialCommandReplace object materialSwaps material references
SetValueCommandChange arbitrary propertyGeneric property setter
MultiCmdsCommandExecute multiple commandsComposite command pattern

Commands can merge with previous commands via the update() method editor/js/Command.js27-31 preventing history spam from continuous value changes (e.g., dragging a slider).

History Persistence

SVG
100%

When settings/history is enabled in the config editor/js/Config.js24 the history is serialized alongside the project and persisted across sessions editor/js/History.js80-150 This allows users to undo changes even after closing and reopening the editor.

File Loading System

The Loader class supports importing 30+ file formats through dynamic module loading.

SVG
100%

Dynamic Import Strategy

The loader uses dynamic import() to load format-specific parsers on-demand editor/js/Loader.js89-959 reducing the initial bundle size:

// Example: GLTF loading
case 'glb':
    reader.addEventListener('load', async function(event) {
        const { GLTFLoader } = await import('three/addons/loaders/GLTFLoader.js');
        const loader = await createGLTFLoader();
        loader.parse(contents, '', function(result) {
            const scene = result.scene;
            scene.animations.push(...result.animations);
            editor.execute(new AddObjectCommand(editor, scene));
        });
    });

GLTF Loader Configuration

The createGLTFLoader() function editor/js/Loader.js954-976 configures a GLTFLoader with:

The KTX2 loader is synchronized with the renderer's capabilities via signals.rendererDetectKTX2Support editor/js/Loader.js967

ZIP Archive Support

The loader can extract and process ZIP archives editor/js/Loader.js747-760 automatically detecting Poly assets (model.obj + materials.mtl) or individual files within the archive editor/js/Loader.js842-951

Storage and Persistence

The editor implements a two-tier storage system for configuration and project data.

SVG
100%

Auto-save Implementation

The auto-save mechanism listens to 10+ signals editor/index.html163-173 and triggers a debounced save after 1000ms of inactivity editor/index.html145-157 The debounce prevents excessive writes during rapid changes:

let timeout;
function saveState() {
    if (editor.config.getKey('autosave') === false) return;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
        editor.signals.savingStarted.dispatch();
        timeout = setTimeout(function() {
            editor.storage.set(editor.toJSON());
            editor.signals.savingFinished.dispatch();
        }, 100);
    }, 1000);
}

IndexedDB Schema

The Storage class editor/js/Storage.js1-92 uses IndexedDB with a single object store:

DatabaseObject StoreKeyValue
threejs-editorstates0 (fixed)Complete project JSON

Service Worker and Offline Support

The editor registers a service worker for offline functionality and cross-origin isolation.

SVG
100%

The service worker implements a network-first caching strategy editor/sw.js284-323 that:

  1. Attempts to fetch from network
  2. Injects COEP/COOP headers for the editor page editor/sw.js290-297
  3. Updates cache on successful fetch
  4. Falls back to cached version if network fails

This enables the Draco, Rhino3dm, and Basis Universal WASM decoders to use SharedArrayBuffer for better performance.

Internationalization

The Strings class provides multi-language support for UI text.

SVG
100%

The strings dictionary uses hierarchical keys (e.g., menubar/file/open, sidebar/object/position) editor/js/Strings.js417-571 The language is auto-detected from navigator.language but can be changed in settings editor/js/Config.js5-7