Documentation is work in progress and not completeEditor
3D System

Canvas Integration

The 2D canvas system controls where a 3D viewport sits — position, size, rotation, opacity — while the Three.js renderer controls what is drawn inside it. This split is what makes a 3D shape behave like any other canvas element.

Mounting

ThreeDShapeRenderer creates a div with position: relative and overflow: hidden, then passes it to ThreeDShapeElement as the mount container. Inside, ThreeDEngine creates a WebGLRenderer, sets its DOM element to display: block with 100% width and height, and appends it to that container.

Positioning

The host div is placed inside the 2D artboard by Canvas.tsx using absolute positioning:

<div
  style={{
    position: 'absolute',
    left: el.x,
    top: el.y,
    width: el.width,
    height: el.height,
    opacity: el.opacity ?? 1,
    overflow: 'hidden',
    pointerEvents: activeThreeDElementId === el.id ? 'auto' : 'none',
    zIndex: elements.indexOf(el) + 1,
    borderRadius: el.borderRadius ?? 0,
  }}
>
  <ThreeDShapeRenderer ... />
</div>

Zoom and pan need no special handling. The CSS transform on the artboard container applies to the 3D div automatically, because the div is a child of the artboard and inherits the transform.

Resize Synchronization

A useEffect in ThreeDShapeRenderer calls resize() whenever the element dimensions change, which updates both the renderer size and the camera aspect ratio:

useEffect(() => {
  if (instanceRef.current) {
    instanceRef.current.resize(element.width, element.height);
  }
}, [element.width, element.height]);

Clipping

Both the outer positioning div in Canvas.tsx and the inner container in ThreeDShapeRenderer set overflow: hidden. If a 3D viewport ever bleeds outside the canvas boundary, one of those two is missing.