Three.js From Zero · Article s8-04
S8-04 Scene Authoring
Season 8 · Article 04
Scene Authoring Tools
Build an editor inside your app. Click to add objects. TransformControls to move/rotate/scale. Inspector panel for properties. Save/load JSON. Non-programmers can populate your world.
1. The minimum viable editor
- Click canvas → raycast → select object.
- TransformControls attached → drag to move/rotate/scale.
- Delete key → remove.
- Toolbar → add primitives (box, sphere).
- Save → serialize scene to JSON + download.
- Load → parse JSON + rebuild.
2. TransformControls
import { TransformControls } from 'three/addons/controls/TransformControls.js';
const tc = new TransformControls(camera, renderer.domElement);
tc.addEventListener('dragging-changed', e => {
orbitControls.enabled = !e.value; // disable orbit while dragging
});
tc.setMode('translate'); // or 'rotate', 'scale'
scene.add(tc);
function select(obj) {
tc.attach(obj);
updateInspector(obj);
}
3. Serialize to JSON
Three.js's toJSON:
const json = scene.toJSON();
downloadAsFile('scene.json', JSON.stringify(json, null, 2));
// Load
const loaded = await fetch('scene.json').then(r => r.json());
const loader = new THREE.ObjectLoader();
const scene2 = loader.parse(loaded);
Handles geometry, materials, lights, cameras, textures (embedded or referenced).
4. Inspector panel
function updateInspector(obj) {
inspectorEl.innerHTML = `
<div>Position: ${obj.position.x.toFixed(2)}, ${obj.position.y.toFixed(2)}, ...</div>
<div>Rotation: ${obj.rotation.x}...</div>
<input type="color" value="${obj.material?.color?.getHexString?.()}" onchange="obj.material.color.set(this.value)" />
`;
}
For real apps: lil-gui or leva. Auto-generated GUI from an object schema.
5. lil-gui for quick inspectors
import GUI from 'lil-gui';
const gui = new GUI();
function buildInspector(obj) {
gui.destroy(); gui = new GUI();
gui.add(obj.position, 'x', -10, 10);
gui.add(obj.position, 'y', -10, 10);
gui.addColor(obj.material, 'color');
}
6. Undo/redo
const history = [];
let historyIdx = -1;
function commit(action) {
history.splice(historyIdx + 1); // drop redo branch
history.push(action);
historyIdx++;
}
function undo() { if (historyIdx >= 0) history[historyIdx--].undo(); }
function redo() { if (historyIdx + 1 < history.length) history[++historyIdx].do(); }
7. Live demo — mini editor
Click to select. T/R/S to switch mode. Delete to remove. Add buttons to spawn primitives. Save dumps JSON to console.
–
8. three.js editor as reference
Official editor is open-source — study its code for a production pattern. It's basically what we built above × 20 features.
9. Takeaways
- TransformControls: drag handles for move/rotate/scale.
- scene.toJSON() / ObjectLoader.parse() for persistence.
- lil-gui for quick inspectors, leva for fancier.
- Undo/redo: command pattern with do/undo closures.
- Official three.js editor source is a masterclass.