Documentation is work in progress and not completeEditor
3D System

Per-Shape Renderer Model

Each ThreeDShapeElement instance owns exactly one isolated Three.js world: one WebGLRenderer, one Scene, one PerspectiveCamera and one set of OrbitControls. Shapes do not share any Three.js resources.

Why Isolation

The design is documented directly in the source header of ThreeDShapeElement.ts, and it exists to guarantee three properties:

  • Clean disposal — when a shape is deleted, its entire GL context, all geometries, materials and textures are released in a single deterministic dispose() call.
  • Independent animation — each shape renders only when its own dirty flag is set, keeping GPU work minimal when shapes are idle.
  • No cross-contamination — selecting, transforming or changing the material of one shape has zero effect on the rendering of any other shape.

Rejected Alternatives

Two other approaches were considered and rejected:

  • Single shared Three.js scene — rejected because it creates stacking and z-order conflicts between shapes, and because deleting one shape would require surgical extraction from a shared scene graph. A bug where shapes disappeared when another was deselected drove the switch to isolation.
  • Offline render-to-texture — rejected because it cannot provide real-time orbit interaction. The user needs to orbit, zoom and pan inside each shape independently while editing.

Tradeoffs

Consequence
ProComplete isolation. Deleting a shape is a single dispose() call with no entanglement.
ProIndependent dirty flags mean idle shapes consume zero GPU time.
ProNo z-order or stacking conflicts between shapes.
ConEach shape creates its own WebGL context. Browsers enforce a hard limit, typically 8-16 active contexts. Exceeding it causes the oldest context to be silently lost.
The context limit is the practical ceiling on how many 3D shapes can be live at once. Under 8 simultaneous shapes is safe across all browsers.

The 2D/3D Bridge

The bridge between the 2D world and the 3D world is the DesignElement type. Every 2D element with type === "threed-shape" stores three optional 3D fields:

FieldTypePurpose
threeDMetadataThreeDMetadataSerialized scene snapshot metadata for project save/load
threeDGeometryTypeGeometryTypeThe primitive type the shape was created with
threeDSceneStateSceneStateSnapshotLive scene state used for persistence and restoration