3D Studio
Parametric 3D models from shapes, holes, arrays, and templates, with print checks, STL/3MF/OBJ/GLB/SVG export, and one-click hand-off to Bambu Studio or OrcaSlicer — 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",
Tinkercad-style direct manipulation with snapping, box selection, perspective or orthographic views, and
view presets (iso, top, bottom, front, back, left, right):
- drag an object to move it across the plate (Shift keeps one axis); pressing an unselected object selects it in the same gesture, and a multi-selection moves together;
- resize handles sit on the object's own frame, so they follow a rotated object: white corners change length
and width, dark side points one side, the top square the height. The opposite side stays put; Shift keeps the
proportions, Alt resizes from the centre. Sizes land in the real dimensions (a box's
size, a cylinder'sdiameter/height) and fall back toscaleonly for expressions, already scaled objects, or stretches the shape cannot express. A selection of unrotated top-level objects resizes along the world axes; - the cone above the selection raises or lowers it; readouts show the sizes or the elevation while a handle is hovered or dragged;
- three curved arrows outside the frame turn the selection around its centre: the one by the front bottom edge spins it around Z, the ones beside the back and right faces tip it around X and Y (the object's own axes for one object, the world axes for a selection, which turns as one piece). A protractor with 15° ticks and a degree readout shows the turn; it snaps to 15° (Shift: 45°, free with snapping off). All handles work in one mode, like Tinkercad.
- 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. A model with more than one colour keeps its colours in the 3MF
as a standard 3MF materials colour group (the object's
pid/pindexname the most used colour, triangles in other colours carryp1); Bambu Studio 2.5 and later offers them in its colour-to-filament mapping dialog. GLB colours are material colours, which Bambu Studio ignores (it only imports GLB textures), so use 3MF for slicers. - Open in slicer — Export → "Open in slicer" → Bambu Studio or OrcaSlicer saves the model and hands it to the desktop slicer on this computer, which downloads it as 3MF and opens it as a new project; slicing, printer choice, and sending the print (including Bambu Lab printers in cloud mode) happen in the slicer. See Open in slicer.
- 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 |
| Drag an object (Shift: one axis) | move it across the build plate |
| Drag a white corner · dark side point · top square (Shift: proportional, Alt: from the centre) | resize length and width · one side · height |
| Drag the cone above the selection | raise / lower |
| Drag a curved arrow (Shift: 45° steps) | rotate around that axis in 15° steps |
| 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 |
| 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 (to Dokumente, or target: "slicer" for an "Open in Bambu Studio/OrcaSlicer" link),
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).
Open in slicer
Clapilot does not slice or talk to printers itself. It hands the model to the slicer the person already uses:
- The editor saves the model and calls
POST /api/modules/3d-studio/exportwithtarget: "slicer". The server exports once (an empty or invalid model fails here, not in the slicer) and returns a signed, expiring file URL plus the slicer deep link for the browser's platform:bambustudioopen://<url>(Bambu Studio on macOS),bambustudio://open?file=<url>(Bambu Studio on Windows and Linux), ororcaslicer://open?file=<url>. - The browser opens the deep link; after the browser's "open app?" prompt the slicer downloads
GET /api/modules/3d-studio/slicer-file/<token>/<name>.3mfand opens it as a new project. Bambu Studio first asks once whether to open a file that is not from MakerWorld; OrcaSlicer opens it directly. A toast keeps a plain "Download 3MF" link for computers without the slicer. The section is hidden on phones and tablets. - The file route is public (allowlisted in the session middleware for GET/HEAD) because the slicer has no
Clapilot session. The token is HMAC-SHA256-signed with
AUTH_SECRETand carries only the model id, the user who created the link, and the expiry: 15 minutes from the editor, 24 hours for links the agent posts in chat. The route re-exports the saved model as that user; forged or foreign tokens get403, expired ones410.
The link has to be reachable from the computer running the slicer: the editor uses the origin the browser is
on, the agent uses the instance's public base URL (Einstellungen). The last path segment is an ASCII
<title>.3mf, because both slicers name the download after it. Bambu Studio downloads through its network
plugin, so the plugin must be installed (Bambu Studio offers it on first start). Bambu Lab printers in cloud mode
keep working as usual, because printing goes through Bambu Studio. The 3MF carries one merged object with the
model's colours (see Export), which Bambu Studio maps to filaments/AMS slots in its colour dialog. Bambu Studio
02.08.02 and older show "The 3mf file has invalid config, load geometry data only" for every 3MF without Bambu
printer settings when it is opened as a project; confirming it loads geometry and colours. Clapilot does not embed
printer settings on purpose, because they would replace the person's printer profile. Later versions drop the
notice.
Agent links: model3d_export_model with target: "slicer" returns the Windows/Linux form. The web chat keeps
these custom-scheme links only when they point at the signed file route, and rewrites Bambu Studio links to
bambustudioopen:// on click on a Mac; the macOS app does the same in its link handler.
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?};{model_id, target: "slicer", slicer: bambu_studio|orca_slicer}returns{open_url, file_url, filename, expires_at}GET /api/modules/3d-studio/slicer-file/<token>/<name>.3mf— public, signed, expiring 3MF download for the slicerPOST /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 resize/lift/rotate handles in
src/lib/model3d/gl/*; resizes and turns go throughsrc/lib/model3d/handle-edits.ts(shared with the nativeresizeandrotateedits), and the evaluator reports each node's own-frame bounds (nodeFrames) for the handles (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 (on macOS in the title bar in place of the page title); 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).
- Open in slicer (macOS) — the export menus list Bambu Studio and OrcaSlicer when they are installed
(
com.bambulab.bambu-studio,com.orcaslicer.OrcaSliceror the oldercom.softfever3d.orca-slicer). The app exports the saved model as 3MF into its temporary folder and opens that file in the slicer, so no download link or trust prompt is involved. iOS and iPadOS have no desktop slicers, so there is no such entry there. - 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 the same resize handles, lift cone, rotate arrows with protractor, and readouts
as the web editor (a SwiftUI overlay using the renderer's camera math;
Views/Studio3dHandles.swift). Drags preview live in RealityKit and commit one undoable edit on release (translate,resize, orrotate). Touch: one finger on a handle resizes, lifts, or turns, on a selected object moves it, elsewhere 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 on a handle resizes or lifts, on an object selects and moves it (Shift: one axis or proportional, Option: from the centre), elsewhere 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; on macOS and iPad above the object list in the inspector), 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).
