sketchflow-mcp
# SketchFlow
A vector sketch board for fast idea capture. You draw with a mouse, stylus or finger, and an AI connected over MCP can see your board and draw on it too.
Everything you draw stays editable: lines, shapes and text are vectors. Endpoints and corners **snap together and join**, and joined points move together when you drag them. On top of that you get drawing spaces (isometric, 1/2/3-point perspective, 3-view and 4-view), parametric dimensions, layers, collage and tracing, background cut-out, and a first linkage/motion simulator.
**v2 adds a parametric 3D model workspace** at `/3d/`. You build solids from primitives, sketch-and-extrude, loft, revolve and sweep, then combine them with mates and booleans. Fillets and chamfers decide for themselves whether to add or remove material. The model is shown in four linked views (TOP · 3D · FRONT · RIGHT) that carry each object's dimensions, and you can edit those dimensions in place. The AI builds with the same operations through six `model_*` MCP tools. See [model/ARCHITECTURE.md](model/ARCHITECTURE.md). The 2D board is unchanged: it is frozen as **v1** (git tag `v1.5.0`, branch `v1`).
```
sketchflow/
├── index.html 2D board UI + styles (v1)
├── js/ core · render · tools · input · ui · io · motion · bridge
├── model/ 3D workspace (v2): index.html, js/kernel · model · views · app, tests, ARCHITECTURE.md
├── server.mjs MCP server + local web server (Node 20+, zero dependencies): / = board, /3d/ = model
├── scripts/ setup (what SF3d_setup.bat runs) · smoke test · Claude Desktop bundle (.mcpb) · release prep
├── SF3d_setup.bat Windows setup: install, AI apps, Ollama, publish — settings in SF3d_setup.env (from the .template)
├── build.mjs makes single-file versions in dist/
└── dist/ sketchflow.html · sketchflow-3d.html — double-click to use offline (no AI link)
```
## 1 · Run it with Claude (MCP)
**Beta:** SketchFlow is on npm as `sketchflow-mcp`. You need **Node 20 or newer**. It has no dependencies; `npx` fetches it on first use. [INSTALL.md](INSTALL.md) covers every client: Claude Code, Claude Desktop (a one-click `.mcpb`), Cursor, VS Code, LM Studio, and local models through Ollama. It also covers the settings and testing a build before it is published.
**Windows:** run `SF3d_setup.bat`. It asks for your settings in a Notepad file, then installs SketchFlow, adds it to your AI apps and, if you like, Ollama and the public release. See [INSTALL.md](INSTALL.md#windows-one-double-click).
**Claude Code**
```bash
claude mcp add --scope user sketchflow -- npx -y sketchflow-mcp@beta
```
Then ask: *"open the sketch board"* or *"open the 3D model and build a 100 × 60 × 8 plate with four M5 holes"*. Claude calls `open_board` / `open_model`, which opens **http://localhost:7777** in your browser.
**Claude Desktop:** install `sketchflow-<version>.mcpb` from the GitHub release. Or add this in Settings → Developer → Edit config:
```json
{
"mcpServers": {
"sketchflow": {
"command": "npx",
"args": ["-y", "sketchflow-mcp@beta"]
}
}
}
```
**From a checkout** (to develop or try changes): use `node /absolute/path/to/sketchflow/server.mjs` as the command, or `claude mcp add sketchflow-dev -- node /absolute/path/to/sketchflow/server.mjs`.
**Local models (Ollama) and small context windows:** add `--tools=3d --brief` (or `--tools=2d`). The model then gets one tool set and short instructions, about 3.5k tokens instead of about 12k. See [INSTALL.md](INSTALL.md#local-models-ollama).
**Draw on a tablet or phone while Claude runs on your computer:**
```json
"env": { "SKETCHFLOW_LAN": "1" }
```
With this set, `open_board` returns a `http://<your-ip>:7777/?k=<code>` link. Open it on the tablet. The pairing code stops other devices on your network from connecting.
Other settings: `SKETCHFLOW_PORT` (default 7777), `SKETCHFLOW_NO_OPEN=1` (don't open a browser), `SKETCHFLOW_EXPORT_DIR` (default `~/Pictures/SketchFlow`), `SKETCHFLOW_TOOLS` and `SKETCHFLOW_BRIEF`. All of them, and the matching flags, are in [INSTALL.md](INSTALL.md#settings) and `npx -y sketchflow-mcp@beta --help`.
### The loop
| You | Claude |
|---|---|
| Sketch, then press **Send** (Ctrl+Enter) with an optional note | `wait_for_sketch` / `look` gets the image + layers + note |
| "Clean this up as a 3-view" | `drawing_space v4` + `draw` (joined vector lines, dimensions, text) |
| "Make this crank move the arm up and down" | `draw` links → `mechanism` pins + motor → `simulate` (joint paths, lock check) → `play` |
| "Fill the left panel, keep it attached" | `draw` with `{type:"fill", x, y}`: a shape fill that follows its outline |
| "Colour-code everything" | `edit_items color_by_type` |
| "Set that to 120 mm" | `edit_items set_dimension`: the geometry stretches and joined lines follow |
| "Put this photo in and trace it" | `place_image` with `as_reference` (or `remove_background`) |
| "Save it" | `export` → PNG, transparent PNG, SVG, ORA, layers ZIP, board file |
**MCP tools:**
- `open_board`
- `look`
- `wait_for_sketch`
- `draw`
- `edit_items`
- `layers`
- `drawing_space`
- `board`
- `place_image`
- `export`
- `mechanism`
- `say`
### 3D models with Claude
Ask: *"open the 3D model and make a flange: Ø80 × 8 disc, Ø36 neck 30 tall, Ø20 bore, four Ø7 holes on a 58 mm circle, 1 mm chamfer on the rim"*. Claude opens **http://localhost:7777/3d/** and builds it in one undoable step. You watch it appear in all four views. Then change any dimension yourself, and everything mated to it follows.
| Tool | What it does |
|---|---|
| `open_model` | open the 3D workspace and read the model |
| `model_build` | add / set / mate / boolean / edge / extrude / loft / revolve / sweep / delete / origin / ground / fix / cleanup / dim, as one atomic batch; `look:true` returns a picture |
| `model_describe` | parameters, positions from the origin, mates, connector names (with positions and normals on request), volumes, warnings |
| `model_view` | a picture of the four views or one view, from any direction |
| `model_session` | undo, redo, new, demo, example (the bundled pump housing and crow shelf bracket), load a `.sf3d.json`, select, say, **share** (a link for live editing together), **room** (who's in it and what they're doing) |
| `model_mass` | mass, centre of gravity and inertia per part and for the assembly, whether it stands, and the parts list |
| `model_addon` | list add-ons, or run one: e.g. `gears/advise` (module, teeth and form for a ratio and a process), `gears/pair`, `welding/advise` (weld, bond or laminate suggestions for light, regular and heavy service) or `welding/apply` |
| `model_import` | an STL, OBJ or STEP file from disk as mesh parts (STEP: planar faces, each solid kept in place) |
| `model_check` | interference (which parts overlap, by how much, exact for moderate parts) and a motion sweep that reports the first contact of a joint |
| `model_query` | geometry questions: every face of a part with the connector name to target it by, its normal, centre and area; edges; distances and angles between faces; section areas; bounding boxes |
| `model_reference` | the op reference: every op in one line, or one op / topic in full with a worked example (works without the browser) |
| `model_export` | **STEP** (AP214 solids for CAD, vetted before it is saved), STL (watertight, for printing), OBJ, `.sf3d.json`, parts list CSV, drawing sheet SVG / DXF (an assembly gets an exploded isometric with balloons numbered as the parts list) |
**The pump housing example** ([examples/](examples/README.md)). Claude built it in one session using nothing but MCP calls. Load it from File → *Example: Pump housing*, or with `model_session {action:"example", id:"pump-housing"}`. It shows:
**The crow shelf bracket example** ([examples/](examples/README.md#crow-shelf-bracket-built-over-mcp-welded-with-the-weld-wizard)). A 1" × ¼" steel bar bent to 16" × 14", braced by a laser-cut ¼" crow in a Northwest Coast formline-inspired style. It was built over MCP and welded through the welding add-on: two seams, fillets a3, ISO 2553 symbols on the drawing. Load it from File → *Example: Crow shelf bracket*.
- a fully constrained flange sketch, with arcs, tangents, equal radii and driving dimensions (0 degrees of freedom);
- spline-profile gussets in a circular pattern, and a counterbored M6 hole pattern;
- a wedge pad with a modelled M5 tapped hole. Claude placed the hole after asking `model_query` for the pad's sloped face;
- text engraved flat (PUMP-01) and wrapped round the housing (SKETCHFLOW);
- a threaded neck with a knurled screw cap on a **screw joint**, with "TURN TO OPEN" embossed on an arc;
- four stainless M6 socket screws.
The checks Claude ran: no interference; a motion sweep of two turns of the cap with no contact; section areas; a measured 80 mm from the flange underside to the cap top; mass 597.75 g; drawing and parts-list exports.
**In the browser:**
- Add a shape with the toolbar: Box, Wedge, Cylinder, Cone, Sphere, Strip (a fillet strip). If a part is selected, the new shape lands on top of it, and Properties → **Combine** joins it, cuts it or keeps the overlap.
- **Putting features on a part:** select the part, then use **Add to *part*** at the top of Properties. Each one asks you to click the face (or edge) it goes on:
- Boss: a cylinder or box joined onto a face
- Cut: a round or square pocket
- Hole, Text
- Sketch on face
- Fillet, Chamfer
- Shell, Pattern
The Features group in the toolbar has the same tools. Bosses, cuts, holes, text and face sketches are mated to their face, so they follow it when the part changes.
- **Sketch**: draw in FRONT, TOP or RIGHT with the sketch bar.
- **Lines:** Line, Arc, Tangent arc and **Spline**, mixed freely.
- An arc is its end point, then a point it passes through.
- A tangent arc carries on smoothly from the last segment and stays tangent.
- Arcs are real sketch arcs, not short segments: give them an **R dimension**, make two **tangent** or **concentric**, set radii **equal**, or turn any segment into an arc (⌒ in Properties → Sketch).
- A spline is a smooth curve through the points you click. It leaves the last segment tangent and blends into the next one. Switch back to Line or Arc, or close the shape, to end it. One spline is one smooth face on the solid.
- In Properties → Sketch, **∿** turns any line into a spline, and a spline's fit points can be moved, added or removed. When dimensions move a spline's ends, its fit points go with them, so the curve keeps its shape.
- **Pin** a fit point so it stays put, or dimension its x or y (formulas work too).
- Each end is *auto*, *tangent*, *corner* or a set *angle*. Auto means tangent if the spline already sets off within 45° of the line, arc or other spline it meets, and a corner otherwise. Tangent is exact, and two splines meeting at a point share one tangent.
- **Shapes:** Rectangle, Circle, Slot, Polygon.
- **Snap ▾:** grid on or off, with a step of 0.5–25 mm; points, corners and centres; edge midpoints; horizontal / vertical only; 15° angles. A green marker shows what you snapped to, with the length so far.
- **Undo point**, **Close shape**, **Cancel**.
Then choose Extrude, Revolve or Loft (Loft asks for the end profile).
- Extrude options: **symmetric** (half each way), **through all** (for cuts, and it stays through as the part grows), **draft** (taper °), and **thin** (a wall of that thickness).
- **Finish open** leaves the outline open: a **rib** or thin plate of a thickness you choose.
- **Sketch on a face** (*On face* in the toolbar, or *On a face…* in the sketch bar): click **any** flat face, inclined ones included, and a view square to it opens with the grid on the face. Then choose *Extrude · join*, *Cut into*, *Cut through* or *New part*. The result is mated to that face.
- Every flat face of a shape can be a target: a wedge's slope, an extrude's side faces, the flat ring of a revolve. That covers holes, text, bosses, cuts, sketches and mates.
- **Lofts through sections, with guide curves:** Properties → *Loft sections & guides*.
- **+ section** adds a profile part-way up. Give each one a height, scale, turn and offset. With *smooth* on, the sides run in a smooth curve through every section (no overshoot); with it off, they're straight between sections.
- **+ guide** adds a curve from the first section to the last, which the sides follow. Edit its points (x, y, z). One guide moves the sections, two also turn and scale them (a barrel), and three or more also skew them.
- **Sweeps** can follow a **smooth** curve through their path points (a bent tube, a handle), **twist** along the way, and **scale** down or up towards the end.
- **Sketching on a curved face:** click the round side of a cylinder, a tube, a revolve or any extruded circle. The face opens **unrolled**: across is the distance round it, up is along it. Draw lines, arcs, splines, shapes or text as on a flat face. When you finish, it is **wrapped** round the face and either **embossed** (joined, standing out by the depth) or **engraved** (cut in). The face doesn't have to be a cylinder primitive: its axis and radius are fitted from the facets. On a cylinder part, the wrap follows the diameter when it changes.
- **Any other curved face** (a sphere, a cone, a loft, a fillet) opens a view square to the surface where you clicked. What you draw or type is **projected** onto the surface and embossed or engraved square to it. It's built on the part as it is at that point in the history, and it moves with the part.
- **Threads are real geometry:** an ISO 60° profile with a chamfered lead-in, so they print, mesh and show in sections.
- **More ▾ → Bolt (threaded)…:** M2–M24, length, hex or socket head, thread length. Mate its *seat* to the face it goes into.
- **More ▾ → Nut (threaded)…:** hex, round or knurled. It can be custom (any diameter and pitch), e.g. a screw cap for a bottle neck.
- **Thread a cylinder or tube:** Properties → Thread, an ISO size or a custom pitch, over all or part of its length, from the top or bottom. *Bore* makes it a tube.
- **Left hand** (a tick box on threaded cylinders, bolts, nuts and modelled tapped holes) makes a left-hand thread.
- **Tapped holes:** the hole wizard's *thread* choice is *drill only* (just the tap-drill hole) or *modelled* (the thread is cut).
- A nut on its bolt, or a cap on its neck, meshes with 0.1 mm clearance and doesn't count as interference.
- **More ▾** (in the Add bar):
- **Spring / coil**: wire Ø, coil radius, pitch, turns, hand.
- **Plane on a face**: a reference plane on a face, with a gap and a tilt. Sketch on it, mate to it, or split with it.
- Fillet strip, and the add-ons (gears, and the weld / join wizard).
- **Split** (Features): cut a part with a plane, keeping the side below, above, or both as two parts.
- Mates take a **tilt** too, so parts and planes can sit at an angle to a face.
- **Sketch constraints**: a drawn polyline gets horizontal / vertical relations and its first point fixed automatically, so a sloppy sketch comes out square. In Properties → Sketch, give any segment a driving dimension, or relate two segments (parallel, perpendicular, equal, angle). The status line says how many degrees of freedom are left and names any conflicting constraint.
- *Mate* (M): click the part, then its connector, then the target connector.
- *Union / Subtract / Intersect*: click the target, then the tool.
- *Fillet / Chamfer*: set the size and click near an edge. Outer edges are trimmed and inner corners are filled; round edges get the treatment all the way round. On the seam between two parts, a fillet merges them into one piece.
- *Weld*: click where two separate parts meet. The bead joins them and they stay separate parts (**E** pulls the assembly apart to show it). Mixing materials that can't be welded gets a warning.
- **Weld wizard**: click the seam where two parts meet (or one part, then the other). It reads the joint (butt, tee, corner, lap; thicknesses; torch access and welding position on each side) and the materials, asks what service the joint is for, and shows a light, a regular and a heavy suggestion side by side: the edge preparation (square, V, X, bevel, K, J, U), root gap, process, filler, position, quality level and inspection, time (fit-up, prep and machining, welding, grinding, inspection), cost at your labour rate, ease, the reasons, and a section through the joint with its ISO 2553 symbol. Materials that do not weld together get bonded, brazed, filled or fibre-tabbed joints instead (or pick one). *Build* cuts the preparation, opens the gap, places the weld metal and pins the weld symbol to the part. Drawings show the symbols with a weld schedule. Change a thickness later (any size field takes a formula, e.g. `=1/8*25.4`), then select the weld symbol and press *Redo for new sizes*.
- *Pattern* (**P**, or Properties → Pattern…): a row, grid, circle or mirror of the selected part or feature. Copies follow the original.
- *Material & mass* in Properties: pick a material, or set density, fill %, part no., supplier and notes. With nothing selected you see the total mass, the centre of gravity (the toolbar button marks it in the views), whether the model stands, and a parts list button.
- *Add-ons* menu: gears (single, pair, train, planetary, and an advisor that picks the right gear for the job and the process). Drop your own into `model/addons/`: see [model/ADDONS.md](model/ADDONS.md).
- **Extend to a part**: a size can reach another part instead of being a number, and it follows that part when it moves, tilts or changes. Use the size's link button → *Extend to a part…* and click the part. **Heights** (box, cylinder and cone height, a blind extrude's length) grow straight up: a bar under an inclined plate grows until its flat top just touches the plate. **Widths and depths** (box width and depth, a sketched rectangle's width and height) grow sideways. The face toward the part you click reaches it and the opposite face stays put (on its anchors, for a rectangle that follows corners). Properties lets you switch which face grows. Each one meets the part at its nearest point (*touch*), at its middle (*centre*) or everywhere (*cover*), with a gap if you want one. One part can extend several sizes at once, e.g. height up to the deck, width to the wall and depth to the wedge. Type a size to set it yourself.
- **Cuts through several parts**: a cut removes material from its own part, plus any part ticked under Properties → Boolean → *Also cuts*. That list shows the parts in its way. *Cut through* on a face ticks every part it goes through when you make it, so a hole goes through a plate and the deck above it. A through cut goes all the way, so its length isn't used, and its preview is shown only across the parts it cuts.
- **Follow corners**: while sketching on a face, snap a corner of a rectangle (or a point of an outline) to a corner of another part, and it follows that corner from then on. The snap label says *follows it*; mirror and pattern copies count. A rectangle snapped to two opposite corners spans them: a deck on a wedge ramp stays the length of the slope and the width across both wedges when you change them. For a shape already drawn, use Properties → *Follows* → *Follow corners…* and click the corners. *Stop following* releases it. Circles and polygons follow a centre (and a rim point), and slots follow their two ends. Sketches drawn in FRONT / TOP / RIGHT follow too. **Your sizes win**: type a size and it is yours. The corners still place the shape, lined up on the first corner, and *Follow again* hands that size back. A driving dimension takes over its place.
- Click any orange dimension in the 2D views to change it. If another part had the same size running the same way, you're offered **Make it follow**: from then on it keeps step with the leader (shown teal, as =90).
- Any size can be a formula: type `=plate.depth`, `=plate.depth - 10` or `=#wall * 2` in Properties (the link button beside each size picks a leader from a list). Model variables (#wall…) are in Properties with nothing selected.
- Placement can follow sizes too: a mate's gap, angle, tilt and slides take formulas. For example, slide x `=plate.width / 2 - 10` keeps a part 10 mm in from the edge as the plate grows. Changing where a part is mated keeps its joint.
- *Measure* (**G**): click two dots in a 2D view. A hole centre then a face dot (the middle of an edge in that view) gives the off-edge distance, measured square to the edge; two points offer horizontal / vertical / aligned. Type a value to make it **driving**: the hole moves and stays at that distance from the edge when the part changes size.
- The feature list shows **By part** (each part with its holes, edges, welds and arrays) or **History** (the order you made things). In History, drag rows to reorder and drag the blue **rollback bar** to see the model as it was (new features go in at the bar). The ⋯ / right-click menu: suppress, duplicate (Ctrl D), linked instance, pattern, move, delete.
- *Profile* sketches: Polyline, **Rectangle** (rounded corners), **Circle**, **Slot**, **Polygon** (two clicks). Then Extrude, **Cut through** the part underneath, or Revolve. The shape's sizes stay editable dimensions.
- *Hole*: pick a size (M2–M16) and type (simple, counterbore, countersink, tapped, heat-set insert) and fit (close / normal / loose / print), then click faces. Each hole is dimensioned from its nearest edges; click a dimension to move it.
- *Shell…* (Properties) hollows **any** part to an even wall thickness, open on one of its faces or closed. This includes booleans, filleted parts and imported meshes. Every face moves inward by the wall (an offset, not a scale), so walls stay even on any shape, with mitred corners. A rounding smaller than the wall gets a sharp inner corner. A boss or rib thinner than two walls stays solid, and a note names it. A cut that would leave a section thinner than two walls is refused, by name.
- **Text** (T): type the words, the height and depth, then pick emboss (a boolean add standing on the face) or engrave (a boolean remove cut into it), and a path: straight, round an arc (reading over the top), or the inside of an arc (reading along the bottom, as on a badge). Click a flat face to place it. The words, sizes, radius, angle, alignment, or a polyline path are all editable later. The built-in font is a single-stroke engraving font, the kind CNC engravers and laser markers use. It covers capitals, digits and the usual symbols, including Ø ± ° ×; lower case prints as capitals.
- **Interference check** (I): one click lists every pair of parts that overlap, with the overlap volume, and shows the overlap in red. Parts that only touch, and welds on the parts they join, don't count.
- **Motion** (J): make a mated part a joint (Properties → Joint: revolute, slider, cylindrical, planar or **screw**, with limits), then drag its slider or press play. A screw joint turns and advances by its pitch per turn, so a nut or cap runs along its thread in step (keeping the thread phase). Its pitch is read from the thread, negative for a left-hand one, and you can change it. Meshed gears turn with it. *Keep this pose* makes it the model's position. **Collisions** are checked as it moves: parts that hit turn red, and *stop at contact* halts play at the first touch.
- **Section** (X): cut the model along X, Y or Z with a slider; the cut shows hatched.
- **Configurations**: add variables, use them in sizes (=#len), then *Add configuration* for each size; switch from the toolbar. Configurations can also switch features off.
- **File → Export STEP (.step)…** writes an AP214 file for CAD (Fusion, SolidWorks, Onshape, FreeCAD…):
- Every part is a **solid B-rep**, not a mesh. Flat faces are merged into single faces, and curved surfaces are kept as their facets.
- Parts are named and coloured, and their material is recorded. Several parts make an **assembly**, and a part repeated by a pattern is written once and placed each time.
- It is **vetted before it is saved**: SketchFlow reads the file back and checks it is a closed, consistently oriented solid whose volume, surface area and size match the model. The toast says what passed. Any hairline gaps a boolean left are closed and listed.
- With threaded parts you choose **plain threads** (cosmetic, as CAD systems exchange them; about 6× smaller) or **modelled** threads.
- File → *Save version…* / *Versions…*; *Import STL / OBJ / STEP…* (STEP with planar faces, such as SketchFlow's own; curved CAD surfaces aren't read); *Preview drawing* / *Export drawing (SVG, DXF)*: an A4/A3/A2 sheet with TOP / FRONT / RIGHT + isometric, hidden lines, dimensions, parts list and title block. With two or more parts the isometric becomes an **exploded isometric with numbered balloons** tied to the parts list (repeated parts are one item, with their quantity). *Exploded* in the preview bar turns it off.
- **Share** (toolbar) opens **shared editing**. Everyone with the link edits one model live, through the SketchFlow server.
- **Safe by design.** A change travels as a diff down to single parameters, so two people changing different sizes of one part both keep their change. A change that would overwrite someone else's is **refused, with the reason**, and never applied over it. The reasons are: the same field, two reorders at once, or a part someone else deleted or relies on.
- **Undo is yours alone.** It undoes your own last change, and only while nobody has changed the same things since. It never touches anyone else's work.
- **You can see each other.** The panel lists who's here and what each person has selected or is working on. Their parts are tinted in their colour in the views and marked in the feature list. Properties says when someone else is on the part you're editing. This is a soft lock: you can still edit, and a real clash is refused.
- **Activity** shows every change, who made it, and whether it was merged or refused. Edits Claude makes over MCP appear as "Claude (via *you*)", and the AI stays with the person who runs it, even when others join.
- **Offline-safe.** If the connection drops, your changes wait and are sent on reconnect, checked like any other. Rooms are saved on the server, so a restart loses nothing.
- File → New, Open or Example while shared asks first, because it would replace the model for everyone. *Leave · keep a copy* keeps the model as your own.
- Other computers: start the server with `SKETCHFLOW_LAN=1` and send them the link with the pairing code (`?k=…`).
- **View ▾** holds:
- layouts: all four views, or one view;
- fit, zoom in and out;
- hidden lines, dimensions, pulled apart, centre of gravity;
- whether dragging in 3D orbits or pans;
- the theme.
The view cube: click a face, edge or corner. **Check** has Clashes (interference), Section and Motion.
- Everything has a button or menu item; keys are only shortcuts:
- 0–4 layouts, F fit, H hidden lines, D dimensions, E pull apart
- S sketch, M mate, G measure, T text, P pattern
- J motion, X section, I clashes
- Ctrl D duplicate (also in Properties), Delete (also in Properties)
## 2 · Or just draw
Open `dist/sketchflow.html` (works offline). Or run `node server.mjs --serve` and open http://localhost:7777. Without the AI link, **Send** copies your sketch to the clipboard so you can paste it into any chat.
## How it flows
- **Pen:** hold still at the end of a stroke and it snaps to a clean line, arc, circle, ellipse, triangle, rectangle or polygon. Keep dragging to adjust it. Tap the Pen button again to cycle Pen → Pencil → Marker → Brush (pressure-sensitive with a stylus).
- **Snap & join (M):** starts and ends lock onto existing joints (ring = join) or onto a line (✕ = T-junction).
- **3D primitives (Shapes → 3D):** box, cylinder, cone, sphere, pyramid, prism.
- Built from real 3D geometry. Visible faces are separate closed faces, so Fill shading and *text on a surface* work on them. Hidden edges are dashed (toggle *Hidden edges*), and round shapes get centre lines.
- Drag to size; Shift gives equal sides. Clicking any part selects the whole primitive (Alt-click picks one part).
- In **3-view / 4-view**, drag inside the FRONT view and the top and side views draw themselves, aligned. 4-view also adds the object to a shared 3D scene in the top-right quadrant.
- **Placing 3D primitives (two steps):**
1. **Base.** Start on a snapped point.
- *From a corner* (joint, grid or any point): drag to the opposite corner, and the base stretches to fit exactly between them on the isometric ground plane. Snap both to a box's top-face corners and the base matches that face.
- *From a centre* (start on a ⊕): the base grows equally in every direction. Round shapes take the radius from your drag.
- *Base from: Auto / Corner / Centre* in the strip. Alt forces centre and Shift makes the base square.
2. **Height.** Move up and click (it snaps to other objects' points and levels so heights can match), or just type a number and press Enter. Esc cancels.
- A **height dimension** is added that *drives* the primitive: tap its number, type a new height, and the primitive rebuilds from its stored sizes. Connected lines, shape fills and surface text stay attached. Toggle *Height dim* off if you don't want it.
- Moving or scaling a primitive keeps its sizes. Rotating or mirroring it, or drawing it in 3-view, turns it into plain lines.
- 2D shapes started on a centre ⊕ also grow equally both ways.
- **Snaps & connectors:**
- Ends snap to joints, **▲ midpoints** of lines and **⊕ centres** of shapes (circles, faces, polygons, arcs).
- A line that lands on a midpoint or centre stays **connected**: move the shape and the line follows. Drop a dragged end somewhere else to disconnect.
- **⊥ Perp** lands a line perpendicular on another line, or squares off a line you start on a line.
- Toggle each in the Pen, Shapes and Joints strips.
- **Line types:** Solid, Dashed (hidden edges), Centre (dash-dot), and **Construction**. Construction lines are guides: they snap and show on screen, but never print or export (unless you tick *Include construction lines*) and never block fills. Dashed and Centre lines don't block fills either. Change a selection's line type from the Select strip.
- **Joints (J):**
- drag a dot to bend; everything joined there follows
- drop it on another dot to join them
- drag along a line to add a bend
- double-tap a dot to remove it
- hold Alt to detach
- **Select (V):** tap or box-select, drag, scale from a corner, rotate with the top dot. Lines joined to the selection stretch to stay attached. With items selected, tapping a colour recolours them.
- **Drawing spaces (P):**
- Free
- Flat grid
- Isometric
- 1-, 2- or 3-point perspective (drag the coloured vanishing-point pips)
- 3-view (Top / Front / Right side with alignment guides)
- 4-view (3-view + an isometric quadrant)
Strokes you draw roughly along a guide direction lock to it.
- **Dimensions (D):** drag between joints. Tap the number and type a value, and the geometry moves to match. Horizontal and vertical dimensions stretch the whole edge. Set units and scale in the strip (px, mm, cm, m, in, ft). In a drawing space, extension lines **follow the planes**: isometric axes, or the vanishing point in perspective. The number lies in that plane. Drag the number to switch planes, or set *Ext lines → Square* for classic perpendicular dimensions.
- **Text (T):** six fonts, bold/italic, size and colour, in three modes:
- *Free*: text goes where you tap.
- *Along a line*: tap a stroke to write along it. Drag it with Select to slide it along or lift it off; *Detach* / *Attach to line* switch between modes.
- *On a surface*: tap inside any 4-sided face (an isometric box side, a perspective plane, a rectangle) and the text is mapped flat onto that plane. It auto-fits the face and stays attached when you drag the face's corners. Drag it with Select to slide it across the face. *Turn on face* rotates it 90°; *Take off surface* makes it free text. You can also select a text and a 4-sided shape and press *Put on surface*.
- Isometric and flat faces keep the text as crisp vectors (also in SVG). Perspective faces warp it through a fine mesh (embedded as an image in SVG).
- **Fill (F):**
- *Tap* fills any enclosed region, even one formed by several lines.
- *Press and hold* (watch the ring) makes a **shape fill**. It's a vector tied to the surrounding outline's corners, curve points and line crossings, so it reshapes when you drag, bend or move those lines. Holes inside stay empty.
- Tap an existing fill or line to recolour it.
- Dimensions and text don't block fills: a fill flows straight through them.
- Moving a shape fill on its own lets go of the outline.
- **Eraser (E):**
- *Cut lines* splits vectors exactly where you erase
- *Whole items* removes anything you touch
- *Photo pixels* erases inside images
- **Import (drop, paste or button):**
- *As is*
- *Remove background* (instant and offline; tap to remove more)
- *AI cut-out* (online, loads `@imgly/background-removal`, AGPL-licensed, ~40 MB the first time)
- *Trace over it*: a faded reference layer plus an ink layer, with the lightbox on
- **Layers:** a tree of layer → type group → item.
- Every item you draw gets its own row automatically, grouped as Lines, Strokes, Rectangles, Circles, Triangles, Polygons, Fills, Text, Dimensions and Images.
- Each row shows a thumbnail of the shape, its size or font, a colour swatch, hide, lock and delete. Double-click a name to rename it.
- Clicking a row selects that item and highlights it on the canvas; hovering a row highlights it too. Clicking a group header selects the whole group.
- Recolour from the swatches at any level (one item, a whole group, or the whole layer) using a pop-up of the current palette, recent colours or a custom colour.
- **Colour by type** gives each type its own colour from the selected palette, chosen to be as different as possible from each other and readable on the paper. **Auto** keeps new items colour-coded as you draw. **Palette** switches presets.
- Layer-level options: visibility, lock, *reference* (shown on screen, left out of exports), opacity, 8 blend modes, duplicate, merge, reorder.
- **Background** is a pinned layer that always sits under everything and fills the canvas. It has a colour swatch, paper presets, and an eye that makes the canvas transparent while remembering the colour. It exports as its own layer in SVG, ORA and the layers ZIP.
- **Lightbox (L)** fades the layers below the one you're on.
- **Motion (X):**
- every item is a rigid link; joints shared by two items are pins
- *Pin* fixes joints to the ground
- *Motor* drives a link around its pivot
- *Trace* records a joint's path
- press ▶; *Keep path* saves the traced curve as a dashed line
- the board warns you if the mechanism locks up
- **Recall:** every board autosaves in this browser (IndexedDB) and stays in **Hub → Recall**. A new board never replaces the old one. Settings, palette, brush sizes and theme are remembered too.
- **Undo everything:**
- Ctrl+Z / Ctrl+Shift+Z, 2-finger tap / 3-finger tap
- or drag the **history scrubber** at the top
### Menus that stay out of the way
| Where | What |
|---|---|
| Left rail | Tools. Warm colours draw, cool colours edit. |
| Slim vertical sliders | Size and opacity of the current tool (or of the selection). |
| Strip beside the rail | Only the current tool's options. |
| Bottom | Palette (11 presets; tap the name to switch), recent colours, custom colour. Presets: Ink, Bright, Pastel, Earth, Neon, Skin, Blueprint, Marker greys, BlackOps, Cyberpunk, Chill. |
| Right-click / pen button / long-press / **Q** | Radial wheel at your pointer. |
| **Tab** | Focus mode: only the canvas and undo. |
| Hub (⊞) | Big tiles for Make, Spaces, Export, Recall, Feel and Help. |
### Keys
| Key | Action |
|---|---|
| B | Pen |
| S | Shapes |
| T | Text |
| F | Fill |
| E | Eraser |
| V | Select |
| J | Joints |
| D | Dimension |
| I / Alt | Pick colour |
| H / Space | Pan |
| [ ] | Size |
| Shift + [ ] | Opacity |
| P | Next drawing space |
| M | Snap on/off |
| L | Lightbox |
| G | Grid |
| N | New layer |
| Shift+N | New board |
| X | Motion mode |
| Ctrl+C | Copy image (Ctrl+Shift+C copies the layer) |
| Ctrl+D | Duplicate |
| Ctrl+S | Save to Recall (Ctrl+Shift+S saves a PNG) |
| Ctrl+Enter | Send to AI |
| 0 | Fit to screen |
| Shift (while drawing) | Straight line / square shape / 15° steps |
| Alt (while drawing) | Draw shape from its centre |
## Export formats
| Format | What you get |
|---|---|
| PNG / Transparent PNG / JPG | Flattened picture, at 0.5×–3× scale |
| SVG | True vectors. Layers become Inkscape layers (`<g inkscape:groupmode="layer">`). Text stays text, including text on a path. |
| ORA (OpenRaster) | Layered file for Krita, GIMP and MyPaint, with opacity and blend modes kept |
| Layers ZIP | One PNG per layer + flat + transparent + SVG + `layers.json` |
| Items ZIP | Every item as its own cropped PNG, in folders by layer and type, + `items.json` with positions and colours |
| .sketchflow | The full editable board. Re-open it with Hub → Make → Open. |
| Clipboard / Share | Copy pastes into any app. Share uses your device's share sheet. |
## Privacy
Everything runs on your machine. The server listens on `127.0.0.1` only, unless you turn on LAN mode, which requires the pairing code. Board commands need a random per-run token. Boards are stored only in your browser. The only network request the app makes is the optional AI cut-out download.
## Roadmap
These build on the same joint model:
- an animation timeline (keyframes of joint positions, onion skin)
- smart connectors that stay attached to shapes
- slider and prismatic joints, gears and springs in the motion solver
- the 3D profile sketcher's geometric constraints (parallel, perpendicular, equal length) on the 2D board too
- sending a 2D board sketch to the 3D workspace as a profile, and projecting 3D views back onto the board
- 3D: see "What is not there yet" in [model/ARCHITECTURE.md](model/ARCHITECTURE.md): STEP with exact curved surfaces (cylinders, cones) and import of curved CAD files, branches for shared models, live cursors
## Tests
```bash
npm test # 3D kernel, model (incl. the pump housing example), gears, welding, add-ons, collisions, the MCP op reference, STEP, shared editing
node build.mjs # rebuild dist/
```
TDQS
Scored across 24 tools
The set has a strong conceptual split: unprefixed 2D sketching tools (draw, edit_items, layers, look, export) versus a model_* prefix for the 3D workspace (model_build, model_view, model_export, model_check). A few boundaries blur: board's 'open (id)' action overlaps with the separate open_board tool, 'say' exists both as a standalone tool and as a model_session action, and board.model undo/redo mirrors model_session undo/redo. These are mostly clarified by descriptions, so misselection is unlikely but possible.
A clear, predictable scheme is at work: everything 3D is model_* (model_build, model_describe, model_query, model_mass...), plus open_board/open_model and wait_for_sketch. The 2D side is less uniform, mixing bare nouns/verbs (board, layers, mechanism, export, say, look) with verb_noun forms (edit_items, place_image), but it remains readable and the domain grouping is consistent.
24 tools is on the heavy side, but the server covers two large domains (2D sketching and parametric 3D CAD) plus kinematics, import/export, mass properties, interference checks and add-ons. Heavy front-end action-multiplexing in board, edit_items, model_build and model_session keeps many operations folded into fewer tools, so most entries earn their place.
Lifecycle coverage is broad: create/edit/delete/transform for 2D items, full layer management, drawing-space/guides, image placement, many export formats, and for 3D a full build/describe/query/check/mass/import/export/version/sharing surface. Minor gaps remain, such as no explicit delete or duplicate action for saved boards and no PDF engineering-drawing export.