3D Studio
Parametric 3D models from shapes, holes, arrays, and templates, with print checks and STL/3MF/OBJ/GLB/SVG export — built so the agent can design, measure, and verify models as well as people can.
What it does
3d-studio is an optional bundled module (React renderer, not installed by default) for simple,
printable 3D objects. People build models Tinkercad-style from shapes and holes in the browser; the
agent builds and edits the same models through model3d_* tools. Models are workspace-global: every
signed-in user sees and edits every model (created_by / updated_by are attribution only).
- Model list — searchable list with thumbnails, size, and date; new models start empty or from a template; the shared file context menu offers rename, copy, delete, share, downloads (STL, 3MF, OBJ, GLB, SVG), and "save to Dokumente" (3MF).
- Editor — WebGL 2 viewport with the print bed and a 10 mm grid, translucent hole "ghosts", move/rotate/scale handles with snapping, box selection, perspective or orthographic views, and view presets (iso, top, bottom, front, back, left, right).
- Inspector — object tree (hide, lock, hole badge), the selected object's fields (every numeric
field accepts a number or a parameter expression such as
width - 2 * wall), position, rotation, scale, mirror, colour, lock, and a dimension readout; with two objects selected it shows their gap or overlap. Without a selection it edits the model parameters and the printer build volume. - Print checks — live size, volume, PLA weight estimate, thinnest wall, and warnings: empty model, separate bodies, exceeds the build volume, holes that cut nothing, overhangs over 45°, walls thinner than 0.8 mm, parts thinner than 0.8 mm, missing text glyphs.
- Import — STL, OBJ, and 3MF files become mesh objects (welded, checked for watertightness, centred); SVG files become extruded outlines (with holes) in one group.
- Export — STL and 3MF for slicers (placed on the build plate: lowest point at z = 0, centred), OBJ, GLB (coloured, Y-up metres for viewers/AR), and SVG (top-view outline in mm for laser cutters). STL and 3MF can also be saved directly to Dokumente.
- Agent prompt — an AI row above the viewport sends a request to the chat agent with the open model as page context; the floating and docked chat show 3D Studio quick actions (create a model, check printability, export as STL).
Dokumente previews STL and 3MF files with the same 3D viewer (web and, through /model3d-viewer, the
iOS/macOS Documents screen).
Shapes and containers
| Type | Fields (mm unless noted) | Notes |
|---|---|---|
box | size [x,y,z], radius or chamfer, edges vertical|top|all | top keeps a flat, sharp bottom |
cylinder | diameter, height, top_diameter, fillet or chamfer, edges both|top|bottom, segments | top_diameter: 0 is a cone |
tube | diameter, wall or inner_diameter, height | |
sphere, hemisphere | diameter (height for a squashed dome) | hemisphere rests on its flat side |
torus | diameter (centre line), tube_diameter | |
wedge, roof, half_cylinder, pyramid, heart | size [x,y,z] | wedge: vertical face at −Y; roof and half cylinder run along X |
prism | sides, diameter or across_flats, height | a flat always faces −Y; across_flats sizes nut traps |
paraboloid | diameter, height | |
star | points, diameter, inner_diameter, height | |
polygon | points [[x,y]…], holes, height, twist, top_scale | extruded along Z, centred on z = 0 |
revolve | points [[r,z]…], angle | revolved around Z |
text | text, size (capital height), height (depth), align, line_spacing | bundled Noto Sans (Latin-1) |
mesh | asset_id | imported STL/OBJ/3MF |
group | children, operation union|hull|intersection | |
array | children, count, step, count2, step2 | linear or grid copies |
radial_array | children, count, angle | copies rotated around the container's Z axis |
Every node has id, optional name, mode (solid/hole), position (centre of the shape's own
bounding box; for polygon, revolve, and arrays the local origin), rotation (degrees, X then Y then Z),
scale, mirror (["x"] …), color, hidden, and locked (editor-only). Holes subtract from the
solids of the same container; a container marked as hole, or holding only holes, cuts its siblings.
Z is up, units are millimetres.
Keyboard and mouse
"Mod" is ⌘ on macOS and Ctrl elsewhere; the in-app help (? or the keyboard button) lists everything.
| Keys | Action |
|---|---|
| Click / Shift- or Mod-click | select / add or remove from the selection |
| Drag on empty space (Shift: add) | box selection |
| Alt-click | select a part inside a group |
| Right-drag, Alt+drag · Shift+right-drag, middle-drag · scroll | orbit · pan · zoom |
| Mod+A, Esc | select all, clear selection |
| Mod+Z, Mod+Shift+Z / Mod+Y | undo, redo |
| Mod+C, Mod+X, Mod+V | copy, cut, paste (clipboard works across models) |
| Mod+D | duplicate in place; pressing it again on the moved copy repeats the move (Tinkercad duplicate-and-repeat) |
| Delete / Backspace | delete (locked objects are kept) |
| Mod+G, Mod+Shift+G | group, ungroup |
| H, S | make hole, make solid |
| W, E, R | move, rotate, scale handles |
| Arrow keys (Shift: ×10) | nudge along X/Y by the snap step |
| Mod+↑/↓, PageUp/PageDown | raise / lower along Z |
| D | drop onto the build plate |
| L, M | align menu, mirror menu |
| Mod+Shift+H, Mod+Shift+A | hide, show all |
| Mod+L | lock / unlock |
| F, Home, O | fit selection or model, home view, orthographic toggle |
| Mod+S, ? | save now, shortcut help |
Agent tools
model3d_list_models, model3d_list_templates, model3d_get_model, model3d_create_model,
model3d_update_model, model3d_measure, model3d_render_image (vision), model3d_import_mesh,
model3d_export_model, model3d_delete_model (approval-gated). The contracts are in
Agent Tool Contracts. Design choices that make agent
output reliable:
- Structured document, no code execution — the agent edits the same JSON model as the editor;
writes are validated and evaluated with the Manifold kernel before saving, and rejected with
path-precise errors (
nodes[2] (lid).size[0]: …) when anything is invalid. Nothing is saved on error. - Geometry-aware operations —
place_on(put a part on a face of another),align(to the selection, the bed, or a node),drop_to_bed,center_on_bed,translate,duplicatewith a step,group/ungroup, plus arrays and parameter expressions, so placement never depends on hand-computed coordinates. - Numeric feedback on every write — world bounding box of every node, metrics (size, volume, bodies, genus, overhang area, thinnest wall and its location), and warnings.
- Measuring —
model3d_measurereturns boxes, gap/overlap per node pair, and the wall report. - Visual verification —
model3d_render_imagerenders up to six views with a mm grid;highlight_node_idstints parts,focus_node_idframes a close-up, andsectioncuts the model open (the kept half faces the iso camera by default). - Templates as worked examples — name tag, storage box, box with lid (with clearance), cable clip,
wall hook (supports-free side profile), knob (radial grip array, D-shaft hole group), battery holder
(grid array), spacer with nut trap (
across_flats), and washer. Every template evaluates without warnings in CI.
The page capability rule tells the agent to start from templates, plan in millimetres with printable
walls and clearances, place parts with operations, verify with measure and render for at most about
three rounds, and export only on request. Outside the module, requests about 3D printing, STL/3MF, or 3D
models route the model3d tool family (resolveRoutedToolBundles).
Storage and API
Module migration 001_create_3d_studio_schema.sql creates studio3d_models (title, document JSONB,
metrics, thumbnail_png, revision, attribution) and studio3d_assets (imported meshes as float32
positions + uint32 indices). The handler re-applies the idempotent schema on first use. Core migration
340_3d_studio_module_default_off.sql keeps the module opt-in under the legacy_all install policy.
Module API (/api/modules/3d-studio/api, session or agent-system token):
GET models?q=&limit=— list;POST models— create{title, document, metrics?, thumbnail_png?}GET|PATCH|DELETE models/:id— PATCH acceptsbase_revisionand returns409withcurrent_revisionwhen the model changed meanwhile (the editor offers reload or overwrite)POST models/:id/duplicate,GET thumbnail/:idPOST assets(positions_b64,indices_b64,name,format,size),GET assets?ids=,GET assets/:id
App routes:
POST /api/modules/3d-studio/export—{model_id | document, format: stl|3mf|obj|glb|svg, target: download|documents, folder_id?}POST /api/modules/3d-studio/import— multipartfile(STL/OBJ/3MF, up to 50 MB and 300,000 triangles) or{document_id}GET /api/modules/3d-studio/manifold-wasm— the Manifold kernel for the editor (ETag revalidated)GET /api/modules/3d-studio/font— the text glyph outlines for the editor (ETag revalidated)POST /api/modules/3d-studio/evaluate— editor backend for the native apps: applies edits (the agent operations plusadd_shapeandpaste), evaluates, optionally saves with metrics and thumbnail, and returns the document plus the mesh (base64 float32/uint32 with per-node runs), hole meshes, node boxes, metrics, and warningsGET /api/modules/3d-studio/templates— template ids, default titles, and parameters/model3d-viewer?document=&format=&title=— chromeless STL/3MF viewer for Apple Documents previews
Limits: 300 nodes, 8 container levels, 400 copies per array, 2,000 points per outline, 80 characters per text node, dimensions 0.01–2,000 mm, Dokumente exports up to 8 MB.
Implementation
- Geometry, validation, operations, rendering, and file formats:
src/lib/model3d/*(isomorphic exceptfiles.ts,service.ts, andmanifold-server.ts). The editor evaluates in the browser with the same code the server and the agent tools use. - Editor UI:
src/components/modules/studio3d-module.tsxandsrc/components/modules/studio3d/*. - Agent tools:
src/lib/model3d/agent-tools.ts, wired throughsrc/lib/agent-runtime/tool-proxy.tsandservices/clapilot-agent/src/tool-definitions.mjs. - Viewer: a small purpose-built WebGL 2 renderer, orbit camera, and move/rotate/scale gizmo in
src/lib/model3d/gl/*(used by the editor and the STL/3MF preview; no general 3D engine is bundled). SVG import parses outlines itself (src/lib/model3d/svg-outline.ts); STL/OBJ/3MF parsing is shared by the server and the browser (src/lib/model3d/mesh-parse.ts). - Dependencies:
manifold-3d(Apache-2.0, WASM mesh kernel). Text uses Noto Sans (SIL OFL 1.1) glyph outlines stored insrc/lib/model3d/fonts/; the server kernel loader imports them and the browser loads them from the font route with the kernel, so neither is part of the JS bundle.
iOS and macOS
The Apple clients have a native SwiftUI 3D Studio screen in the side menu (MainAppSection.studio3d, route
/modules/3d-studio, shown only while the 3d-studio module is installed; Views/Studio3dView.swift and the
Studio3d* files next to it). It never loads the web page. Geometry is evaluated by the server kernel through
POST /api/modules/3d-studio/evaluate: the app keeps the model document as returned, sends every change as
the same operations the web editor and the agent use (coalesced into one request while one is in flight), and
each request re-evaluates and saves the model with the revision check. Undo and redo replay whole documents.
- Model list — thumbnails, size, and date, with search; the + menu creates an empty model or one from a template. A long-press or right-click menu renames, duplicates, exports (STL, 3MF, OBJ, GLB, SVG via the save panel on macOS and the share sheet on iOS), saves STL/3MF to Dokumente, or deletes (with confirmation).
- Viewport — RealityKit on iOS 18 / macOS 15 and later: flat-shaded parts in their colours, translucent holes, the bed with a 10 mm grid, and an accent box around the selection. Touch: one finger orbits, two fingers pan, pinch zooms, tap selects (the toolbar's multi-select switch makes taps add or remove), double-tap fits. Mouse and trackpad: drag orbits, Shift- or right-drag pans, scroll wheel, ⌘-scroll, or pinch zooms, click selects, Shift/⌘-click adds, Option-click picks a part inside a group, double-click fits. Picking uses the same camera math as the renderer.
- Toolbar — add shapes (basic shapes, more shapes, hole), hole/solid, duplicate (duplicating the copy again repeats the offset, like Tinkercad), delete (locked objects are kept), group/ungroup, align (per axis, to the selection or the bed, centre on the bed), mirror, drop to bed, undo/redo, view presets and fit, export, import of STL/OBJ/3MF meshes, and the save state. The keyboard shortcuts of the web editor work on macOS and iPad keyboards (the help sheet lists them).
- Inspector — print checks and warnings (tap a warning to select its object), the object tree with hide toggles, the selected object's fields (numbers or parameter expressions, per type as on the web), position, rotation, scale, mirror, colour, and lock; without a selection the model parameters and the build volume. It is a trailing column on macOS and iPad and a sheet on iPhone (opened from the toolbar or the selection chip).
- Agent — the AI row below the viewport sends a request with the model as page context: into the docked chat
on macOS and to the chat on iPhone. The docked chat shows 3D Studio quick actions (create a model, check
printability, export as STL). Page context uses the web keys (
studio3dModelId,studio3dSelectedNodeIds, …). - Links —
/modules/3d-studio?model=<id>opens that model in the native editor.
The Documents screen previews STL/3MF files with the web viewer (/model3d-viewer).
