diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..4b825b97 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,85 @@ +# SolveCraft — instructions for agents + +SolveCraft is a clean-room, open-source, pure-Rust parametric 3D CAD application in the style of +Autodesk Fusion: sketches with a constraint solver, a parametric timeline of features, a B-rep +kernel, and a desktop UI that agents can drive. Siblings with the same conventions live next to +it in `storytold/`: `cadcraft` (AutoCAD-style, the closest relative), `photocraft`, `vectorcraft`, +`gridcraft`, `designcraft`, `wordcraft`, `deckcraft`, `soundcraft`. Repos don't share code; when +code is adapted from a sibling (MIT OR Apache-2.0) it is noted in ATTRIBUTION.md. + +## Start every session here +1. Read `plan/STATUS.md` (current milestone, next task), then the task in `plan/execution-plan.md` + and the relevant `plan/architecture.md` section. Behaviour reference: `plan/fusion/` + (`menu-tree.json` is Fusion's toolbar dump; `oracle/*/` are parts built in Fusion with their + recipes and measurements). +2. Kernel and library decisions: `plan/adr/0001-geometry-kernel.md` (what we may depend on, what + is rejected for licence reasons). +3. Follow the autonomous operation protocol (`plan/execution-plan.md` §6). Don't stop to ask + unless it lists the decision as the owner's. + +`plan/` is gitignored (local only). + +## Never crash +People trust SolveCraft with their designs; a crash loses their work. **This outranks feature work.** +- **No panics in non-test code:** no `unwrap()`, `expect()`, `panic!`, `unreachable!`, `todo!`, + `unimplemented!`; no `unsafe` (`unsafe_code = "forbid"`). +- **Errors are `Result`** through the crate's error type and `?`. An unfinished feature + returns an error ("not supported yet: …"); it never panics. +- **Input-derived numbers are hostile** (command parameters, design files, control-channel + input): `get()` not `[i]`, finite checks, caps on sizes and loop counts. +- **Third-party kernel calls are guarded:** everything that calls `truck` goes through + `solvecraft_kernel::guard`, which turns a panic into `KernelError::Internal`. +- **Last-resort guard:** `Session::execute` runs every command under `catch_unwind`; an escaped + panic restores the design and reports `EngineError::Internal`. +- **Prove it:** every crash fix lands with a regression test (see `hostile_params_never_panic`). +- Every production crate root carries + `#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]`. + +## Non-negotiables +- **Clean-room.** Fusion may be *observed* black-box (its UI, its toolbar dump, parts built in it + and their measurements, kept under `plan/fusion/`, never committed). Never copy Autodesk icons, + artwork, help text, tooltips, templates or materials, and never commit files produced by + Fusion. Command ids and command names are used as identifiers only (`xtask/data/fusion-catalog.tsv` + holds ids and names, nothing else). File formats come from public specifications. **Never read, + copy or link GPL/LGPL/AGPL code**: OpenCASCADE, FreeCAD (incl. planegcs), SolveSpace, + CadQuery/OCP, LibreCAD, QCAD — don't even read their sources. The sketch solver and the blend + operations are our own. +- **Assets — absolutely essential.** SolveCraft contains **no Autodesk iconography, images, + fonts or artwork — ever.** Every icon is drawn in code (`crates/ui-egui/src/icons.rs`). Any + file asset must be original or openly licensed and **must have a row in ATTRIBUTION.md** + (`cargo xtask assets` enforces it). Screenshots of Autodesk software are never committed. + Breaking this rule is the most serious mistake you can make in this repo. +- **Everything is a command.** User-visible behaviour = a command in `crates/engine/src/cmd/*` + (`CommandSpec`: id = Fusion's command id where Fusion has the command, else a dotted id; label; + toolbar tab and panel; icon; shortcut; params doc; `enabled`; JSON `run`) + tests. The toolbar, + dialogs, sketch tools, palette, scripts, CLI and control channel all reach the same commands. +- **Programmatic calls never open dialogs.** `engine.execute` runs the JSON form; only toolbar + clicks (`ui.start`) start interactive tools and dialogs, which then run commands. +- **Layering** is enforced by `cargo xtask layers`: L0 `geom` → L1 `sketch`, `kernel`, `render` + → L2 `doc` → L3 `io` → L4 `engine` → L5 `ui-egui` → apps. Nothing below L5 depends on + egui/eframe/winit/wgpu/rfd. **The UI crate is swappable.** Only `crates/kernel` may use `truck`. +- **The UI is thin**: panels read engine state and act through `app.run(id, params)` / + `app.start(id)`. Colours come from `theme::Tokens`. +- **Rust only.** Units are millimetres and radians internally; Z is up. +- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, + assets, layers). Commit after every feature arc that builds. + +## Running and looking at the app +- `cargo run --release -p solvecraft -- --sample --control PORT` (sample design + control channel). + Pick a free port. Without a display, run it under `Xvfb :99` with `DISPLAY=:99`. +- Drive it with JSON lines on `127.0.0.1:PORT` (see `docs/control-protocol.md`): + - `{"id":1,"method":"engine.execute","params":{"command":"Extrude","params":{"distance":20}}}` + - `{"id":2,"method":"ui.start","params":{"command":"SketchCreate"}}` then `ui.click {x, y}` + - `{"id":3,"method":"ui.screenshot","params":{"path":"/tmp/shot.png"}}` then read the PNG. +- **For UI work, look at the result** (screenshot, read the PNG). Without a window use + `ui.render` or `solvecraft-cli snapshot`. +- Headless: `solvecraft-cli run script.json --out part.step`, `solvecraft-cli eval design.solvecraft`, + `solvecraft-cli snapshot script.json --out shot.png`, `solvecraft-cli commands`. +- Fusion oracle: `cargo xtask oracle` replays `plan/fusion/oracle/*/recipe.json` and compares + with Fusion's `measure.json` (writes `docs/oracle.md`). +- Build with `CARGO_TARGET_DIR=/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. + +## Roadmap +`ROADMAP.md` (committed) tracks status, milestones, parity and estimates. Update it whenever a +milestone task lands. `cargo xtask parity` recomputes command parity in `docs/parity.md`; +`cargo xtask oracle` recomputes `docs/oracle.md`. diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md new file mode 100644 index 00000000..209f6e9b --- /dev/null +++ b/ATTRIBUTION.md @@ -0,0 +1,31 @@ +# Attribution + +Every non-code asset in this repository (images, icons, fonts, example parts) is listed here with +its author, source and licence. `cargo xtask assets` (part of `cargo xtask ci`) fails if an asset +file is missing from this table. + +**Policy (mandatory):** SolveCraft contains **no Autodesk iconography, images, artwork, fonts, +templates, materials or help text.** Every asset is original work by SolveCraft contributors or +third-party material under an open licence. Screenshots of Autodesk software are never committed. + +Generated-in-code assets are original and have no file to list: +- the UI icon set (`crates/ui-egui/src/icons.rs`); +- the view cube, navigation bar and timeline glyphs (`crates/ui-egui/src/viewport.rs`, + `crates/ui-egui/src/timeline.rs`). + +## Files + +| File | Author | Source | Licence | +|---|---|---|---| +| docs/screenshots/sample-plate.png | SolveCraft contributors | screenshot of SolveCraft itself (`solvecraft --sample`) | MIT OR Apache-2.0 | + +## Code adapted from sibling projects + +| SolveCraft file | Adapted from | Licence | +|---|---|---| +| xtask/src/layers.rs | CADCraft `xtask/src/layers.rs` (dependency layering rules and tests) | MIT OR Apache-2.0 | +| apps/solvecraft/src/control_server.rs | CADCraft `apps/cadcraft/src/control_server.rs` (loopback JSON-lines server) | MIT OR Apache-2.0 | +| crates/ui-egui/src/lib.rs (screenshot queue, synthetic input) | CADCraft `crates/ui-egui/src/lib.rs` | MIT OR Apache-2.0 | +| crates/ui-egui/src/control.rs (method dispatch and screenshot saving) | CADCraft `crates/ui-egui/src/control.rs` | MIT OR Apache-2.0 | +| crates/ui-egui/src/gpu.rs (paint-callback structure) | CADCraft `crates/ui-egui/src/gpu.rs` | MIT OR Apache-2.0 | +| LICENSE-MIT, LICENSE-APACHE (licence text) | CADCraft | — | diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..4b825b97 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,85 @@ +# SolveCraft — instructions for agents + +SolveCraft is a clean-room, open-source, pure-Rust parametric 3D CAD application in the style of +Autodesk Fusion: sketches with a constraint solver, a parametric timeline of features, a B-rep +kernel, and a desktop UI that agents can drive. Siblings with the same conventions live next to +it in `storytold/`: `cadcraft` (AutoCAD-style, the closest relative), `photocraft`, `vectorcraft`, +`gridcraft`, `designcraft`, `wordcraft`, `deckcraft`, `soundcraft`. Repos don't share code; when +code is adapted from a sibling (MIT OR Apache-2.0) it is noted in ATTRIBUTION.md. + +## Start every session here +1. Read `plan/STATUS.md` (current milestone, next task), then the task in `plan/execution-plan.md` + and the relevant `plan/architecture.md` section. Behaviour reference: `plan/fusion/` + (`menu-tree.json` is Fusion's toolbar dump; `oracle/*/` are parts built in Fusion with their + recipes and measurements). +2. Kernel and library decisions: `plan/adr/0001-geometry-kernel.md` (what we may depend on, what + is rejected for licence reasons). +3. Follow the autonomous operation protocol (`plan/execution-plan.md` §6). Don't stop to ask + unless it lists the decision as the owner's. + +`plan/` is gitignored (local only). + +## Never crash +People trust SolveCraft with their designs; a crash loses their work. **This outranks feature work.** +- **No panics in non-test code:** no `unwrap()`, `expect()`, `panic!`, `unreachable!`, `todo!`, + `unimplemented!`; no `unsafe` (`unsafe_code = "forbid"`). +- **Errors are `Result`** through the crate's error type and `?`. An unfinished feature + returns an error ("not supported yet: …"); it never panics. +- **Input-derived numbers are hostile** (command parameters, design files, control-channel + input): `get()` not `[i]`, finite checks, caps on sizes and loop counts. +- **Third-party kernel calls are guarded:** everything that calls `truck` goes through + `solvecraft_kernel::guard`, which turns a panic into `KernelError::Internal`. +- **Last-resort guard:** `Session::execute` runs every command under `catch_unwind`; an escaped + panic restores the design and reports `EngineError::Internal`. +- **Prove it:** every crash fix lands with a regression test (see `hostile_params_never_panic`). +- Every production crate root carries + `#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]`. + +## Non-negotiables +- **Clean-room.** Fusion may be *observed* black-box (its UI, its toolbar dump, parts built in it + and their measurements, kept under `plan/fusion/`, never committed). Never copy Autodesk icons, + artwork, help text, tooltips, templates or materials, and never commit files produced by + Fusion. Command ids and command names are used as identifiers only (`xtask/data/fusion-catalog.tsv` + holds ids and names, nothing else). File formats come from public specifications. **Never read, + copy or link GPL/LGPL/AGPL code**: OpenCASCADE, FreeCAD (incl. planegcs), SolveSpace, + CadQuery/OCP, LibreCAD, QCAD — don't even read their sources. The sketch solver and the blend + operations are our own. +- **Assets — absolutely essential.** SolveCraft contains **no Autodesk iconography, images, + fonts or artwork — ever.** Every icon is drawn in code (`crates/ui-egui/src/icons.rs`). Any + file asset must be original or openly licensed and **must have a row in ATTRIBUTION.md** + (`cargo xtask assets` enforces it). Screenshots of Autodesk software are never committed. + Breaking this rule is the most serious mistake you can make in this repo. +- **Everything is a command.** User-visible behaviour = a command in `crates/engine/src/cmd/*` + (`CommandSpec`: id = Fusion's command id where Fusion has the command, else a dotted id; label; + toolbar tab and panel; icon; shortcut; params doc; `enabled`; JSON `run`) + tests. The toolbar, + dialogs, sketch tools, palette, scripts, CLI and control channel all reach the same commands. +- **Programmatic calls never open dialogs.** `engine.execute` runs the JSON form; only toolbar + clicks (`ui.start`) start interactive tools and dialogs, which then run commands. +- **Layering** is enforced by `cargo xtask layers`: L0 `geom` → L1 `sketch`, `kernel`, `render` + → L2 `doc` → L3 `io` → L4 `engine` → L5 `ui-egui` → apps. Nothing below L5 depends on + egui/eframe/winit/wgpu/rfd. **The UI crate is swappable.** Only `crates/kernel` may use `truck`. +- **The UI is thin**: panels read engine state and act through `app.run(id, params)` / + `app.start(id)`. Colours come from `theme::Tokens`. +- **Rust only.** Units are millimetres and radians internally; Z is up. +- **Quality gates** before every commit: `cargo xtask ci` (fmt, clippy -D warnings, tests, + assets, layers). Commit after every feature arc that builds. + +## Running and looking at the app +- `cargo run --release -p solvecraft -- --sample --control PORT` (sample design + control channel). + Pick a free port. Without a display, run it under `Xvfb :99` with `DISPLAY=:99`. +- Drive it with JSON lines on `127.0.0.1:PORT` (see `docs/control-protocol.md`): + - `{"id":1,"method":"engine.execute","params":{"command":"Extrude","params":{"distance":20}}}` + - `{"id":2,"method":"ui.start","params":{"command":"SketchCreate"}}` then `ui.click {x, y}` + - `{"id":3,"method":"ui.screenshot","params":{"path":"/tmp/shot.png"}}` then read the PNG. +- **For UI work, look at the result** (screenshot, read the PNG). Without a window use + `ui.render` or `solvecraft-cli snapshot`. +- Headless: `solvecraft-cli run script.json --out part.step`, `solvecraft-cli eval design.solvecraft`, + `solvecraft-cli snapshot script.json --out shot.png`, `solvecraft-cli commands`. +- Fusion oracle: `cargo xtask oracle` replays `plan/fusion/oracle/*/recipe.json` and compares + with Fusion's `measure.json` (writes `docs/oracle.md`). +- Build with `CARGO_TARGET_DIR=/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. + +## Roadmap +`ROADMAP.md` (committed) tracks status, milestones, parity and estimates. Update it whenever a +milestone task lands. `cargo xtask parity` recomputes command parity in `docs/parity.md`; +`cargo xtask oracle` recomputes `docs/oracle.md`. diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..3ab2b2bf --- /dev/null +++ b/NOTICE @@ -0,0 +1,21 @@ +SolveCraft +Copyright (c) 2026 SolveCraft contributors. +Licensed under the MIT License or the Apache License, Version 2.0, at your option +(LICENSE-MIT, LICENSE-APACHE). + +Third-party material + +Software dependencies are listed in Cargo.lock. The geometry kernel builds on the truck crates +(truck-modeling, truck-shapeops, truck-meshalgo, truck-stepio, truck-topology and their +dependencies, https://github.com/ricosjp/truck), licensed under the Apache License 2.0 and used +unmodified as libraries. + +Some code is adapted from sibling projects in the storytold family (CADCraft), which are +licensed MIT OR Apache-2.0; ATTRIBUTION.md lists the files. + +None of the bundled assets come from third parties: every icon is drawn in code. The per-file +list is in ATTRIBUTION.md. + +SolveCraft is an independent project and is not affiliated with, sponsored by or endorsed by +Autodesk, Inc. Autodesk and Fusion are trademarks of Autodesk, Inc.; they are used here only to +describe compatibility goals. diff --git a/README.md b/README.md new file mode 100644 index 00000000..c4c4710d --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# SolveCraft + +SolveCraft is an open-source parametric 3D CAD application written in Rust, in the style of +Autodesk Fusion: sketch on a plane, constrain and dimension the sketch, turn profiles into solids +with extrude and revolve, round edges, combine bodies, and change a parameter to watch the whole +timeline rebuild. It is a clean-room implementation (see [CLAUDE.md](CLAUDE.md)) and part of the +storytold "craft" family. + +![SolveCraft with the sample plate](docs/screenshots/sample-plate.png) + +**Status: early (milestone M0 done, M1 in progress).** See [ROADMAP.md](ROADMAP.md), +[docs/parity.md](docs/parity.md) (command parity with Fusion's Design workspace) and +[docs/oracle.md](docs/oracle.md) (parts built in Fusion, rebuilt and measured in SolveCraft). + +## What works + +- **Sketches** on the origin planes, offset planes or planar faces: lines, rectangles (2-point, + 3-point, centre), circles (centre, 2-point, 3-point), arcs (3-point, centre), polygons, slots + and points; construction geometry. +- **Constraints and dimensions** solved by our own solver (damped Gauss–Newton with + degree-of-freedom analysis): coincident, horizontal/vertical, parallel, perpendicular, tangent, + equal, concentric, collinear, midpoint, symmetry, fix; linear, aligned, horizontal, vertical, + radius, diameter and angle dimensions driven by parameters. Over-constraining edits are + rejected; fully constrained geometry turns black. +- **Profiles** found automatically, including regions split by lines and holes inside outlines. +- **Features** on a parametric timeline: extrude (one side, flipped, symmetric, two-sided, start + offset; new body, join, cut, intersect), revolve, fillet and chamfer (straight convex edges), + box, cylinder, sphere, torus, combine, move. The timeline rebuilds incrementally from the first + changed feature; it can be rolled back, and features can be suppressed, renamed, edited and + deleted. +- **Parameters** with unit-aware expressions (`2 * width + 5 mm`, `angle / 2`). +- **Files**: designs as JSON (`.solvecraft`), export to STEP, STL (binary/ASCII) and OBJ. +- **Desktop app** (egui + wgpu): toolbar with workspace tabs, browser, timeline, 3D viewport with + view cube and navigation bar, sketch tools, feature dialogs, command palette, and a JSON-lines + control channel so agents and tests can drive it. +- **Headless CLI** `solvecraft-cli`: run command scripts, measure (volume, area, centre of mass, + face/edge/vertex counts), export, render PNG snapshots, replay Fusion oracle recipes. + +## Build and run + +```sh +cargo run --release -p solvecraft -- --sample # desktop app with a sample part +cargo run --release -p solvecraft-cli -- commands # the command registry +cargo run --release -p solvecraft-cli -- run examples/bracket.json --out bracket.step +cargo run --release -p solvecraft-cli -- snapshot examples/bracket.json --out bracket.png +cargo xtask ci # fmt, clippy, tests, assets, layers +``` + +Windows builds: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. + +## Scripts + +A script is a JSON list of commands, the same ones the UI runs: + +```json +{"commands": [ + {"command": "SketchCreate", "params": {"plane": "XY"}}, + {"command": "ShapeRectangleTwoPoint", "params": {"p0": [0, 0], "p1": [40, 30]}}, + {"command": "Extrude", "params": {"distance": 20}}, + {"command": "FusionFilletEdgesCommand", "params": {"edges": [[0, 0, 10]], "radius": 3}} +]} +``` + +## Architecture + +| Layer | Crates | Role | +|---|---|---| +| L0 | `geom` | vectors, planes, profiles, meshes and their measures | +| L1 | `sketch`, `kernel`, `render` | constraint solver and profiles; the B-rep kernel boundary (truck); view math and CPU rasterizer | +| L2 | `doc` | parameters, expressions, the feature timeline and its incremental evaluation | +| L3 | `io` | design files, STL/OBJ/STEP export | +| L4 | `engine` | the session and the command registry (everything is a command) | +| L5 | `ui-egui` | the swappable desktop front end | +| apps | `solvecraft`, `solvecraft-cli` | desktop app, headless CLI | + +## Licence + +MIT OR Apache-2.0, at your option. SolveCraft is not affiliated with Autodesk; Fusion is a +trademark of Autodesk, Inc. diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000..53e9e14e --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,48 @@ +# SolveCraft roadmap + +Status as of **2026-10-07**. SolveCraft targets Fusion-style parametric modelling (sketch → +features → parametric timeline) as an open, pure-Rust, agent-drivable application. + +## At a glance + +| Question | Answer | +|---|---| +| Where are we? | **M0 (vertical slice) done.** Sketch with solver, extrude/revolve/fillet/chamfer/cut, parameters that rebuild the timeline, STEP/STL export, desktop app, CLI, oracle harness. | +| Command parity (SOLID + SKETCH toolbar) | **46 / 291 (16%)** — [docs/parity.md](docs/parity.md) | +| Fusion oracle | **2 / 29 parts match** Fusion's measurements (16 need features not built yet) — [docs/oracle.md](docs/oracle.md) | +| Tests | 60 (solver, profiles, kernel booleans/blends/measures, expressions, timeline, file formats, camera, engine end-to-end, hostile-input fuzz over every command) | +| Gates | `cargo xtask ci`: fmt, clippy -D warnings, tests, asset attribution, layering — green | +| Weighted parity estimate | **≈ 5%** of Fusion's Design workspace by importance (sketch + basic solids are the core, but surfaces, assemblies, sheet metal, CAM, drawings are untouched) | +| Time to a useful alpha (M0–M6) | ≈ **150 agent hours** remain | + +## Milestones + +| # | Milestone | Status | Hours left | +|---|---|---|---| +| M0 | Vertical slice | done | — | +| M1 | Sketch depth, oracle sketch cases (arcs, taper, two-sided, sketch modify tools) | in progress | 16 | +| M2 | Robust modelling: coplanar booleans in the kernel, holes, patterns, mirror, shell, draft, split, construction geometry | planned | 24 | +| M3 | General fillets and chamfers (curved edges, chains, vertex blends) | planned | 30 | +| M4 | Files: STEP import, mesh import, DXF sketches, 3MF | planned | 16 | +| M5 | Persistent naming of faces and edges | planned | 20 | +| M6 | UI depth: profile shading, selection filters, measure tool, section view, edit dialogs, drag-solve | planned | 24 | +| M7 | Sweep, loft, rib, web, emboss, thread, coil, pipe | planned | 24 | +| M8 | Surface workspace | planned | 30 | +| M9 | Assemblies and joints | planned | 40 | +| M10 | Sheet metal | planned | 30 | +| M11 | 2D drawings | planned | 30 | +| M12 | Release: installers, signing, docs, performance | planned | 16 | + +## Known limitations + +- Fillets and chamfers: straight convex edges between planar faces with perpendicular planar end + faces; two blended edges may not share a corner yet. +- Booleans of bodies with coincident faces fail unless they come from extrudes (where the tool is + extended automatically); fully internal voids are not supported. +- Mass properties come from fine tessellation (curved faces within ~1e-4 relative). +- No STEP import yet; no persistent naming (fillet edges are re-found by position). + +## Kernel + +truck (Apache-2.0) behind our own `kernel` crate, with our own blend operation and boolean +retry/validation; see `plan/adr/0001-geometry-kernel.md` (local) — summary in README. diff --git a/docs/control-protocol.md b/docs/control-protocol.md new file mode 100644 index 00000000..43c44cc8 --- /dev/null +++ b/docs/control-protocol.md @@ -0,0 +1,46 @@ +# Control protocol + +`solvecraft --control PORT` (or `SOLVECRAFT_CONTROL_PORT=PORT`) listens on `127.0.0.1:PORT` for +JSON lines. Each request is one line `{"id": …, "method": "…", "params": {…}}`; each reply is one +line `{"id": …, "ok": true, "result": …}` or `{"id": …, "ok": false, "error": "…"}`. Requests are +handled on the UI thread between frames; pointer and keyboard input is injected as real egui +events, one pointer event per frame. + +## Engine + +| Method | Params | Result | +|---|---|---| +| `engine.execute` | `command`: command id, `params`: JSON object | the command's result | +| `engine.script` | `commands`: `[{command, params}, …]` | results, stops at the first error | +| `engine.commands` | — | every command: id, label, tab, panel, icon, shortcut, params doc, enabled | +| `document.inspect` | `measure?`: bool | parameters, timeline (errors, timings), bodies, sketches, selection | + +Commands never open dialogs when run this way. `solvecraft-cli commands` prints the same registry. + +## UI + +| Method | Params | Notes | +|---|---|---| +| `ui.inspect` | — | UI state, viewport rect, camera, active tool/dialog, hover, renderer, timings | +| `ui.set` | any `UiState` field (`tab`, `perspective`, `showGrid`, `hiddenBodies`, …) | | +| `ui.view` | `view`: `front`, `back`, `top`, `bottom`, `left`, `right`, `iso`, `home`, `fit` | | +| `ui.start` | `command` | like a toolbar click: starts the sketch tool or dialog for the command | +| `ui.click` | `x`, `y` (screen points), `button?`: left/right/middle, `shift?` | real pointer input | +| `ui.move` | `x`, `y` | | +| `ui.scroll` | `x`, `y`, `delta?` | wheel zoom at the cursor | +| `ui.key` | `key` (egui key name, `Enter`, `Escape`…), `cmd?`, `shift?` | | +| `ui.text` | `text` | typed text | +| `ui.screenshot` | `path?` | PNG of the window (needs a presented frame) | +| `ui.render` | `path`, `width?`, `height?` | CPU render of the model with the current camera (no window needed) | +| `ui.resize` | `width`, `height` | | +| `app.quit` | — | | + +## Example + +```text +{"id":1,"method":"engine.execute","params":{"command":"SketchCreate","params":{"plane":"XY"}}} +{"id":2,"method":"engine.execute","params":{"command":"ShapeRectangleTwoPoint","params":{"p0":[0,0],"p1":[40,30]}}} +{"id":3,"method":"engine.execute","params":{"command":"Extrude","params":{"distance":20}}} +{"id":4,"method":"engine.execute","params":{"command":"FusionFilletEdgesCommand","params":{"edges":[[0,0,10]],"radius":3}}} +{"id":5,"method":"ui.screenshot","params":{"path":"/tmp/part.png"}} +``` diff --git a/docs/oracle.md b/docs/oracle.md new file mode 100644 index 00000000..0d9395db --- /dev/null +++ b/docs/oracle.md @@ -0,0 +1,37 @@ +# Fusion oracle + +Generated by `cargo xtask oracle`. Each case is a part built in Fusion (recipe and measurements kept locally in `plan/fusion/oracle/`, not committed). SolveCraft replays the recipe through its command engine and compares body count, volume and area (relative tolerance 1e-3) and face/edge/vertex counts (exact). + +**2 / 29 cases pass** (16 need features not implemented yet). + +| Case | Result | Notes | +|---|---|---| +| 01-box | pass | | +| 02-cylinder | pass | | +| 03-box-through-hole | FAIL | step 11 (Extrude): invalid parameters for `Extrude`: `distance` must be a number or an expression | +| 04-revolve-vase | not yet | recipe: sketch entity type `arc_three_point` is not supported yet | +| 05-taper-extrude | FAIL | volume_mm3: got 48000.0 want 61814.82596; area_mm2: got 8000.0 want 9676.91517 | +| 06-symmetric-extrude | FAIL | volume_mm3: got 15000.0 want 30000.0; area_mm2: got 4100.0 want 6200.0 | +| 07-fillet-all-edges | FAIL | step 8 (FusionFilletEdgesCommand): not supported yet: the faces at the edge ends must be planar | +| 08-chamfer | FAIL | step 8 (FusionChamferCommand): not supported yet: the faces at the edge ends must be perpendicular to the edge | +| 09-shell | not yet | recipe: feature op `shell` is not supported yet | +| 10-rect-pattern-holes | not yet | recipe: feature op `rectangular_pattern` is not supported yet | +| 11-circular-pattern-flange | not yet | recipe: feature op `circular_pattern` is not supported yet | +| 12-mirror-feature | not yet | recipe: feature op `mirror` is not supported yet | +| 13-combine-join | not yet | recipe: feature op `combine` is not supported yet | +| 14-combine-cut | not yet | recipe: sketch entity type `arc_three_point` is not supported yet | +| 15-combine-intersect | not yet | recipe: sketch entity type `arc_three_point` is not supported yet | +| 16-sweep | not yet | recipe: sketch entity type `arc_three_point` is not supported yet | +| 17-loft | not yet | recipe: feature op `construction_plane` is not supported yet | +| 18-hole-features | not yet | recipe: feature op `hole` is not supported yet | +| 19-l-bracket-constrained | FAIL | step 8 (ConstraintHorizontalVertical): invalid parameters for `ConstraintHorizontalVertical`: `line` must be a curve id | +| 20-slot-constrained | not yet | recipe: sketch entity type `arc_center_start_sweep` is not supported yet | +| 21-draft | not yet | recipe: feature op `draft` is not supported yet | +| 22-split-body | not yet | recipe: feature op `construction_plane` is not supported yet | +| 23-bracket-multifeature | not yet | recipe: feature op `construction_plane` is not supported yet | +| 24-user-parameters | FAIL | step 11 (ConstraintCoincident): invalid parameters for `ConstraintCoincident`: `a` must be a point reference | +| 25-sketch-triangle | FAIL | step 5 (ConstraintCoincident): invalid parameters for `ConstraintCoincident`: `a` must be a point reference | +| 26-sketch-belt | not yet | recipe: constraint `horizontal_points` is not supported yet | +| 27-sketch-trapezoid | FAIL | step 9 (ConstraintHorizontalVertical): invalid parameters for `ConstraintHorizontalVertical`: `line` must be a curve id | +| 28-blind-pocket-fillets | FAIL | step 15 (FusionFilletEdgesCommand): not supported yet: the blend is larger than the neighbouring faces | +| 29-two-sided-and-partial-revolve | FAIL | step 7 (Extrude): invalid parameters for `Extrude`: `distance` must be a number or an expression | diff --git a/docs/screenshots/sample-plate.png b/docs/screenshots/sample-plate.png new file mode 100644 index 00000000..d35c51ce Binary files /dev/null and b/docs/screenshots/sample-plate.png differ diff --git a/examples/bracket.json b/examples/bracket.json new file mode 100644 index 00000000..80b26577 --- /dev/null +++ b/examples/bracket.json @@ -0,0 +1,14 @@ +{"commands": [ + {"command": "ChangeParameterCommand", "params": {"name": "width", "expression": "60 mm"}}, + {"command": "ChangeParameterCommand", "params": {"name": "thickness", "expression": "6 mm"}}, + {"command": "SketchCreate", "params": {"plane": "XZ", "name": "Profile"}}, + {"command": "DrawPolyline", "params": {"points": [[0, 0], [40, 0], [40, 6], [6, 6], [6, 30], [0, 30]], "closed": true, "ids": ["a", "b", "c", "d", "e", "f"]}}, + {"command": "SketchStop", "params": {}}, + {"command": "Extrude", "params": {"distance": "width", "direction": "negative", "body_name": "Bracket"}}, + {"command": "FusionFilletEdgesCommand", "params": {"edges": [[40, 30, 6]], "radius": 2}}, + {"command": "SketchCreate", "params": {"plane": "XY", "name": "Holes"}}, + {"command": "CircleCenterRadius", "params": {"center": [25, 15], "diameter": 8}}, + {"command": "CircleCenterRadius", "params": {"center": [25, 45], "diameter": 8}}, + {"command": "SketchStop", "params": {}}, + {"command": "Extrude", "params": {"distance": "thickness", "operation": "cut"}} +]}