Documentation is work in progress and not completeEditor

Overview

The 3D feature system enables users to embed live, interactive Three.js viewports directly into the 2D design canvas. Each 3D shape behaves like any other canvas element — it can be repositioned, resized, layered, have its opacity adjusted, and participate in the animation timeline — but internally it contains a fully independent Three.js scene where users can place, transform, and material-paint 3D primitives or imported models.

Snapshot-Bridge Architecture

The core architectural idea is called the snapshot-bridge. Every 3D shape on the 2D canvas is a live Three.js renderer embedded as an HTML <canvas> element inside a <div> that is absolutely positioned within the 2D canvas artboard. The 2D canvas system controls where the 3D viewport sits (position, size, rotation, opacity), while the Three.js renderer controls what is drawn inside it.

This approach was chosen over two alternatives:

  • Single shared Three.js scene — rejected because it creates stacking and z-order conflicts between shapes, and because deletion of one shape would require surgical extraction from a shared scene graph. A bug where shapes would disappear 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.
┌─────────────────────────────────────────────────┐
│              2D Canvas (Artboard)                │
│                                                  │
│   ┌──────────────────┐  ┌──────────────────┐     │
│   │ <div> host        │  │ <div> host        │    │
│   │  ┌──────────────┐ │  │  ┌──────────────┐ │   │
│   │  │ WebGLRenderer │ │  │  │ WebGLRenderer │ │   │
│   │  │   <canvas>    │ │  │  │   <canvas>    │ │   │
│   │  │              │ │  │  │              │ │   │
│   │  │  Scene       │ │  │  │  Scene       │ │   │
│   │  │  Camera      │ │  │  │  Camera      │ │   │
│   │  │  OrbitCtrl   │ │  │  │  OrbitCtrl   │ │   │
│   │  └──────────────┘ │  │  └──────────────┘ │   │
│   │  ThreeDShapeElem  │  │  ThreeDShapeElem  │   │
│   └──────────────────┘  └──────────────────┘     │
│                                                  │
│   CSS transform on artboard handles zoom/pan     │
└─────────────────────────────────────────────────┘

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 (e.g. 'box')
threeDSceneStateSceneStateSnapshotLive scene state used for persistence and restoration

These fields are defined in src/types/design.ts (lines 200-205).