Documentation is work in progress and not completeEditor
3D System

3D Shape Library

The shape picker is the modal for choosing a primitive or importing a model. It renders through a portal into document.body with a full-screen backdrop.

Shape Catalog

TypeLabelDescription
boxBoxA solid rectangular cuboid with flat faces
sphereSphereA perfect round ball with smooth surface
cylinderCylinderA tube shape with circular top and bottom
torusTorusA donut shape with a hole through the center
coneConeA pointed shape tapering from a circular base
capsuleCapsuleA cylinder capped with hemispheres at both ends

Each entry has a custom inline SVG icon on a 44x44 viewBox, defined in the same file.

Layout

  • Left column — a 3x2 grid of shape cards. Clicking one selects it, highlighted with a cyan border. Below the grid sits the "Import 3D Model from PC" button.
  • Right column — 192px wide, holding a live 3D preview, the shape name and description, and an "Add to Canvas" button.

Pressing Escape closes the picker. The handler is registered on window with no capture option, so a parent calling stopPropagation() would prevent it from firing.

Live Preview

ThreeDShapePreview creates a temporary ThreeDEngine in a small container, adds the selected primitive, disables orbit controls and runs a continuous camera orbit:

const animate = () => {
  angleRef.current += 0.012;
  const r = 4;
  engine.setCameraPosition(
    { x: Math.sin(angleRef.current) * r, y: 1.5, z: Math.cos(angleRef.current) * r },
    { x: 0, y: 0, z: 0 }
  );
  engine.markDirty();
  rafRef.current = requestAnimationFrame(animate);
};

The camera orbits at a radius of 4 units and a fixed height of 1.5, at 0.012 radians per frame. When the geometryType prop changes, the engine is disposed and recreated with the new primitive.

The preview creates a full engine — and therefore a WebGL context — for a small viewport. The useEffect cleanup disposes it when the modal closes. In any scrollable list context, engines should be created only for visible items.

Model Import Flow

  • A hidden file input is triggered.
  • The selected file is passed to onImportModel(file) and the picker closes.
  • The parent component performs the import via engine.importModelFromFile(file).