Retire legacy reference data and the external command catalog (#302)

- Remove xtask/data/fusion-catalog.tsv and xtask/data/fusion-ids.tsv.
- Remove the legacy command-id table (crates/engine/src/legacy_ids.rs) and its use in
  find_command and in the shortcut, recents and pinned-command loaders. Only SolidCraft's
  dotted ids name commands; any other id is an unknown command.
- Boundary Fill's id becomes solid.boundary_fill.
- Replace the parity report with SolidCraft's own feature checklist: `cargo xtask features`
  writes docs/features.md from the command registry.
- docs/oracle.md, docs/step-import.md (corpus section) and docs/iges-import.md: reference
  results are being rebuilt on analytic and open-source (FreeCAD) values; see #292.
  `cargo xtask oracle` and `cargo xtask step-corpus [--iges]` write these placeholders.
- AGENTS.md, CLAUDE.md, CONTRIBUTING.md, README.md, ROADMAP.md and the book describe
  SolidCraft as independent, with reference tests on analytic values and open-source tools,
  and agents do not drive or extract data from commercial CAD products.


Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-12 11:19:15 -04:00
1 parent c7f0139ad4
commit 3b8028a040
32 files changed
+695 -2324

No files matched your search

+19 -18
View File
@@ -16,8 +16,7 @@ compatibility notes.
## 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).
and the relevant `plan/architecture.md` section.
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
@@ -42,20 +41,22 @@ People trust SolidCraft with their designs; a crash loses their work. **This out
`#![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. (`tools/freecad-oracle/` runs
FreeCAD as a separate program through its public scripting API to compute reference values;
- **Independent.** SolidCraft is independent. Behaviour is designed from public documentation,
general CAD conventions and user feedback. Reference tests use analytic values and open-source
tools. Never copy another product's code, icons, artwork, help text, tooltips, templates or
materials. File formats come from public specifications.
- **No commercial CAD products.** Agents must not drive, script, automate or extract data from
commercial CAD products (Fusion, SolidWorks, Onshape, …) for this project: no test data,
measurements, command lists, ids or files produced with them.
- **Never read, copy or link GPL/LGPL/AGPL code**: OpenCASCADE, FreeCAD (incl. planegcs),
SolveSpace, CadQuery/OCP, LibreCAD, QCAD — don't even read their sources. (`tools/freecad-oracle/`
runs FreeCAD as a separate program through its public scripting API to compute reference values;
nothing from FreeCAD is linked, vendored or shipped.) The sketch solver and the blend
operations are our own.
- **Assets — absolutely essential.** SolidCraft 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.
- **Assets — absolutely essential.** SolidCraft contains **no iconography, images, fonts or
artwork from commercial CAD products — 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 commercial CAD 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 = our own dotted, lower-case id `<area>.<thing>[.<variant>]` such as
@@ -126,10 +127,10 @@ before the draft is verified.
`solvecraft-cli snapshot script.json --out shot.png`, `solvecraft-cli commands`.
- Reference tests: `cargo xtask oracle` replays `tests/oracle/*/recipe.json` and compares with
each case's `expected.json` (analytic or FreeCAD values; writes `docs/oracle.md`). Expected
values never come from Fusion or any other commercial CAD product.
values never come from a commercial CAD product.
- Build with `CARGO_TARGET_DIR=<repo>/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`.
`ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a
milestone task lands. `cargo xtask features` regenerates `docs/features.md` (SolidCraft's
commands by area, from the registry) when commands are added or renamed.
+19 -18
View File
@@ -16,8 +16,7 @@ compatibility notes.
## 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).
and the relevant `plan/architecture.md` section.
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
@@ -42,20 +41,22 @@ People trust SolidCraft with their designs; a crash loses their work. **This out
`#![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. (`tools/freecad-oracle/` runs
FreeCAD as a separate program through its public scripting API to compute reference values;
- **Independent.** SolidCraft is independent. Behaviour is designed from public documentation,
general CAD conventions and user feedback. Reference tests use analytic values and open-source
tools. Never copy another product's code, icons, artwork, help text, tooltips, templates or
materials. File formats come from public specifications.
- **No commercial CAD products.** Agents must not drive, script, automate or extract data from
commercial CAD products (Fusion, SolidWorks, Onshape, …) for this project: no test data,
measurements, command lists, ids or files produced with them.
- **Never read, copy or link GPL/LGPL/AGPL code**: OpenCASCADE, FreeCAD (incl. planegcs),
SolveSpace, CadQuery/OCP, LibreCAD, QCAD — don't even read their sources. (`tools/freecad-oracle/`
runs FreeCAD as a separate program through its public scripting API to compute reference values;
nothing from FreeCAD is linked, vendored or shipped.) The sketch solver and the blend
operations are our own.
- **Assets — absolutely essential.** SolidCraft 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.
- **Assets — absolutely essential.** SolidCraft contains **no iconography, images, fonts or
artwork from commercial CAD products — 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 commercial CAD 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 = our own dotted, lower-case id `<area>.<thing>[.<variant>]` such as
@@ -103,10 +104,10 @@ before the draft is verified.
`solvecraft-cli snapshot script.json --out shot.png`, `solvecraft-cli commands`.
- Reference tests: `cargo xtask oracle` replays `tests/oracle/*/recipe.json` and compares with
each case's `expected.json` (analytic or FreeCAD values; writes `docs/oracle.md`). Expected
values never come from Fusion or any other commercial CAD product.
values never come from a commercial CAD product.
- Build with `CARGO_TARGET_DIR=<repo>/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`.
`ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a
milestone task lands. `cargo xtask features` regenerates `docs/features.md` (SolidCraft's
commands by area, from the registry) when commands are added or renamed.
+8 -5
View File
@@ -88,13 +88,16 @@ The [README](README.md#architecture) has the layer table. The short version:
## Rules that aren't negotiable
1. **Clean-room.** We observe Fusion as a black box: its UI, how parts it builds measure, and
what it does with a given input. We never copy Autodesk code, icons, artwork, help text,
tooltips, templates or materials, and we never commit files Fusion produced. Command ids are
our own (`solid.fillet`, not Fusion's internal names).
1. **Independent.** SolidCraft is independent. Behaviour is designed from public
documentation, general CAD conventions and user feedback. Reference tests use analytic values
and open-source tools. We don't drive, script, automate or extract data from commercial CAD
products, and we never copy another product's code, icons, artwork, help text, tooltips,
templates or materials. Command ids are our own (`solid.fillet`).
2. **No GPL/LGPL/AGPL code, not even reading it.** That rules out OpenCASCADE, FreeCAD
(including planegcs), SolveSpace, CadQuery/OCP, LibreCAD and QCAD. SolidCraft is
MIT OR Apache-2.0, and its solver and blends are written from the maths. Permissive
MIT OR Apache-2.0, and its solver and blends are written from the maths. (Running an
open-source application to get reference values for a test is fine; reading its source is
not.) Permissive
dependencies are fine. Note which one you're adding and why in the PR, and run
`cargo xtask licences` so THIRD-PARTY-LICENSES.txt lists it (CI checks that it is current).
3. **Every asset is original or openly licensed and has a row in
+4 -3
View File
@@ -20,8 +20,8 @@ SolidCraft application feed. See [install and launch commands](https://bherbruck
**Status: early but usable for simple parts.** 75 of 76 public reference parts
match their analytic or FreeCAD-computed volume, area, centre of mass and bounding box
([docs/oracle.md](docs/oracle.md)); the other is a tracked bug.
These checks do not establish complete geometric or workflow equivalence. Feature coverage
is tracked in [docs/parity.md](docs/parity.md) and [ROADMAP.md](ROADMAP.md).
These checks do not establish complete geometric or workflow equivalence. The commands SolidCraft has
are listed by area in [docs/features.md](docs/features.md); status and plans are in [ROADMAP.md](ROADMAP.md).
Open work and known bugs are in [GitHub issues](https://github.com/bherbruck/solidcraft/issues),
and help is welcome: see [CONTRIBUTING.md](CONTRIBUTING.md).
@@ -168,6 +168,7 @@ MIT OR Apache-2.0, at your option. Developed under the
[clean-room contribution rules](CLAUDE.md); third-party code and assets retain their
documented licences and attribution.
References to other products describe workflow comparisons and benchmark provenance.
SolidCraft is independent. Behaviour is designed from public documentation, general CAD
conventions and user feedback. Reference tests use analytic values and open-source tools.
SolidCraft is not affiliated with, sponsored by or endorsed by Autodesk. Autodesk and
Fusion are trademarks of Autodesk, Inc.
+7 -10
View File
@@ -7,8 +7,8 @@ features → parametric timeline) as an open, pure-Rust, agent-drivable applicat
| Question | Answer |
|---|---|
| Where are we? | **M0 and M13 done; M1, M2, M5–M7, M9, M10, M14 in progress.** Sketch with solver and the full SKETCH create/modify set; extrude, revolve (two sides, symmetric, to object), fillet/chamfer (variable radius, chord length, a radius per edge, corner patches), holes, threads (cosmetic and modelled), patterns, mirror, shell (inside/outside/both), draft, loft, sweep, coil, split body and split face, delete face, construction planes, axes and points; persistent naming of faces and edges; parameters and configurations; components, joints, motion studies, exploded views; sheet metal and a plastic enclosure subset; STEP/IGES/3MF/STL/OBJ/DXF; autosave and crash recovery; desktop and browser (wasm) app, CLI, MCP server, oracle harness. |
| Command parity (in scope) | **335 / 541 (62%)** in-scope commands; SOLID + SKETCH **188 / 291 (65%)** — [docs/parity.md](docs/parity.md); registry breadth does not establish workflow or geometric parity |
| Where are we? | **M0 and M13 done; M1, M2, M5–M7, M9, M10, M14 in progress.** Sketch with solver and the full SKETCH create/modify set; extrude, revolve (two sides, symmetric, to object), fillet/chamfer (variable radius, chord length, a radius per edge, corner patches), holes, threads (cosmetic and modelled), patterns, mirror, shell (inside/outside/both), draft, loft, sweep, coil, split body and split face, delete face, construction planes, axes and points; persistent naming of faces and edges; parameters and configurations; components, joints, motion studies, exploded views; sheet metal and a plastic enclosure subset; STEP/IGES/3MF/STL/OBJ/DXF; autosave and crash recovery; desktop and browser (wasm) app, CLI, MCP server. |
| Features | Every registered command by area — [docs/features.md](docs/features.md) (`cargo xtask features`); registry breadth does not establish workflow or geometric depth |
| Reference tests | **75 / 76 parts match** — [docs/oracle.md](docs/oracle.md): public cases in `tests/oracle/` with analytic (55) or FreeCAD-computed (21) expected values, run by CI on every PR; 75-sm-bracket-holes fails (#296). |
| Tests | Solver, profiles, kernel booleans/blends/measures, expressions, timeline, persistent naming, file formats and migrations, assemblies, sheet metal, engine end-to-end, hostile-input fuzz over every command and headless UI scenarios. `cargo xtask ci` reports the current passing counts. |
| Gates | `cargo xtask ci`: fmt, clippy -D warnings, tests, asset attribution, layering, wasm32 build — green |
@@ -20,8 +20,7 @@ The issue batch adds preservation of blind pockets in through cuts, associative
offsets and plastic face placements, XZ (+Y normal) with a v6 migration preserving older
designs, interactive angle placement, file-picker sketch imports, Home/recent controls,
toolbar overflow, and the remaining component-frame and assembly WIP work. The enclosure
acceptance scenarios now include board resizes; STEP reopening is automated. Inspection in
Fusion remains an external acceptance step. See [WIP reconciliation](docs/wip-reconciliation.md).
acceptance scenarios now include board resizes; STEP reopening is automated. See [WIP reconciliation](docs/wip-reconciliation.md).
In scope, in priority order:
1. SOLID and SKETCH (now).
@@ -38,8 +37,7 @@ In scope, in priority order:
5. A small PLASTIC subset for enclosures, after sheet metal: Boss, Rib, Web, Lip/Groove, Snap Fit.
Deferred until further notice: MESH, FORM (T-splines), SURFACE beyond what solids need, PCB / 3D
PCB / Package, Render, Animation, Simulation, Manufacture/CAM, Drawings. The parity report's
headline counts in-scope tabs only and lists the deferred ones separately.
PCB / Package, Render, Animation, Simulation, Manufacture/CAM, Drawings.
## Milestones
@@ -49,14 +47,13 @@ headline counts in-scope tabs only and lists the deferred ones separately.
| M1 | Sketch depth: command coverage implemented — projection/intersect/include as linked geometry (auto-project on faces, lost-reference warnings, break link), full SKETCH create/modify set (slots, polygons, tangent arcs/circles, ellipse, fit/control splines, conic, text, trim/extend/break, fillet/chamfer, offset, mirror, patterns, move/scale, blend curve, centerline), constraints incl. curvature and polygon with over-constraint refusal, driven/arc-length/linear-diameter dimensions, AutoConstrain, DXF/SVG insert, 3D sketch curves (Project To Surface, Intersection Curve, Isoparametric Curve, Spun Profile), exact free-form profiles (B-spline/NURBS edges, any spline degree, curves cut by crossings), sweeps and pipes along 3D sketch curves, canvases and decals, curvature combs. Exact free-form Extend and certified associative offsets now preserve geometry and IDs through edits, deletion and reopen. Occurrence-frame 3D wires now store explicit coordinate spaces and retain points and analytic fits through moves, refresh, undo and reopen. Remaining workflow repairs: mixed offset junctions, legacy natural-spline seams, and damaged legacy wire links lacking frame provenance | in progress | 4 |
| M2 | Robust modelling: coplanar booleans in the kernel, holes (placed on faces and on sketch points), threads (cosmetic, then modelled), patterns, mirror, shell, draft, split, construction geometry | in progress | 16 |
| M3 | General fillets and chamfers (curved edges, chains, vertex blends); saddle rolling-ball surfaces now use continuous seam sections and arc-length fitting with shared contact boundaries and bounded accuracy checks | in progress | 30 |
| M4 | Files: STEP import (done: all 29 Fusion STEP files — [docs/step-import.md](docs/step-import.md)), 3MF export and 3MF/STL import as mesh bodies (done), constant-section parametric mesh reconstruction, DXF sketches, OBJ import | in progress | 6 |
| M4 | Files: STEP import (done — [docs/step-import.md](docs/step-import.md)), 3MF export and 3MF/STL import as mesh bodies (done), DXF sketches, OBJ import | in progress | 6 |
| M4 | Files: STEP import (done — [docs/step-import.md](docs/step-import.md)), 3MF export and 3MF/STL import as mesh bodies (done), constant-section parametric mesh reconstruction, DXF sketches, OBJ import | in progress | 6 |
| M5 | Persistent naming of faces and edges (plan/adr/0002): faces named from their history (sketch curve sides, caps, revolve sections, primitive sides, blends, pattern/mirror copies; split pieces numbered), edges by their faces; fillets/chamfers, sketches on faces, shell/draft/offset/replace faces, hole placements, joint origins and face appearances resolve by name first and warn when the entity split or vanished: done. sheet metal edges by base sketch line and flange side, shell inner faces, sweep and loft roles: done. Left: kernel-reported face history (exact through coincident surfaces) | in progress | 20 |
| M6 | UI depth: selection feedback and origin (done), timeline editing (done: hover and selection highlight modifier faces, including fillets and chamfers; edit feature, history marker drag, reorder with dependency checks, suppress, rename, delete with dependents, re-resolved references; redefining selections refreshes persistent edge/face references while retaining feature identity and dimension names), right-docked dialogs (done), live previews for every feature dialog (done), keyboard-first commands with on-canvas value boxes and sketch inline dimensions (done), drag manipulators with automatic join/cut (done: extrude incl. two sides, fillet, shell, hole depth, move, pattern spacing, revolve rotator; taper handle open), dark theme (done), right-click menu with Repeat (done), measure tool (done), section analysis (done), selection filter (done), drag-solve of sketch points (done); appearance controls now preserve body/face/component targeting, named transparent looks, reuse/search and override removal; preferences | in progress | 6 |
| M7 | Sweep, loft (incl. to a point), rib and web (to next / depth), emboss (planar faces and exact radial emboss/deboss of bounded orthogonal profiles on complete exterior cylinders/sleeves), thread (cosmetic, and modelled M3–M20 outside and inside: the ISO profile screwed in as a faceted cut), coil (smooth B-spline helical walls), pipe, pattern on path, patterns of bodies and components, replace face (parallel), align, remove, feature copy/paste: done. Unique eligible cylindrical targets are inferred for new Emboss features. Left: general curved-face emboss and exact (unfaceted) modelled threads | in progress | 12 |
| M8 | Surface workspace | deferred | — |
| M9 | Components and assemblies: New Component / Create Components from Bodies, active component, per-component origin/bodies/sketches/timeline entries, occurrences with transforms, Copy/Paste vs Paste New, nested Browser tree with visibility and isolate; Ground, Move/Copy of occurrences, joints (rigid, revolute, slider, cylindrical, pin-slot, planar, ball) by joint origins with limits and Drive Joints, As-built Joint, Rigid Group, Contact Sets (driving and motion studies stop where bodies in a set would pass through each other), Motion Study (joint values keyed along a timeline, playback, export of occurrence positions as JSON/CSV), Exploded views (automatic or by hand, shown without changing placements); interference, per-component physical properties; STEP with assembly structure. Physical properties now measure material-aware component/occurrence placements, descendants and repeated instances, including pending moves and body reassignment offsets; contact geometry and automatic exploded centres respect those offsets. Groundwork done: component tree, occurrences with transforms (instances, Paste New), world placement, active component as authoring frame, ground, Capture/Revert Position, moving bodies and sketches. UI: ASSEMBLE panel dialogs for New Component, Joint (snaps on faces, edges, circles and vertices; animated motion preview; offsets, flip, limits), As-built Joint, Joint Origin, Rigid Group, Drive Joints (live slider), Motion Link and Interference (overlaps shown red); joints in the timeline and the Browser | in progress | 32 |
| M10 | Sheet metal: flange (base, edge, contour), hem, unfold/refold, convert, flat pattern + DXF, rules: done (oracle 67-76). PLASTIC enclosure subset: Boss, Rib, Web, Lip/Groove, Snap Fit, Rest, Plastic Rules (library, edit, assign; rule draft and clearance as feature defaults): done, no Fusion oracle (licence), tested against hand-computed geometry. UI: SHEET METAL and PLASTIC tabs in Fusion's layout with dialogs (live preview, Edit Feature, pre-selection) for Flange, Hem, Unfold/Refold, Convert, Sheet Metal Rules, Create Flat Pattern (flat view with bend lines, bend table CSV/JSON and DXF export with exact circle/arc/line cutouts), Boss, Lip/Groove, Snap Fit, Rest, Manage and Assign Plastic Rules; Fold (bend along a sketch line) | in progress | 36 |
| M10 | Sheet metal: flange (base, edge, contour), hem, unfold/refold, convert, flat pattern + DXF, rules: done. PLASTIC enclosure subset: Boss, Rib, Web, Lip/Groove, Snap Fit, Rest, Plastic Rules (library, edit, assign; rule draft and clearance as feature defaults): done, tested against hand-computed geometry. UI: SHEET METAL and PLASTIC tabs in Fusion's layout with dialogs (live preview, Edit Feature, pre-selection) for Flange, Hem, Unfold/Refold, Convert, Sheet Metal Rules, Create Flat Pattern (flat view with bend lines, bend table CSV/JSON and DXF export with exact circle/arc/line cutouts), Boss, Lip/Groove, Snap Fit, Rest, Manage and Assign Plastic Rules; Fold (bend along a sketch line) | in progress | 36 |
| M11 | 2D drawings | deferred | — |
| M12 | Release: cross-platform packages, verification and deliberate publication implemented; original current-UI demo refreshed. Trusted distribution signing and broader performance work remain | in progress | 16 |
| M14 | Configurations: a table of rows (parameter expressions and feature suppressions per row) switched with config.activate (undoable, all or nothing), kept through parameter renames and feature deletes (config.configure, config.table, config.column/row/activate). Per-row body materials and appearances (library looks, custom colour/opacity and clearing overrides), undoable activation and save/reopen: done. Ordered typed configuration rules, atomic validation and structured rule editing: done. Component appearance and certified semantic face style columns, atomic preview/apply and independent-copy remapping: done. Exact constructed sketch-side and immutable imported-face lineage now preserve legacy names and reject retargeting. Left: ambiguous shifted/two-sided caps | in progress | 4 |
@@ -311,7 +308,7 @@ headline counts in-scope tabs only and lists the deferred ones separately.
- Rolling-ball fillet accuracy: independent offset-cylinder tee references check surface
distance, actual trimmed tessellation, supporting-cylinder contacts and tangency at two
scales. The measured trimmed-part error is below 0.0001 mm; this is an analytic geometry
check, not a new Fusion oracle result. Under-resolved fits return an error.
check. Under-resolved fits return an error.
- Contact driving checks the trajectory between clear endpoints, including linked joints,
playback and sparse motion exports. Checks use bounded tessellation samples, not exact
continuous collision detection; local thin walls and small details remain limitations.
+2 -2
View File
@@ -11,7 +11,7 @@ use crate::params::{bad, bool_, expr, req_expr, str_, string_list, vec3};
use crate::{Result, Session};
pub static COMMANDS: &[CommandSpec] = &[
CommandSpec::new("SurfaceSculpt", "Boundary Fill", boundary_fill).at("SOLID", "CREATE").icon("boundary_fill").params(
CommandSpec::new("solid.boundary_fill", "Boundary Fill", boundary_fill).at("SOLID", "CREATE").icon("boundary_fill").params(
"tools: [bodies]; cells: [[x,y,z] a point inside each cell to fill (a cell: inside some tools, outside the rest)]; operation?: new|join|cut|intersect; remove_tools?: bool",
),
CommandSpec::new("solid.coil", "Coil", coil).at("SOLID", "CREATE").icon("coil").params(
@@ -422,7 +422,7 @@ pub(super) fn snap_point(s: &Session, kind: &str, at: Vec3) -> Option<Vec3> {
}
fn boundary_fill(s: &mut Session, p: &Value) -> Result<Value> {
let cmd = "SurfaceSculpt";
let cmd = "solid.boundary_fill";
let tools = string_list(p, "tools");
let st = s.model.state();
if tools.is_empty() || tools.len() > 64 || tools.iter().any(|t| st.body(t).is_none()) {
+1 -3
View File
@@ -1,6 +1,6 @@
//! The command registry. Ids are SolveCraft's own dotted ids (`solid.extrude`,
//! `sketch.rectangle.two_point`); the toolbar placement (`tab`, `panel`) follows the familiar
//! Design workspace layout. Ids used before the rename still resolve (`legacy_ids`).
//! Design workspace layout.
/// The params-doc note of every command that adds sketch geometry (see `sketch::created`).
macro_rules! created_doc {
@@ -180,7 +180,5 @@ pub fn command_specs() -> Vec<&'static CommandSpec> {
pub fn find_command(id: &str) -> Option<&'static CommandSpec> {
let all = command_specs();
// Ids from before the rename still find their command.
let id = crate::legacy_ids::current_id(id);
all.iter().find(|c| c.id == id).or_else(|| all.iter().find(|c| c.id.eq_ignore_ascii_case(id))).copied()
}
+2 -2
View File
@@ -184,7 +184,7 @@ fn base(r: &mut Rng) -> Step {
("sketch.line", json!({"points": pts})),
("sketch.arc.three_point", json!({"start": [0, h], "end": [0, 0], "through": [-bulge, h / 2.0]})),
("sketch.finish", json!({})),
("Extrude", json!({"distance": d})),
("solid.extrude", json!({"distance": d})),
],
)
}
@@ -198,7 +198,7 @@ fn base(r: &mut Rng) -> Step {
("sketch.create", json!({"plane": "XZ"})),
("sketch.rectangle.two_point", json!({"p0": [r0, 0], "p1": [r1, h]})),
("sketch.finish", json!({})),
("Revolve", json!({"axis": "Z", "angle": angle})),
("solid.revolve", json!({"axis": "Z", "angle": angle})),
],
)
}
-236
View File
@@ -1,236 +0,0 @@
//! Legacy migration: the command ids SolveCraft used before 2026-10-09, when many commands
//! carried the id of the matching command in another CAD program, and the dotted ids that
//! replaced them. This is the one place the old ids live. Old scripts, recipes, control-channel
//! calls, saved shortcuts and toolbar layouts keep working: `find_command` and the preference
//! loaders map an old id through `current_id`. `solvecraft-tools/rename_ids.sh` converts a
//! worktree with this same table.
/// (old id, current id).
pub const LEGACY_IDS: &[(&str, &str)] = &[
("AsBuiltPositionsCmd", "component.revert_position"),
("FusionCreateComponentsFromBodiesCommand", "component.from_bodies"),
("FusionCreateNewComponentCommand", "component.create"),
("SnapshotCmd", "component.capture_position"),
("FusionShowDesignConfigPanelCmd", "config.table"),
("FusionStartDesignConfigModeCmd", "config.configure"),
("FusionComputeAllCommand", "timeline.compute_all"),
("FusionDeleteCommand", "timeline.delete"),
("FusionRenameTimelineEntryCommand", "timeline.rename"),
("RedoCommand", "edit.redo"),
("UndoCommand", "edit.undo"),
("timeline.rollTo", "timeline.roll_to"),
("AlignCmd", "solid.align"),
("EmbossCmd", "solid.emboss"),
("FusionReplaceFaceCommand", "solid.replace_face"),
("FusionRibCommand", "solid.rib"),
("FusionWebCommand", "solid.web"),
("PrimitiveCoil", "solid.coil"),
("SoftDeleteCommand", "solid.remove"),
("ConstructionPlaneAtAngleCommand", "construct.plane.at_angle"),
("ConstructionPlaneOffsetFromPlaneCommand", "construct.plane.offset"),
("Extrude", "solid.extrude"),
("FusionChamferCommand", "solid.chamfer"),
("FusionCombineCommand", "solid.combine"),
("FusionDraftCommand", "solid.draft"),
("FusionFilletEdgesCommand", "solid.fillet"),
("FusionHoleCommand", "solid.hole"),
("FusionMoveCommand", "solid.move"),
("FusionOffsetFacesCommand", "solid.offset_face"),
("FusionPressPullCommand", "solid.press_pull"),
("FusionShellBodyCommand", "solid.shell"),
("FusionSplitBodyCommand", "solid.split_body"),
("FusionThreadCommand", "solid.thread"),
("MirrorCommand", "solid.mirror"),
("ModifyScale", "solid.scale"),
("PatternCircular", "solid.pattern.circular"),
("PatternOnPath", "solid.pattern.path"),
("PatternRectangular", "solid.pattern.rectangular"),
("PrimitiveBox", "solid.box"),
("PrimitiveCylinder", "solid.cylinder"),
("PrimitivePipe", "solid.pipe"),
("PrimitiveSphere", "solid.sphere"),
("PrimitiveTorus", "solid.torus"),
("Revolve", "solid.revolve"),
("SolidLoft", "solid.loft"),
("StockModelCommand", "solid.bounding_solid"),
("Sweep", "solid.sweep"),
("ExportCommand", "file.export"),
("FusionImportCommandFromToolbar", "file.insert_step"),
("FusionSaveAsSTLCommand", "file.save_mesh"),
("NewDocumentCommand", "file.new"),
("ParaMeshInsertAlignCommand", "file.insert_mesh"),
("SaveDocumentAsCommand", "file.save_as"),
("SaveDocumentCommand", "file.save"),
("AppearanceCommand", "appearance.assign"),
("MeasureCommand", "inspect.measure"),
("PhysicalMaterialCommand", "material.assign"),
("FusionMotionRelationshipCommand", "joint.motion_link"),
("FusionMoveJointsCommand", "joint.drive"),
("InterferenceCheckCommand", "inspect.interference"),
("JointAsBuiltCmd", "joint.as_built"),
("JointAssembleCmdNew", "joint.create"),
("JointOrigin", "joint.origin"),
("RigidGroupCmd", "joint.rigid_group"),
("ContactSetCmd", "contact.create"),
("DisableAllContactCmd", "contact.disable_all"),
("EnableAllContactCmd", "contact.enable_all"),
("EnableContactSetsCmd", "contact.enable_sets"),
("FusionMotionStudyCommand", "motion.study"),
("ChangeParameterCommand", "parameters.change"),
("FusionFastenersCommand", "parts.fastener"),
("FusionAssignPlasticRuleCommand", "plastic.assign_rule"),
("FusionBossCommand", "plastic.boss"),
("FusionLipCommand", "plastic.lip"),
("FusionManagePlasticRuleCommand", "plastic.manage_rules"),
("FusionRestCommand", "plastic.rest"),
("FusionSnapFitCommand", "plastic.snap_fit"),
("FusionHalfSectionViewCommand", "inspect.section"),
("ConvertToSheetMetalCmd", "sheet.convert"),
("FusionSheetMetalFlangeCommand", "sheet.flange"),
("FusionSheetMetalFlatPatternCmd", "sheet.flat_pattern"),
("FusionSheetMetalHemFlangeCommand", "sheet.hem"),
("FusionSheetMetalRulesCommand", "sheet.manage_rules"),
("FusionSheetmetalUnfoldCommand", "sheet.unfold"),
("SheetMetalFoldCmd", "sheet.fold"),
("FusionAddCanvasCommand", "canvas.insert"),
("FusionAddEditDecalCommand", "canvas.decal"),
("ConstraintSmooth", "sketch.constraint.curvature"),
("SketchAutoConstrainAndFinish", "sketch.finish_auto_constrain"),
("SketchAutoConstraintAndDimCmd", "sketch.auto_constrain"),
("SketchAutoConstraintAndDimFromDatumCmd", "sketch.auto_constrain_from_datum"),
("SketchConstrainer", "sketch.constrainer"),
("SketchPolygonConstraintCmd", "sketch.constraint.polygon"),
("ArcTangent", "sketch.arc.tangent"),
("BlendG1CurveSketchCmd", "sketch.blend_curve"),
("CircleElipse", "sketch.ellipse"),
("CircleTanTanRadius", "sketch.circle.two_tangent"),
("CircleThreeTangent", "sketch.circle.three_tangent"),
("ConicCurveCmd", "sketch.conic"),
("DrawCVMSpline3D", "sketch.spline.control_point"),
("DrawCVMSpline5D", "sketch.spline.control_point_5"),
("DrawSpline", "sketch.spline.fit_point"),
("MTextCmd", "sketch.text"),
("ShapeArcSlotCenterTwoPoint", "sketch.slot.arc_center"),
("ShapeArcSlotThreePoint", "sketch.slot.arc_three_point"),
("ShapeSlotCenterPoint", "sketch.slot.center_point"),
("SketchMidpointLine", "sketch.line.midpoint"),
("ImportDxfFileCommand", "sketch.insert_dxf"),
("SketchImportSVG", "sketch.insert_svg"),
("FusionCenterOfMassCommand", "inspect.center_of_mass"),
("FusionCurvatureCombAnalysisCommand", "inspect.curvature_comb"),
("FusionIsoCurveAnalysisCommand", "inspect.isocurve"),
("FusionMinimumRadiusAnalysisCommand", "inspect.minimum_radius"),
("BreakSketchCmd", "sketch.break"),
("ChamferSketchDistanceAngle", "sketch.chamfer.distance_angle"),
("ChamferSketchDistanceDistance", "sketch.chamfer.two_distance"),
("ChamferSketchEqualDistance", "sketch.chamfer.equal_distance"),
("CircularSketchPatternCommand", "sketch.pattern.circular"),
("ExtendSketchCmd", "sketch.extend"),
("FilletSketchCmd", "sketch.fillet"),
("MirrorSketchCommand", "sketch.mirror"),
("Offset", "sketch.offset"),
("RectangularSketchPatternCommand", "sketch.pattern.rectangular"),
("SketchScaleCmd", "sketch.scale"),
("TrimSketchCmd", "sketch.trim"),
("FitCurvesToSectionCommand", "sketch.fit_curves_to_section"),
("Include3DGeometry", "sketch.include_3d"),
("IntersectCmd", "sketch.intersect"),
("IntersectionCurve", "sketch.intersection_curve"),
("ProjectNewCmd", "sketch.project"),
("ProjectToSurface", "sketch.project_to_surface"),
("SketchIsoparametricCurve", "sketch.isoparametric_curve"),
("SpunProfileCmd", "sketch.spun_profile"),
("ArcCenterTwoPoint", "sketch.arc.center_point"),
("ArcThreePoint", "sketch.arc.three_point"),
("CircleCenterRadius", "sketch.circle.center"),
("CircleThreePoint", "sketch.circle.three_point"),
("CircleTwoPoint", "sketch.circle.two_point"),
("ConstraintCoincident", "sketch.constraint.coincident"),
("ConstraintCollinear", "sketch.constraint.collinear"),
("ConstraintConcentric", "sketch.constraint.concentric"),
("ConstraintEqual", "sketch.constraint.equal"),
("ConstraintFix", "sketch.constraint.fix"),
("ConstraintHorizontalVertical", "sketch.constraint.horizontal_vertical"),
("ConstraintMidPoint", "sketch.constraint.midpoint"),
("ConstraintParallel", "sketch.constraint.parallel"),
("ConstraintPerpendicular", "sketch.constraint.perpendicular"),
("ConstraintSymmetry", "sketch.constraint.symmetry"),
("ConstraintTangent", "sketch.constraint.tangent"),
("DrawPoint", "sketch.point"),
("DrawPolyline", "sketch.line"),
("ShapePolygonCircumscribed", "sketch.polygon.circumscribed"),
("ShapePolygonEdge", "sketch.polygon.edge"),
("ShapePolygonInscribed", "sketch.polygon.inscribed"),
("ShapeRectangleCenter", "sketch.rectangle.center"),
("ShapeRectangleThreePoint", "sketch.rectangle.three_point"),
("ShapeRectangleTwoPoint", "sketch.rectangle.two_point"),
("ShapeSlotCenterToCenter", "sketch.slot.center_to_center"),
("ShapeSlotOverall", "sketch.slot.overall"),
("SketchActivate", "sketch.edit"),
("SketchCreate", "sketch.create"),
("SketchDimension", "sketch.dimension"),
("SketchStop", "sketch.finish"),
("FusionAccessibilityAnalysisCommand", "inspect.accessibility"),
("FusionCurvatureMapAnalysisCommand", "inspect.curvature_map"),
("FusionDraftAnalysisCommand", "inspect.draft"),
("FusionEnvironmentMapAnalysisCommand", "inspect.environment_map"),
("FusionZebraAnalysisCommand", "inspect.zebra"),
("FusionExtendCommand", "surface.extend"),
("FusionSurfacePatchCommand", "surface.patch"),
("FusionSurfaceStitchCommand", "surface.stitch"),
("FusionSurfaceThickenCommand", "surface.thicken"),
("FusionSurfaceTrimCommand", "surface.trim"),
("FusionSplitFaceCommand", "solid.split_face"),
("ConstructionAxisThroughCylinderCommand", "construct.axis.through_cylinder"),
("ConstructionAxisNormalToFaceCommand", "construct.axis.normal_to_face"),
("ConstructionAxisFromTwoPlanesCommand", "construct.axis.two_planes"),
("ConstructionAxisThroughTwoPointsCommand", "construct.axis.two_points"),
("ConstructionAxisThroughEdgeCommand", "construct.axis.edge"),
("ConstructionPointFromPointCommand", "construct.point.vertex"),
("ConstructionPointThroughTwoEdgesCommand", "construct.point.two_edges"),
("ConstructionPointFromThreePlanesCommand", "construct.point.three_planes"),
("ConstructionPointFromCircleOrSphereCommand", "construct.point.center"),
("ConstructionPointAtEdgeAndPlaneCommand", "construct.point.edge_plane"),
("ConstructionPointAlongPathCommand", "construct.point.along_path"),
("ConstructionMidPlaneCommand", "construct.plane.midplane"),
("ConstructionPlaneFromTwoEdgesCommand", "construct.plane.two_edges"),
("ConstructionPlaneFromThreePointsCommand", "construct.plane.three_points"),
("ConstructionTangentPlaneCommand", "construct.plane.tangent"),
("ConstructionPlaneAlongPathCommand", "construct.plane.along_path"),
];
/// The current id for a command id that may be a legacy one (unchanged otherwise).
pub fn current_id(id: &str) -> &str {
LEGACY_IDS.iter().find(|(old, _)| old.eq_ignore_ascii_case(id)).map(|(_, new)| *new).unwrap_or(id)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_legacy_id_names_a_command() {
let unknown: Vec<&str> =
LEGACY_IDS.iter().filter(|(_, new)| crate::find_command(new).is_none_or(|c| c.id != *new)).map(|(_, new)| *new).collect();
// The construction set and Split Face are on a branch not yet merged when the table was made.
let pending = ["solid.split_face"];
let unknown: Vec<&str> = unknown
.into_iter()
.filter(|n| {
!pending.contains(n)
&& !n.starts_with("construct.axis")
&& !n.starts_with("construct.point")
&& ![
"construct.plane.midplane",
"construct.plane.two_edges",
"construct.plane.three_points",
"construct.plane.tangent",
"construct.plane.along_path",
]
.contains(n)
})
.collect();
assert!(unknown.is_empty(), "{unknown:?}");
assert_eq!(crate::find_command("SketchCreate").map(|c| c.id), Some("sketch.create"));
}
}
-1
View File
@@ -10,7 +10,6 @@
pub mod cmd;
pub mod frames;
pub mod fuzz;
pub mod legacy_ids;
pub mod licences;
pub mod occurrences;
pub mod params;
+15 -4
View File
@@ -512,11 +512,22 @@ fn registry_is_consistent() {
let n = ids.len();
ids.dedup();
assert_eq!(ids.len(), n, "duplicate command ids");
assert!(find_command("extrude").is_some(), "case-insensitive lookup");
assert_eq!(find_command("Solid.Extrude").map(|c| c.id), Some("solid.extrude"), "case-insensitive lookup");
let s = Session::default();
assert!(!find_command("sketch.line").unwrap().info(&s).enabled);
}
/// Only SolidCraft's own dotted ids name commands; other ids are unknown commands.
#[test]
fn only_own_ids_name_commands() {
for old in ["Extrude", "SketchCreate", "FusionFilletEdgesCommand"] {
assert!(find_command(old).is_none(), "{old}");
let mut s = Session::default();
let err = s.execute(old, &serde_json::json!({})).unwrap_err();
assert!(matches!(err, crate::EngineError::UnknownCommand(_)), "{old}: {err}");
}
}
#[test]
fn sample_design_builds() {
let mut s = Session::default();
@@ -2336,15 +2347,15 @@ fn boundary_fill_cells() {
let mut s = Session::default();
run(&mut s, "solid.box", json!({"length": 20, "width": 20, "height": 20, "body_name": "A"}));
run(&mut s, "solid.box", json!({"corner": [10, 0, 0], "length": 20, "width": 20, "height": 20, "body_name": "B"}));
let r = run(&mut s, "SurfaceSculpt", json!({"tools": ["A", "B"], "cells": [[15, 10, 10]], "remove_tools": true}));
let r = run(&mut s, "solid.boundary_fill", json!({"tools": ["A", "B"], "cells": [[15, 10, 10]], "remove_tools": true}));
let m = run(&mut s, "inspect.measure", json!({}));
assert_eq!(m["body_count"], 1, "{r} {m}");
assert!(rel(m["total"]["volume_mm3"].as_f64().unwrap_or(0.0), 10.0 * 20.0 * 20.0) < 1e-9);
run(&mut s, "edit.undo", json!({}));
run(&mut s, "SurfaceSculpt", json!({"tools": ["A", "B"], "cells": [[5, 10, 10], [25, 10, 10]], "remove_tools": true}));
run(&mut s, "solid.boundary_fill", json!({"tools": ["A", "B"], "cells": [[5, 10, 10], [25, 10, 10]], "remove_tools": true}));
let m = run(&mut s, "inspect.measure", json!({}));
assert!(rel(m["total"]["volume_mm3"].as_f64().unwrap_or(0.0), 2.0 * 10.0 * 20.0 * 20.0) < 1e-9, "{m}");
assert!(s.execute("SurfaceSculpt", &json!({"tools": ["A"], "cells": [[100, 100, 100]]})).is_err());
assert!(s.execute("solid.boundary_fill", &json!({"tools": ["A"], "cells": [[100, 100, 100]]})).is_err());
}
/// Rectangles name their sides and corners, so they can be dimensioned without inspecting the
+3 -3
View File
@@ -366,7 +366,7 @@ impl Dialog {
Kind::ReplaceFace,
vec![SelInput::new("Faces", PLANAR_FACES, true), SelInput::new("Target", PLANES | PLANAR_FACES, false)],
),
"SurfaceSculpt" => {
"solid.boundary_fill" => {
Dialog::new(Kind::BoundaryFill { operation: 0, cells: Vec::new(), of: Vec::new() }, vec![SelInput::new("Tools", BODIES, true)])
}
"solid.align" => Dialog::new(
@@ -2848,7 +2848,7 @@ fn dialog_commands(app: &SolveApp, d: &Dialog) -> Result<Vec<(String, Value)>, S
if picked.is_empty() {
return Err("tick the cells to fill".into());
}
("SurfaceSculpt", json!({"tools": body_names(0), "cells": picked, "operation": OPS.get(*operation).copied().unwrap_or("new")}))
("solid.boundary_fill", json!({"tools": body_names(0), "cells": picked, "operation": OPS.get(*operation).copied().unwrap_or("new")}))
}
Kind::Combine { operation, keep_tools } => {
need(0, "the target body")?;
@@ -3383,7 +3383,7 @@ pub fn for_feature(app: &SolveApp, id: u64, marker: Option<usize>) -> Option<Dia
d
}
FeatureKind::BoundaryFill { tools, cells, operation, remove_tools } => {
let mut d = start("SurfaceSculpt")?;
let mut d = start("solid.boundary_fill")?;
// The cells again, ticked where a stored cell point lies in the same cell.
let before = s.model.state_before(f.id);
let found = fill_cells(&before, tools);
+1 -6
View File
@@ -38,15 +38,10 @@ impl Keymap {
}
pub fn load(&mut self, v: &Value) {
self.custom =
v.as_object().map(|o| o.iter().take(2000).filter_map(|(k, v)| Some((current(k), v.as_str()?.to_string()))).collect()).unwrap_or_default();
v.as_object().map(|o| o.iter().take(2000).filter_map(|(k, v)| Some((k.clone(), v.as_str()?.to_string()))).collect()).unwrap_or_default();
}
}
/// Saved before the command ids were renamed: the current id.
fn current(id: &str) -> String {
solvecraft_engine::legacy_ids::current_id(id).to_string()
}
/// A key press as a shortcut name: `E`, `Shift+E`, `Ctrl+Alt+K`, `F5`, `Delete`.
pub fn key_name(key: egui::Key, mods: egui::Modifiers) -> String {
let mut s = String::new();
+2 -2
View File
@@ -594,8 +594,8 @@ fn toolbar_pins_removes_reorders_and_keeps_its_layout() {
tc::reorder(&mut app, "SOLID", extra, "MODIFY", None);
assert!(!ids(&app, "CREATE").contains(&extra) && ids(&app, "MODIFY").last() == Some(&extra));
// Pin to Shortcuts goes to the S box's favourites.
act(&mut app, &Target::ToolbarCommand { id: "Extrude".into() }, "Pin to Shortcuts");
assert!(app.sbox.pinned.iter().any(|p| p == "Extrude"));
act(&mut app, &Target::ToolbarCommand { id: "solid.extrude".into() }, "Pin to Shortcuts");
assert!(app.sbox.pinned.iter().any(|p| p == "solid.extrude"));
// Kept between runs, and exported and imported with the shortcuts.
let mut other = sample_app();
other.load_prefs(&app.prefs());
+1 -1
View File
@@ -543,7 +543,7 @@ fn boundary_fill_finds_the_cells_and_fills_the_ticked_ones() {
{"command": "solid.box", "params": {"length": 20, "width": 20, "height": 20}},
{"command": "solid.box", "params": {"length": 20, "width": 20, "height": 20, "corner": [10, 10, 0], "operation": "new"}}
]));
let mut d = start(&mut app, vec![], "SurfaceSculpt");
let mut d = start(&mut app, vec![], "solid.boundary_fill");
d.inputs[0].items = vec![Sel::Body { name: "Body1".into() }, Sel::Body { name: "Body2".into() }];
app.dialog = Some(d);
// The dialog finds the cells on its next frame.
+1 -4
View File
@@ -34,10 +34,7 @@ impl ShortcutBox {
}
pub fn load(&mut self, v: &Value) {
let list = |k: &str| -> Vec<String> {
v.get(k)
.and_then(Value::as_array)
.map(|a| a.iter().take(64).filter_map(|x| x.as_str().map(|id| solvecraft_engine::legacy_ids::current_id(id).to_string())).collect())
.unwrap_or_default()
v.get(k).and_then(Value::as_array).map(|a| a.iter().take(64).filter_map(|x| x.as_str().map(str::to_string)).collect()).unwrap_or_default()
};
self.recent = list("recent");
self.pinned = list("pinned");
+1 -1
View File
@@ -26,7 +26,7 @@
- [Test harnesses](dev/testing.md)
- [Control protocol](dev/control-protocol.md)
- [Reference tests](dev/oracle.md)
- [Command parity](dev/parity.md)
- [Features](dev/features.md)
- [STEP import](dev/step-import.md)
# Reference
+1 -1
View File
@@ -7,7 +7,7 @@ SolidCraft is a Cargo workspace in layers. A crate only depends on crates in low
The web app, `apps/solvecraft-web`, is the desktop front end compiled to wasm with
[trunk](https://trunkrs.dev). `xtask` holds the repository's own tooling: `cargo xtask ci`,
`layers`, `assets`, `oracle`, `parity` and `book`.
`layers`, `assets`, `features`, `oracle` and `book`.
A few rules follow from the layering:
+2 -2
View File
@@ -24,8 +24,8 @@ before it runs, and a failing command leaves the document unchanged. Feature com
feature to the timeline and let the document evaluate it; they validate their inputs first
(units, ranges, references) and return `BadParams` instead of building a broken feature.
Ids used before the 2026-10 rename still resolve through `crates/engine/src/legacy_ids.rs`, so
old scripts, recipes, saved shortcuts and toolbar layouts keep working.
Only the registry's own dotted ids name commands (matched ignoring case); any other id fails
with `unknown command`.
## Adding a command
+1
View File
@@ -0,0 +1 @@
{{#include ../../../features.md}}
-1
View File
@@ -1 +0,0 @@
{{#include ../../../parity.md}}
+1 -1
View File
@@ -10,4 +10,4 @@ The PLASTIC tab has a small enclosure subset:
clearance per material, used as the features' defaults.
Rib and web (on the SOLID tab) complete the set. These features are checked against
hand-computed geometry rather than a Fusion oracle.
hand-computed geometry.
+2 -2
View File
@@ -11,8 +11,8 @@ The SHEET METAL tab builds parts from a sheet of constant thickness under a **sh
- **Create Flat Pattern** (`sheet.flat_pattern`) shows the flat part with its bend lines and a
bend table, and exports it as DXF or a bend-table CSV through the save picker.
Bends follow the rule's K-factor, so flat lengths match what a press brake will make. The
oracle checks these against parts built in Fusion.
Bends follow the rule's K-factor, so flat lengths match what a press brake will make. Tests
check flat lengths against hand-computed bend allowances.
For a shop drawing or spreadsheet, `sheet.export_bend_table` returns CSV by default; choose
`format: "json"` for structured data. It includes the sheet rule, thickness, bend angles,
+6 -4
View File
@@ -21,8 +21,8 @@ also script, test or hand to an agent.
SolidCraft is early. Sketching, solid modelling, parameters, components with joints, sheet metal
and a plastic-enclosure subset work; surfaces, drawings, CAM and simulation are deferred. The
[roadmap](https://github.com/bherbruck/solidcraft/blob/main/ROADMAP.md) has the details, and
[command parity](dev/parity.md) and the [reference tests](dev/oracle.md) measure how far along it
is.
the [feature list](dev/features.md) lists every command by area, and the
[reference tests](dev/oracle.md) check modelling results against analytic and FreeCAD values.
Existing `.solvecraft` designs and `solvecraft-cli` commands keep their names and behavior.
@@ -30,5 +30,7 @@ This book has two halves: the **user guide** for people modelling with SolidCraf
**developer guide** for people working on it. The [command reference](reference/commands.md) is
generated from the code on every build.
SolidCraft is licensed MIT OR Apache-2.0. It is a clean-room implementation and is not affiliated
with Autodesk; Fusion is a trademark of Autodesk, Inc.
SolidCraft is licensed MIT OR Apache-2.0. It is independent: behaviour is designed from public
documentation, general CAD conventions and user feedback, and reference tests use analytic
values and open-source tools. SolidCraft is not affiliated with Autodesk; Fusion is a trademark
of Autodesk, Inc.
+487
View File
@@ -0,0 +1,487 @@
# Features
SolidCraft's commands by area, generated by `cargo xtask features` from the command registry (`solvecraft-cli commands`). **314 commands.** Every command runs the same way from the toolbar, a script, `solvecraft-cli exec <id> '<json>'`, the control channel and MCP; parameters are in the [command reference](book/src/reference/commands.md) (`cargo xtask book`). Status and plans: [ROADMAP](../ROADMAP.md).
## Sketch (97)
| Command | Id | Toolbar |
|---|---|---|
| Create Sketch | `sketch.create` | SOLID › CREATE |
| Edit Sketch | `sketch.edit` | – |
| Finish Sketch | `sketch.finish` | SKETCH › FINISH SKETCH |
| Line (L) | `sketch.line` | SKETCH › CREATE |
| Draw Dimensioned Sketch Geometry | `sketch.draw.dimensioned` | – |
| 2-Point Rectangle (R) | `sketch.rectangle.two_point` | SKETCH › CREATE |
| 3-Point Rectangle | `sketch.rectangle.three_point` | SKETCH › CREATE |
| Center Rectangle | `sketch.rectangle.center` | SKETCH › CREATE |
| Center Diameter Circle (C) | `sketch.circle.center` | SKETCH › CREATE |
| 2-Point Circle | `sketch.circle.two_point` | SKETCH › CREATE |
| 3-Point Circle | `sketch.circle.three_point` | SKETCH › CREATE |
| 3-Point Arc | `sketch.arc.three_point` | SKETCH › CREATE |
| Center Point Arc | `sketch.arc.center_point` | SKETCH › CREATE |
| Inscribed Polygon | `sketch.polygon.inscribed` | SKETCH › CREATE |
| Circumscribed Polygon | `sketch.polygon.circumscribed` | SKETCH › CREATE |
| Edge Polygon | `sketch.polygon.edge` | SKETCH › CREATE |
| Center to Center Slot | `sketch.slot.center_to_center` | SKETCH › CREATE |
| Overall Slot | `sketch.slot.overall` | SKETCH › CREATE |
| Point | `sketch.point` | SKETCH › CREATE |
| Sketch Dimension (D) | `sketch.dimension` | SKETCH › CREATE |
| Horizontal/Vertical | `sketch.constraint.horizontal_vertical` | SKETCH › CONSTRAINTS |
| Coincident | `sketch.constraint.coincident` | SKETCH › CONSTRAINTS |
| Tangent | `sketch.constraint.tangent` | SKETCH › CONSTRAINTS |
| Equal | `sketch.constraint.equal` | SKETCH › CONSTRAINTS |
| Parallel | `sketch.constraint.parallel` | SKETCH › CONSTRAINTS |
| Perpendicular | `sketch.constraint.perpendicular` | SKETCH › CONSTRAINTS |
| Fix/UnFix | `sketch.constraint.fix` | SKETCH › CONSTRAINTS |
| MidPoint | `sketch.constraint.midpoint` | SKETCH › CONSTRAINTS |
| Concentric | `sketch.constraint.concentric` | SKETCH › CONSTRAINTS |
| Collinear | `sketch.constraint.collinear` | SKETCH › CONSTRAINTS |
| Symmetry | `sketch.constraint.symmetry` | SKETCH › CONSTRAINTS |
| Normal/Construction (X) | `sketch.construction` | SKETCH › CREATE |
| Delete Sketch Entities | `sketch.delete` | – |
| Drag Sketch Point | `sketch.move_point` | – |
| Drag Sketch Geometry | `sketch.drag` | – |
| Move Dimension Text | `sketch.dimension_text` | – |
| Sketch Palette Options | `sketch.options` | – |
| Chain | `sketch.chain` | – |
| Solve Sketch | `sketch.solve` | – |
| Midpoint Line | `sketch.line.midpoint` | SKETCH › CREATE |
| Tangent Arc | `sketch.arc.tangent` | SKETCH › CREATE |
| 2-Tangent Circle | `sketch.circle.two_tangent` | SKETCH › CREATE |
| 3-Tangent Circle | `sketch.circle.three_tangent` | SKETCH › CREATE |
| Center Point Slot | `sketch.slot.center_point` | SKETCH › CREATE |
| Three Point Arc Slot | `sketch.slot.arc_three_point` | SKETCH › CREATE |
| Center Point Arc Slot | `sketch.slot.arc_center` | SKETCH › CREATE |
| Ellipse | `sketch.ellipse` | SKETCH › CREATE |
| Fit Point Spline | `sketch.spline.fit_point` | SKETCH › CREATE |
| Control Point Spline | `sketch.spline.control_point` | SKETCH › CREATE |
| Control Point Spline (Degree 5) | `sketch.spline.control_point_5` | SKETCH › CREATE |
| Conic Curve | `sketch.conic` | SKETCH › CREATE |
| Blend Curve | `sketch.blend_curve` | SKETCH › MODIFY |
| Centerline | `sketch.centerline` | – |
| Text | `sketch.text` | SKETCH › CREATE |
| Edit Text | `sketch.edit_text` | – |
| Curvature | `sketch.constraint.curvature` | SKETCH › CONSTRAINTS |
| Polygon | `sketch.constraint.polygon` | SKETCH › CONSTRAINTS |
| AutoConstrain | `sketch.auto_constrain` | SKETCH › CONSTRAINTS |
| AutoConstrain from datum | `sketch.auto_constrain_from_datum` | SKETCH › CONSTRAINTS |
| Finish with AutoConstrain | `sketch.finish_auto_constrain` | SKETCH › FINISH SKETCH |
| Sketch Constrainer | `sketch.constrainer` | SKETCH › CREATE |
| Toggle Driven Dimension | `sketch.toggle_driven` | – |
| Constraint Glyphs | `sketch.glyphs` | – |
| Snap Inference | `sketch.snap` | – |
| Insert DXF | `sketch.insert_dxf` | SKETCH › INSERT |
| Insert SVG | `sketch.insert_svg` | SKETCH › INSERT |
| Save As DXF | `sketch.export_dxf` | – |
| 3D Line | `sketch.line3d` | – |
| 3D Spline | `sketch.spline3d` | – |
| 3D Point | `sketch.point3d` | – |
| Move 3D Point | `sketch.move3d` | – |
| Fillet | `sketch.fillet` | SKETCH › MODIFY |
| Equal Distance Chamfer | `sketch.chamfer.equal_distance` | SKETCH › MODIFY |
| Distance and Angle Chamfer | `sketch.chamfer.distance_angle` | SKETCH › MODIFY |
| Two Distance Chamfer | `sketch.chamfer.two_distance` | SKETCH › MODIFY |
| Offset (O) | `sketch.offset` | SKETCH › MODIFY |
| Break Offset Association | `sketch.offset.break` | – |
| Trim (T) | `sketch.trim` | SKETCH › MODIFY |
| Extend | `sketch.extend` | SKETCH › MODIFY |
| Break | `sketch.break` | SKETCH › MODIFY |
| Sketch Scale | `sketch.scale` | SKETCH › MODIFY |
| Move/Copy Sketch Entities | `sketch.move` | – |
| Mirror | `sketch.mirror` | SKETCH › CREATE |
| Circular Pattern | `sketch.pattern.circular` | SKETCH › CREATE |
| Rectangular Pattern | `sketch.pattern.rectangular` | SKETCH › CREATE |
| Project (P) | `sketch.project` | SKETCH › CREATE |
| Intersect | `sketch.intersect` | SKETCH › CREATE |
| Include 3D Geometry | `sketch.include_3d` | SKETCH › CREATE |
| Project To Surface | `sketch.project_to_surface` | SKETCH › CREATE |
| Intersection Curve | `sketch.intersection_curve` | SKETCH › CREATE |
| Spun Profile | `sketch.spun_profile` | SKETCH › CREATE |
| Isoparametric Curve | `sketch.isoparametric_curve` | SKETCH › CREATE |
| Fit Curves to Mesh Section | `sketch.fit_curves_to_section` | SKETCH › CREATE |
| Break Link | `sketch.break_link` | – |
| Auto-Project Edges on Reference | `sketch.auto_project` | – |
| Redefine Sketch Plane | `sketch.redefine` | – |
| Inspect Sketch | `sketch.inspect` | – |
## Solid modelling (35)
| Command | Id | Toolbar |
|---|---|---|
| Extrude (E) | `solid.extrude` | SOLID › CREATE |
| Revolve | `solid.revolve` | SOLID › CREATE |
| Sweep | `solid.sweep` | SOLID › CREATE |
| Loft | `solid.loft` | SOLID › CREATE |
| Box | `solid.box` | SOLID › CREATE |
| Cylinder | `solid.cylinder` | SOLID › CREATE |
| Sphere | `solid.sphere` | SOLID › CREATE |
| Torus | `solid.torus` | SOLID › CREATE |
| Fillet (F) | `solid.fillet` | SOLID › MODIFY |
| Chamfer | `solid.chamfer` | SOLID › MODIFY |
| Combine | `solid.combine` | SOLID › MODIFY |
| Rectangular Pattern | `solid.pattern.rectangular` | SOLID › CREATE |
| Circular Pattern | `solid.pattern.circular` | SOLID › CREATE |
| Pattern on Path | `solid.pattern.path` | SOLID › CREATE |
| Mirror | `solid.mirror` | SOLID › CREATE |
| Hole (H) | `solid.hole` | SOLID › CREATE |
| Pipe | `solid.pipe` | SOLID › CREATE |
| Bounding Solid | `solid.bounding_solid` | SOLID › CREATE |
| Scale | `solid.scale` | SOLID › MODIFY |
| Offset Face | `solid.offset_face` | SOLID › MODIFY |
| Thread | `solid.thread` | SOLID › CREATE |
| Shell | `solid.shell` | SOLID › MODIFY |
| Draft | `solid.draft` | SOLID › MODIFY |
| Split Face | `solid.split_face` | SOLID › MODIFY |
| Split Body | `solid.split_body` | SOLID › MODIFY |
| Press Pull (Q) | `solid.press_pull` | SOLID › MODIFY |
| Move/Copy (M) | `solid.move` | SOLID › MODIFY |
| Boundary Fill | `solid.boundary_fill` | SOLID › CREATE |
| Coil | `solid.coil` | SOLID › CREATE |
| Rib | `solid.rib` | SOLID › CREATE |
| Web | `solid.web` | SOLID › CREATE |
| Emboss | `solid.emboss` | SOLID › CREATE |
| Replace Face | `solid.replace_face` | SOLID › MODIFY |
| Align | `solid.align` | SOLID › MODIFY |
| Remove | `solid.remove` | SOLID › MODIFY |
## Surfaces (5)
| Command | Id | Toolbar |
|---|---|---|
| Patch | `surface.patch` | SURFACE › CREATE |
| Stitch | `surface.stitch` | SURFACE › MODIFY |
| Thicken | `surface.thicken` | SURFACE › CREATE |
| Extend | `surface.extend` | SURFACE › MODIFY |
| Trim | `surface.trim` | SURFACE › MODIFY |
## Construction geometry (19)
| Command | Id | Toolbar |
|---|---|---|
| Offset Plane | `construct.plane.offset` | SOLID › CONSTRUCT |
| Plane at Angle | `construct.plane.at_angle` | SOLID › CONSTRUCT |
| Axis Through Cylinder/Cone/Torus | `construct.axis.through_cylinder` | SOLID › CONSTRUCT |
| Axis Perpendicular To Face | `construct.axis.normal_to_face` | SOLID › CONSTRUCT |
| Axis Through Two Planes | `construct.axis.two_planes` | SOLID › CONSTRUCT |
| Axis Through Two Points | `construct.axis.two_points` | SOLID › CONSTRUCT |
| Axis Through Edge | `construct.axis.edge` | SOLID › CONSTRUCT |
| Point At Vertex | `construct.point.vertex` | SOLID › CONSTRUCT |
| Point Through Two Edges | `construct.point.two_edges` | SOLID › CONSTRUCT |
| Point Through Three Planes | `construct.point.three_planes` | SOLID › CONSTRUCT |
| Point At Center Of Circle/Sphere/Torus | `construct.point.center` | SOLID › CONSTRUCT |
| Point At Edge And Plane | `construct.point.edge_plane` | SOLID › CONSTRUCT |
| Point Along Path | `construct.point.along_path` | SOLID › CONSTRUCT |
| Midplane | `construct.plane.midplane` | SOLID › CONSTRUCT |
| Plane Through Two Edges | `construct.plane.two_edges` | SOLID › CONSTRUCT |
| Plane Through Three Points | `construct.plane.three_points` | SOLID › CONSTRUCT |
| Tangent Plane | `construct.plane.tangent` | SOLID › CONSTRUCT |
| Plane Along Path | `construct.plane.along_path` | SOLID › CONSTRUCT |
| Perpendicular Plane | `construct.plane.perpendicular` | SOLID › CONSTRUCT |
## Sheet metal (11)
| Command | Id | Toolbar |
|---|---|---|
| Flange | `sheet.flange` | SHEET METAL › CREATE |
| Hem | `sheet.hem` | SHEET METAL › CREATE |
| Fold | `sheet.fold` | SHEET METAL › CREATE |
| Unfold | `sheet.unfold` | SHEET METAL › MODIFY |
| Refold | `sheet.refold` | SHEET METAL › MODIFY |
| Convert to Sheet Metal | `sheet.convert` | SHEET METAL › CREATE |
| Sheet Metal Rules | `sheet.manage_rules` | SHEET METAL › MODIFY |
| List Sheet Metal Rules | `sheet.rules` | – |
| Create Flat Pattern | `sheet.flat_pattern` | SHEET METAL › CREATE |
| Export Flat Pattern as DXF | `sheet.export_dxf` | – |
| Export Bend Table | `sheet.export_bend_table` | – |
## Plastic parts (7)
| Command | Id | Toolbar |
|---|---|---|
| Boss | `plastic.boss` | PLASTIC › CREATE |
| Lip | `plastic.lip` | PLASTIC › CREATE |
| Snap Fit | `plastic.snap_fit` | PLASTIC › CREATE |
| Rest | `plastic.rest` | PLASTIC › CREATE |
| Manage Plastic Rules | `plastic.manage_rules` | PLASTIC › SETUP |
| Assign Plastic Rule | `plastic.assign_rule` | PLASTIC › SETUP |
| List Plastic Rules | `plastic.rules` | – |
## Components (12)
| Command | Id | Toolbar |
|---|---|---|
| New Component | `component.create` | SOLID › ASSEMBLE |
| Create Components from Bodies | `component.from_bodies` | – |
| Activate Component | `component.activate` | – |
| List Components | `component.list` | – |
| Component Physical Properties | `component.properties` | – |
| Rename Component | `component.rename` | – |
| Delete Component | `component.delete` | – |
| Move Bodies to Component | `component.move_bodies` | – |
| Move Sketches to Component | `component.move_sketches` | – |
| Paste New | `component.paste_new` | – |
| Capture Position | `component.capture_position` | SOLID › POSITION |
| Revert Position | `component.revert_position` | SOLID › POSITION |
## Assembly joints (11)
| Command | Id | Toolbar |
|---|---|---|
| Joint Origin | `joint.origin` | SOLID › CREATE |
| Joint (J) | `joint.create` | SOLID › ASSEMBLE |
| As-Built Joint | `joint.as_built` | SOLID › ASSEMBLE |
| Rigid Group | `joint.rigid_group` | SOLID › ASSEMBLE |
| Drive Joints | `joint.drive` | SOLID › ASSEMBLE |
| Motion Link | `joint.motion_link` | SOLID › ASSEMBLE |
| Joint Limits | `joint.limits` | – |
| Edit Joint | `joint.edit` | – |
| Delete Joint | `joint.delete` | – |
| List Joints | `joint.list` | – |
| Solve Joints | `joint.solve` | – |
## Configurations (8)
| Command | Id | Toolbar |
|---|---|---|
| Configure | `config.configure` | SOLID › CONFIGURE |
| Display Configuration Table | `config.table` | SOLID › CONFIGURE |
| Configuration Column | `config.column` | – |
| Configuration Row | `config.row` | – |
| Activate Configuration | `config.activate` | – |
| Preview Configuration | `config.preview` | – |
| Configuration Rule | `config.rule` | – |
| Configuration Rules | `config.rules` | – |
## Timeline (13)
| Command | Id | Toolbar |
|---|---|---|
| Compute All | `timeline.compute_all` | SOLID › MODIFY |
| Delete (Delete) | `timeline.delete` | SOLID › MODIFY |
| Rename | `timeline.rename` | – |
| Move Timeline Marker | `timeline.rollback` | – |
| Roll History Marker | `timeline.roll_to` | – |
| Reorder Feature | `timeline.reorder` | – |
| Edit Feature | `timeline.redefine` | – |
| Feature Dependents | `timeline.dependents` | – |
| Suppress Feature | `timeline.suppress` | – |
| Edit Feature | `timeline.edit` | – |
| Inspect Feature | `timeline.inspect` | – |
| Copy Features | `timeline.copy` | – |
| Paste Features | `timeline.paste` | – |
## Inspect (12)
| Command | Id | Toolbar |
|---|---|---|
| Curvature Comb Analysis | `inspect.curvature_comb` | SKETCH › INSPECT |
| Minimum Radius Analysis | `inspect.minimum_radius` | SKETCH › INSPECT |
| Isocurve Analysis | `inspect.isocurve` | SKETCH › INSPECT |
| Center of Mass | `inspect.center_of_mass` | SKETCH › INSPECT |
| Zebra Analysis | `inspect.zebra` | SKETCH › INSPECT |
| Draft Analysis | `inspect.draft` | SKETCH › INSPECT |
| Environment Map Analysis | `inspect.environment_map` | SKETCH › INSPECT |
| Accessibility Analysis | `inspect.accessibility` | SKETCH › INSPECT |
| Curvature Map Analysis | `inspect.curvature_map` | SKETCH › INSPECT |
| Interference | `inspect.interference` | SOLID › INSPECT |
| Measure (I) | `inspect.measure` | SOLID › INSPECT |
| Section Analysis | `inspect.section` | SOLID › INSPECT |
## Files (7)
| Command | Id | Toolbar |
|---|---|---|
| New Design (Ctrl+N) | `file.new` | – |
| Insert STEP | `file.insert_step` | SOLID › INSERT |
| Insert Mesh | `file.insert_mesh` | SOLID › INSERT |
| Save (Ctrl+S) | `file.save` | – |
| Save As | `file.save_as` | – |
| Export | `file.export` | – |
| Save As Mesh | `file.save_mesh` | – |
## Documents (4)
| Command | Id | Toolbar |
|---|---|---|
| Open (Ctrl+O) | `doc.open` | – |
| Recoverable Designs | `doc.recovery_list` | – |
| Recover Design | `doc.recover` | – |
| Discard Recovered Design | `doc.recovery_discard` | – |
## Edit (4)
| Command | Id | Toolbar |
|---|---|---|
| Undo (Ctrl+Z) | `edit.undo` | – |
| Redo (Ctrl+Y) | `edit.redo` | – |
| Checkpoint | `edit.checkpoint` | – |
| Restore Checkpoint | `edit.restore_checkpoint` | – |
## `appearance.*` (3)
| Command | Id | Toolbar |
|---|---|---|
| Appearance (A) | `appearance.assign` | SOLID › MODIFY |
| Appearance Library | `appearance.library` | – |
| List Appearances | `appearance.list` | – |
## `body.*` (1)
| Command | Id | Toolbar |
|---|---|---|
| Rename Body | `body.rename` | – |
## `browser.*` (6)
| Command | Id | Toolbar |
|---|---|---|
| New Group | `browser.group` | – |
| Ungroup | `browser.ungroup` | – |
| Rename Group | `browser.rename_group` | – |
| Move Browser Items | `browser.move` | – |
| Order Browser Items | `browser.order` | – |
| Show/Hide | `browser.visibility` | – |
## `canvas.*` (5)
| Command | Id | Toolbar |
|---|---|---|
| Canvas | `canvas.insert` | SKETCH › INSERT |
| Decal | `canvas.decal` | SKETCH › INSERT |
| Edit Canvas | `canvas.edit` | SKETCH › INSERT |
| Calibrate Canvas | `canvas.calibrate` | – |
| Delete Canvas | `canvas.delete` | – |
## `contact.*` (7)
| Command | Id | Toolbar |
|---|---|---|
| Enable Contact Sets | `contact.enable_sets` | SOLID › ASSEMBLE |
| Enable All Contact | `contact.enable_all` | SOLID › ASSEMBLE |
| Disable Contact | `contact.disable_all` | SOLID › ASSEMBLE |
| New Contact Set | `contact.create` | SOLID › ASSEMBLE |
| Edit Contact Set | `contact.edit` | – |
| List Contact Sets | `contact.list` | – |
| Check Contact | `contact.check` | – |
## `document.*` (2)
| Command | Id | Toolbar |
|---|---|---|
| Change Design Units | `document.units` | – |
| Inspect Design | `document.inspect` | – |
## `engine.*` (1)
| Command | Id | Toolbar |
|---|---|---|
| List Commands | `engine.commands` | – |
## `explode.*` (4)
| Command | Id | Toolbar |
|---|---|---|
| Exploded View | `explode.create` | SOLID › ASSEMBLE |
| Show Exploded View | `explode.show` | – |
| List Exploded Views | `explode.list` | – |
| Delete Exploded View | `explode.delete` | – |
## `expr.*` (1)
| Command | Id | Toolbar |
|---|---|---|
| Evaluate Expression | `expr.evaluate` | – |
## `face.*` (1)
| Command | Id | Toolbar |
|---|---|---|
| Delete Face | `face.delete` | SOLID › MODIFY |
## `material.*` (2)
| Command | Id | Toolbar |
|---|---|---|
| Physical Material | `material.assign` | SOLID › MODIFY |
| List Materials | `material.list` | – |
## `mesh.*` (1)
| Command | Id | Toolbar |
|---|---|---|
| Convert Mesh | `mesh.convert` | MESH › MODIFY |
## `model.*` (3)
| Command | Id | Toolbar |
|---|---|---|
| List Edges | `model.edges` | – |
| List Faces | `model.faces` | – |
| List Threads | `model.threads` | – |
## `motion.*` (5)
| Command | Id | Toolbar |
|---|---|---|
| Motion Study | `motion.study` | SOLID › ASSEMBLE |
| Play Motion Study | `motion.play` | – |
| Export Motion Study | `motion.export` | – |
| List Motion Studies | `motion.list` | – |
| Delete Motion Study | `motion.delete` | – |
## `occurrence.*` (4)
| Command | Id | Toolbar |
|---|---|---|
| Occurrence Physical Properties | `occurrence.properties` | – |
| Paste (Instance) | `occurrence.copy` | – |
| Move Occurrence | `occurrence.move` | – |
| Ground | `occurrence.ground` | – |
## `parameters.*` (12)
| Command | Id | Toolbar |
|---|---|---|
| Change Parameters | `parameters.change` | SOLID › MODIFY |
| List Parameters | `parameters.list` | – |
| Add User Parameter | `parameters.add` | – |
| Rename Parameter | `parameters.rename` | – |
| Delete Parameter | `parameters.delete` | – |
| Favourite Parameter | `parameters.favorite` | – |
| Comment Parameter | `parameters.comment` | – |
| Parameter Users | `parameters.users` | – |
| Parameter Graph | `parameters.graph` | – |
| Export Parameters | `parameters.export` | – |
| Import Parameters | `parameters.import` | – |
| Complete Expression | `parameters.complete` | – |
## `parts.*` (4)
| Command | Id | Toolbar |
|---|---|---|
| Standard Parts | `parts.library` | – |
| Insert Fastener | `parts.fastener` | SOLID › INSERT |
| Insert Part | `parts.insert` | – |
| Change Part Size | `parts.resize` | – |
## `select.*` (2)
| Command | Id | Toolbar |
|---|---|---|
| Select | `select.set` | – |
| Clear Selection | `select.clear` | – |
## `selection.*` (1)
| Command | Id | Toolbar |
|---|---|---|
| Delete | `selection.delete` | – |
## `view.*` (4)
| Command | Id | Toolbar |
|---|---|---|
| New Named View | `view.save` | – |
| Rename Named View | `view.rename` | – |
| Delete Named View | `view.delete` | – |
| List Named Views | `view.list` | – |
-406
View File
@@ -1,406 +0,0 @@
# Fusion command parity
Generated by `cargo xtask parity` from `xtask/data/fusion-catalog.tsv` (the toolbar commands of Fusion's Design workspace, ids and names only) and the live command registry (`solvecraft-cli commands`). A command counts as live when SolidCraft registers the same command id. This measures breadth, not depth; see ROADMAP.md and docs/oracle.md for depth.
**In scope (SOLID, SKETCH, ASSEMBLY, SHEET METAL, PLASTIC enclosure subset): 335 / 541 commands live (62%).** SOLID + SKETCH: 188 / 291 (65%). Registered commands: 314.
Deferred until further notice (not in the in-scope figure): MESH, FORM, SURFACE beyond what solids need, PCB, render, animation, simulation, manufacture, drawings, MANAGE, UTILITIES and the rest of PLASTIC. All Design tabs together: 631 / 1175 (54%).
| Tab | Panel | Live | Total | % |
|---|---|---:|---:|---:|
| SOLID | CREATE | 23 | 35 | 66% |
| SOLID | MODIFY | 19 | 32 | 59% |
| SOLID | ASSEMBLE | 12 | 21 | 57% |
| SOLID | CONFIGURE | 3 | 3 | 100% |
| SOLID | CONSTRUCT | 19 | 20 | 95% |
| SOLID | INSPECT | 12 | 25 | 48% |
| SOLID | INSERT | 6 | 11 | 55% |
| SOLID | SELECT | 0 | 15 | 0% |
| SOLID | POSITION | 2 | 2 | 100% |
| SKETCH | CREATE | 41 | 41 | 100% |
| SKETCH | MODIFY | 12 | 12 | 100% |
| SKETCH | CONSTRAINTS | 15 | 15 | 100% |
| SKETCH | CONFIGURE | 3 | 3 | 100% |
| SKETCH | INSPECT | 12 | 25 | 48% |
| SKETCH | INSERT | 7 | 13 | 54% |
| SKETCH | ASSEMBLE | 0 | 1 | 0% |
| SKETCH | SELECT | 0 | 15 | 0% |
| SKETCH | FINISH SKETCH | 2 | 2 | 100% |
| SHEET METAL | CREATE | 15 | 19 | 79% |
| SHEET METAL | MODIFY | 12 | 21 | 57% |
| SHEET METAL | ASSEMBLE | 11 | 20 | 55% |
| SHEET METAL | CONFIGURE | 3 | 3 | 100% |
| SHEET METAL | CONSTRUCT | 19 | 20 | 95% |
| SHEET METAL | INSPECT | 12 | 25 | 48% |
| SHEET METAL | INSERT | 6 | 11 | 55% |
| SHEET METAL | SELECT | 0 | 15 | 0% |
| SHEET METAL | REFOLD | 0 | 1 | 0% |
| SHEET METAL | POSITION | 2 | 2 | 100% |
| ASSEMBLY | INSERT | 4 | 8 | 50% |
| ASSEMBLY | CREATE | 5 | 8 | 62% |
| ASSEMBLY | RELATIONSHIPS | 4 | 11 | 36% |
| ASSEMBLY | MOTION | 3 | 3 | 100% |
| ASSEMBLY | MODIFY | 8 | 11 | 73% |
| ASSEMBLY | CONTACT | 2 | 2 | 100% |
| ASSEMBLY | CONFIGURE | 3 | 3 | 100% |
| ASSEMBLY | CONSTRUCT | 19 | 20 | 95% |
| ASSEMBLY | INSPECT | 12 | 25 | 48% |
| ASSEMBLY | SELECT | 0 | 15 | 0% |
| ASSEMBLY | POSITION | 2 | 2 | 100% |
| PLASTIC | enclosure subset | 5 | 5 | 100% |
### Deferred tabs
| Tab | Panel | Live | Total | % |
|---|---|---:|---:|---:|
| SURFACE | CREATE | 9 | 25 | 36% |
| SURFACE | MODIFY | 17 | 26 | 65% |
| SURFACE | ASSEMBLE | 11 | 20 | 55% |
| SURFACE | CONFIGURE | 3 | 3 | 100% |
| SURFACE | CONSTRUCT | 19 | 20 | 95% |
| SURFACE | INSPECT | 12 | 25 | 48% |
| SURFACE | INSERT | 6 | 11 | 55% |
| SURFACE | SELECT | 0 | 15 | 0% |
| SURFACE | POSITION | 2 | 2 | 100% |
| MESH | CREATE | 2 | 5 | 40% |
| MESH | PREPARE | 0 | 4 | 0% |
| MESH | MODIFY | 7 | 30 | 23% |
| MESH | ASSEMBLE | 12 | 21 | 57% |
| MESH | CONFIGURE | 3 | 3 | 100% |
| MESH | CONSTRUCT | 19 | 20 | 95% |
| MESH | INSPECT | 12 | 25 | 48% |
| MESH | INSERT | 5 | 10 | 50% |
| MESH | SELECT | 0 | 10 | 0% |
| MESH | EXPORT | 0 | 1 | 0% |
| MESH | POSITION | 2 | 2 | 100% |
| FORM | CREATE | 2 | 14 | 14% |
| FORM | MODIFY | 5 | 31 | 16% |
| FORM | SYMMETRY | 0 | 6 | 0% |
| FORM | UTILITIES | 0 | 5 | 0% |
| FORM | CONSTRUCT | 19 | 20 | 95% |
| FORM | INSPECT | 12 | 25 | 48% |
| FORM | INSERT | 7 | 13 | 54% |
| FORM | ASSEMBLE | 0 | 1 | 0% |
| FORM | SELECT | 0 | 15 | 0% |
| FORM | FINISH FORM | 0 | 1 | 0% |
| PLASTIC | SETUP | 2 | 2 | 100% |
| PLASTIC | CREATE | 27 | 35 | 77% |
| PLASTIC | MODIFY | 19 | 32 | 59% |
| PLASTIC | ASSEMBLE | 11 | 20 | 55% |
| PLASTIC | CONFIGURE | 3 | 3 | 100% |
| PLASTIC | CONSTRUCT | 19 | 20 | 95% |
| PLASTIC | INSPECT | 12 | 26 | 46% |
| PLASTIC | INSERT | 6 | 11 | 55% |
| PLASTIC | SELECT | 0 | 15 | 0% |
| PLASTIC | POSITION | 2 | 2 | 100% |
| MANAGE | ASSIGN | 0 | 1 | 0% |
| MANAGE | RELEASE | 0 | 2 | 0% |
| MANAGE | BOM | 0 | 2 | 0% |
| MANAGE | PROCESS MANAGEMENT | 0 | 3 | 0% |
| MANAGE | TASK MANAGEMENT | 0 | 3 | 0% |
| UTILITIES | MODELING TOOLS | 0 | 1 | 0% |
| UTILITIES | MAKE | 0 | 1 | 0% |
| UTILITIES | NEST | 0 | 1 | 0% |
| UTILITIES | ADD-INS | 0 | 2 | 0% |
| UTILITIES | UTILITY | 1 | 3 | 33% |
| UTILITIES | INSPECT | 11 | 24 | 46% |
| UTILITIES | CREATE PMI | 0 | 4 | 0% |
| UTILITIES | SELECT | 0 | 15 | 0% |
| UTILITIES | POSITION | 2 | 2 | 100% |
## Live (SOLID, SKETCH)
- SOLID › CREATE › Create Sketch
- SOLID › CREATE › Extrude
- SOLID › CREATE › Revolve
- SOLID › CREATE › Sweep
- SOLID › CREATE › Loft
- SOLID › CREATE › Rib
- SOLID › CREATE › Web
- SOLID › CREATE › Emboss
- SOLID › CREATE › Hole
- SOLID › CREATE › Thread
- SOLID › CREATE › Box
- SOLID › CREATE › Cylinder
- SOLID › CREATE › Sphere
- SOLID › CREATE › Torus
- SOLID › CREATE › Coil
- SOLID › CREATE › Pipe
- SOLID › CREATE › Bounding Solid
- SOLID › CREATE › Rectangular Pattern
- SOLID › CREATE › Circular Pattern
- SOLID › CREATE › Pattern on Path
- SOLID › CREATE › Mirror
- SOLID › CREATE › Thicken
- SOLID › CREATE › Joint Origin
- SOLID › MODIFY › Press Pull
- SOLID › MODIFY › Fillet
- SOLID › MODIFY › Chamfer
- SOLID › MODIFY › Shell
- SOLID › MODIFY › Draft
- SOLID › MODIFY › Scale
- SOLID › MODIFY › Combine
- SOLID › MODIFY › Offset Face
- SOLID › MODIFY › Replace Face
- SOLID › MODIFY › Split Face
- SOLID › MODIFY › Split Body
- SOLID › MODIFY › Move/Copy
- SOLID › MODIFY › Align
- SOLID › MODIFY › Delete
- SOLID › MODIFY › Remove
- SOLID › MODIFY › Physical Material
- SOLID › MODIFY › Appearance
- SOLID › MODIFY › Change Parameters
- SOLID › MODIFY › Compute All
- SOLID › ASSEMBLE › Insert Component
- SOLID › ASSEMBLE › New Component
- SOLID › ASSEMBLE › Joint
- SOLID › ASSEMBLE › As-Built Joint
- SOLID › ASSEMBLE › Rigid Group
- SOLID › ASSEMBLE › Drive Joints
- SOLID › ASSEMBLE › Motion Link
- SOLID › ASSEMBLE › Motion Study
- SOLID › ASSEMBLE › Enable Contact Sets
- SOLID › ASSEMBLE › Enable All Contact
- SOLID › ASSEMBLE › Disable Contact
- SOLID › ASSEMBLE › New Contact Set
- SOLID › CONFIGURE › Configure
- SOLID › CONFIGURE › Display Configuration Table
- SOLID › CONFIGURE › Create Configuration Rules
- SOLID › CONSTRUCT › Offset Plane
- SOLID › CONSTRUCT › Plane at Angle
- SOLID › CONSTRUCT › Tangent Plane
- SOLID › CONSTRUCT › Midplane
- SOLID › CONSTRUCT › Perpendicular Plane
- SOLID › CONSTRUCT › Plane Through Two Edges
- SOLID › CONSTRUCT › Plane Through Three Points
- SOLID › CONSTRUCT › Plane Along Path
- SOLID › CONSTRUCT › Axis Through Cylinder/Cone/Torus
- SOLID › CONSTRUCT › Axis Perpendicular To Face
- SOLID › CONSTRUCT › Axis Through Two Planes
- SOLID › CONSTRUCT › Axis Through Two Points
- SOLID › CONSTRUCT › Axis Through Edge
- SOLID › CONSTRUCT › Point At Vertex
- SOLID › CONSTRUCT › Point Through Two Edges
- SOLID › CONSTRUCT › Point Through Three Planes
- SOLID › CONSTRUCT › Point At Center Of Circle/Sphere/Torus
- SOLID › CONSTRUCT › Point At Edge And Plane
- SOLID › CONSTRUCT › Point Along Path
- SOLID › INSPECT › Measure
- SOLID › INSPECT › Interference
- SOLID › INSPECT › Section Analysis
- SOLID › INSPECT › Curvature Comb Analysis
- SOLID › INSPECT › Curvature Map Analysis
- SOLID › INSPECT › Draft Analysis
- SOLID › INSPECT › Environment Map Analysis
- SOLID › INSPECT › Isocurve Analysis
- SOLID › INSPECT › Zebra Analysis
- SOLID › INSPECT › Accessibility Analysis
- SOLID › INSPECT › Center of Mass
- SOLID › INSPECT › Minimum Radius Analysis
- SOLID › INSERT › Decal
- SOLID › INSERT › Canvas
- SOLID › INSERT › Insert SVG
- SOLID › INSERT › Insert DXF
- SOLID › INSERT › Insert Mesh
- SOLID › INSERT › Insert Fastener
- SOLID › POSITION › Capture Position
- SOLID › POSITION › Revert Position
- SKETCH › CREATE › Line
- SKETCH › CREATE › Midpoint Line
- SKETCH › CREATE › SketchConstrainer
- SKETCH › CREATE › 2-Point Rectangle
- SKETCH › CREATE › 3-Point Rectangle
- SKETCH › CREATE › Center Rectangle
- SKETCH › CREATE › Center Diameter Circle
- SKETCH › CREATE › 2-Point Circle
- SKETCH › CREATE › 3-Point Circle
- SKETCH › CREATE › 2-Tangent Circle
- SKETCH › CREATE › 3-Tangent Circle
- SKETCH › CREATE › 3-Point Arc
- SKETCH › CREATE › Center Point Arc
- SKETCH › CREATE › Tangent Arc
- SKETCH › CREATE › Circumscribed Polygon
- SKETCH › CREATE › Inscribed Polygon
- SKETCH › CREATE › Edge Polygon
- SKETCH › CREATE › Ellipse
- SKETCH › CREATE › Center to Center Slot
- SKETCH › CREATE › Overall Slot
- SKETCH › CREATE › Center Point Slot
- SKETCH › CREATE › Three Point Arc Slot
- SKETCH › CREATE › Center Point Arc Slot
- SKETCH › CREATE › Fit Point Spline
- SKETCH › CREATE › Control Point Spline
- SKETCH › CREATE › Control Point Spline
- SKETCH › CREATE › Conic Curve
- SKETCH › CREATE › Point
- SKETCH › CREATE › Text
- SKETCH › CREATE › Fit Curves to Mesh Section
- SKETCH › CREATE › Mirror
- SKETCH › CREATE › Circular Pattern
- SKETCH › CREATE › Rectangular Pattern
- SKETCH › CREATE › Project
- SKETCH › CREATE › Intersect
- SKETCH › CREATE › Spun Profile
- SKETCH › CREATE › Include 3D Geometry
- SKETCH › CREATE › Project To Surface
- SKETCH › CREATE › Intersection Curve
- SKETCH › CREATE › Isoparametric Curve
- SKETCH › CREATE › Sketch Dimension
- SKETCH › MODIFY › Fillet
- SKETCH › MODIFY › Equal Distance Chamfer
- SKETCH › MODIFY › Distance and Angle Chamfer
- SKETCH › MODIFY › Two Distance Chamfer
- SKETCH › MODIFY › Blend Curve
- SKETCH › MODIFY › Offset
- SKETCH › MODIFY › Trim
- SKETCH › MODIFY › Extend
- SKETCH › MODIFY › Break
- SKETCH › MODIFY › Sketch Scale
- SKETCH › MODIFY › Move/Copy
- SKETCH › MODIFY › Change Parameters
- SKETCH › CONSTRAINTS › AutoConstrain
- SKETCH › CONSTRAINTS › AutoConstrain from datum
- SKETCH › CONSTRAINTS › Horizontal/Vertical
- SKETCH › CONSTRAINTS › Coincident
- SKETCH › CONSTRAINTS › Tangent
- SKETCH › CONSTRAINTS › Equal
- SKETCH › CONSTRAINTS › Parallel
- SKETCH › CONSTRAINTS › Perpendicular
- SKETCH › CONSTRAINTS › Fix/UnFix
- SKETCH › CONSTRAINTS › MidPoint
- SKETCH › CONSTRAINTS › Concentric
- SKETCH › CONSTRAINTS › Collinear
- SKETCH › CONSTRAINTS › Symmetry
- SKETCH › CONSTRAINTS › Curvature
- SKETCH › CONSTRAINTS › Polygon
- SKETCH › CONFIGURE › Configure
- SKETCH › CONFIGURE › Display Configuration Table
- SKETCH › CONFIGURE › Create Configuration Rules
- SKETCH › INSPECT › Measure
- SKETCH › INSPECT › Interference
- SKETCH › INSPECT › Section Analysis
- SKETCH › INSPECT › Curvature Comb Analysis
- SKETCH › INSPECT › Curvature Map Analysis
- SKETCH › INSPECT › Draft Analysis
- SKETCH › INSPECT › Environment Map Analysis
- SKETCH › INSPECT › Isocurve Analysis
- SKETCH › INSPECT › Zebra Analysis
- SKETCH › INSPECT › Accessibility Analysis
- SKETCH › INSPECT › Center of Mass
- SKETCH › INSPECT › Minimum Radius Analysis
- SKETCH › INSERT › Decal
- SKETCH › INSERT › Canvas
- SKETCH › INSERT › Insert SVG
- SKETCH › INSERT › Insert DXF
- SKETCH › INSERT › Insert Mesh
- SKETCH › INSERT › Insert Component
- SKETCH › INSERT › Insert Fastener
- SKETCH › FINISH SKETCH › Finish Sketch
- SKETCH › FINISH SKETCH › Finish with AutoConstrain
## Not yet (SOLID, SKETCH)
- SOLID › CREATE › Create Form
- SOLID › CREATE › Derive
- SOLID › CREATE › Automated Modeling
- SOLID › CREATE › Geometric Pattern
- SOLID › CREATE › Boundary Fill
- SOLID › CREATE › Find Features
- SOLID › CREATE › Fluid Volume
- SOLID › CREATE › Create Base Feature
- SOLID › CREATE › Create Linked PCB
- SOLID › CREATE › Derive PCB
- SOLID › CREATE › Create Unlinked PCB
- SOLID › CREATE › Generate Timeline
- SOLID › MODIFY › Edit Face
- SOLID › MODIFY › Silhouette Split
- SOLID › MODIFY › Arrange
- SOLID › MODIFY › Remove Features
- SOLID › MODIFY › Remove Faces
- SOLID › MODIFY › Replace with Primitives
- SOLID › MODIFY › Volumetric Lattice
- SOLID › MODIFY › Volumetric Texture
- SOLID › MODIFY › VolFieldModifyModelCommand
- SOLID › MODIFY › Manage Materials
- SOLID › MODIFY › Compute Unresolved
- SOLID › MODIFY › Convert
- SOLID › MODIFY › Bill of Materials
- SOLID › ASSEMBLE › Duplicate With Joints
- SOLID › ASSEMBLE › Constrain Components
- SOLID › ASSEMBLE › Align Constraint
- SOLID › ASSEMBLE › Angle Constraint
- SOLID › ASSEMBLE › Center Constraint
- SOLID › ASSEMBLE › Tangent Constraint
- SOLID › ASSEMBLE › Joint Constraint
- SOLID › ASSEMBLE › As-Built Constraint
- SOLID › CONSTRUCT › User Coordinate System (UCS)
- SOLID › INSPECT › Validate
- SOLID › INSPECT › Component Connection Analysis
- SOLID › INSPECT › DOF Analysis
- SOLID › INSPECT › Edit Component Connection Analysis
- SOLID › INSPECT › Fastener Stack Analysis
- SOLID › INSPECT › Find Similar Components
- SOLID › INSPECT › Navigator
- SOLID › INSPECT › Display Component Colors
- SOLID › INSPECT › Display Mesh Face Groups
- SOLID › INSPECT › Assembly Statistics
- SOLID › INSPECT › Change Summary
- SOLID › INSPECT › History
- SOLID › INSPECT › Sustainability Insights
- SOLID › INSERT › Insert T-Spline
- SOLID › INSERT › Insert Derive
- SOLID › INSERT › Insert McMaster-Carr Component
- SOLID › INSERT › Insert a manufacturer part
- SOLID › INSERT › Insert TraceParts Supplier Components
- SOLID › ASSEMBLE › Add To Assembly
- SOLID › SELECT › Select
- SOLID › SELECT › Window Selection
- SOLID › SELECT › Freeform Selection
- SOLID › SELECT › Paint Selection
- SOLID › SELECT › Select By Name
- SOLID › SELECT › Select By Boundary
- SOLID › SELECT › Select By Size
- SOLID › SELECT › Invert Selection
- SOLID › SELECT › Seed And Boundary
- SOLID › SELECT › Component Drag
- SOLID › SELECT › Select Body Priority
- SOLID › SELECT › Select Face Priority
- SOLID › SELECT › Select Edge Priority
- SOLID › SELECT › Select Component Priority
- SOLID › SELECT › Selection Filters
- SKETCH › INSPECT › Validate
- SKETCH › INSPECT › Component Connection Analysis
- SKETCH › INSPECT › DOF Analysis
- SKETCH › INSPECT › Edit Component Connection Analysis
- SKETCH › INSPECT › Fastener Stack Analysis
- SKETCH › INSPECT › Find Similar Components
- SKETCH › INSPECT › Navigator
- SKETCH › INSPECT › Display Component Colors
- SKETCH › INSPECT › Display Mesh Face Groups
- SKETCH › INSPECT › Assembly Statistics
- SKETCH › INSPECT › Change Summary
- SKETCH › INSPECT › History
- SKETCH › INSPECT › Sustainability Insights
- SKETCH › INSERT › Insert T-Spline
- SKETCH › INSERT › Duplicate With Joints
- SKETCH › INSERT › Insert Derive
- SKETCH › INSERT › Insert McMaster-Carr Component
- SKETCH › INSERT › Insert a manufacturer part
- SKETCH › INSERT › Insert TraceParts Supplier Components
- SKETCH › ASSEMBLE › Add To Assembly
- SKETCH › SELECT › Select
- SKETCH › SELECT › Window Selection
- SKETCH › SELECT › Freeform Selection
- SKETCH › SELECT › Paint Selection
- SKETCH › SELECT › Select By Name
- SKETCH › SELECT › Select By Boundary
- SKETCH › SELECT › Select By Size
- SKETCH › SELECT › Invert Selection
- SKETCH › SELECT › Seed And Boundary
- SKETCH › SELECT › Component Drag
- SKETCH › SELECT › Select Body Priority
- SKETCH › SELECT › Select Face Priority
- SKETCH › SELECT › Select Edge Priority
- SKETCH › SELECT › Select Component Priority
- SKETCH › SELECT › Selection Filters
+2 -2
View File
@@ -1,7 +1,7 @@
# WIP branch reconciliation (#6)
The branches predate the dotted command IDs. Their remaining changes were ported through
`crates/engine/src/legacy_ids.rs` and reconciled with the current implementation.
The branches predate the dotted command IDs. Their remaining changes were ported to the
dotted ids and reconciled with the current implementation.
| Branches | Result |
|---|---|
File diff suppressed because it is too large. Load diff
-184
View File
@@ -1,184 +0,0 @@
# Fusion catalog command id -> SolveCraft command id, for `cargo xtask parity` only (observation data).
# A catalog command is live when its SolveCraft command is registered.
SketchCreate sketch.create
Extrude solid.extrude
Revolve solid.revolve
Sweep solid.sweep
SolidLoft solid.loft
FusionRibCommand solid.rib
FusionWebCommand solid.web
EmbossCmd solid.emboss
FusionHoleCommand solid.hole
FusionThreadCommand solid.thread
PrimitiveBox solid.box
PrimitiveCylinder solid.cylinder
PrimitiveSphere solid.sphere
PrimitiveTorus solid.torus
PrimitiveCoil solid.coil
PrimitivePipe solid.pipe
StockModelCommand solid.bounding_solid
PatternRectangular solid.pattern.rectangular
PatternCircular solid.pattern.circular
PatternOnPath solid.pattern.path
MirrorCommand solid.mirror
FusionSurfaceThickenCommand surface.thicken
JointOrigin joint.origin
FusionPressPullCommand solid.press_pull
FusionFilletEdgesCommand solid.fillet
FusionChamferCommand solid.chamfer
FusionShellBodyCommand solid.shell
FusionDraftCommand solid.draft
ModifyScale solid.scale
FusionCombineCommand solid.combine
FusionOffsetFacesCommand solid.offset_face
FusionReplaceFaceCommand solid.replace_face
FusionSplitFaceCommand solid.split_face
FusionSplitBodyCommand solid.split_body
FusionMoveCommand solid.move
AlignCmd solid.align
FusionDeleteCommand timeline.delete
SoftDeleteCommand solid.remove
PhysicalMaterialCommand material.assign
AppearanceCommand appearance.assign
ChangeParameterCommand parameters.change
FusionComputeAllCommand timeline.compute_all
FusionImportCommandFromToolbar file.insert_step
FusionCreateNewComponentCommand component.create
JointAssembleCmdNew joint.create
JointAsBuiltCmd joint.as_built
RigidGroupCmd joint.rigid_group
FusionMoveJointsCommand joint.drive
FusionMotionRelationshipCommand joint.motion_link
FusionMotionStudyCommand motion.study
EnableContactSetsCmd contact.enable_sets
EnableAllContactCmd contact.enable_all
DisableAllContactCmd contact.disable_all
ContactSetCmd contact.create
FusionStartDesignConfigModeCmd config.configure
FusionShowDesignConfigPanelCmd config.table
FusionConfigurationRulesCmd config.rules
ConstructionPlaneOffsetFromPlaneCommand construct.plane.offset
ConstructionPlaneAtAngleCommand construct.plane.at_angle
ConstructionTangentPlaneCommand construct.plane.tangent
ConstructionMidPlaneCommand construct.plane.midplane
ConstructionPlaneFromTwoEdgesCommand construct.plane.two_edges
ConstructionPlaneFromThreePointsCommand construct.plane.three_points
ConstructionPlaneAlongPathCommand construct.plane.along_path
ConstructionAxisThroughCylinderCommand construct.axis.through_cylinder
ConstructionAxisNormalToFaceCommand construct.axis.normal_to_face
ConstructionAxisFromTwoPlanesCommand construct.axis.two_planes
ConstructionAxisThroughTwoPointsCommand construct.axis.two_points
ConstructionAxisThroughEdgeCommand construct.axis.edge
ConstructionPointFromPointCommand construct.point.vertex
ConstructionPointThroughTwoEdgesCommand construct.point.two_edges
ConstructionPointFromThreePlanesCommand construct.point.three_planes
ConstructionPointFromCircleOrSphereCommand construct.point.center
ConstructionPointAtEdgeAndPlaneCommand construct.point.edge_plane
ConstructionPointAlongPathCommand construct.point.along_path
MeasureCommand inspect.measure
InterferenceCheckCommand inspect.interference
FusionHalfSectionViewCommand inspect.section
FusionCurvatureCombAnalysisCommand inspect.curvature_comb
FusionCurvatureMapAnalysisCommand inspect.curvature_map
FusionDraftAnalysisCommand inspect.draft
FusionEnvironmentMapAnalysisCommand inspect.environment_map
FusionIsoCurveAnalysisCommand inspect.isocurve
FusionZebraAnalysisCommand inspect.zebra
FusionAccessibilityAnalysisCommand inspect.accessibility
FusionCenterOfMassCommand inspect.center_of_mass
FusionMinimumRadiusAnalysisCommand inspect.minimum_radius
FusionAddEditDecalCommand canvas.decal
FusionAddCanvasCommand canvas.insert
SketchImportSVG sketch.insert_svg
ImportDxfFileCommand sketch.insert_dxf
ParaMeshInsertAlignCommand file.insert_mesh
FusionFastenersCommand parts.fastener
SnapshotCmd component.capture_position
AsBuiltPositionsCmd component.revert_position
DrawPolyline sketch.line
SketchMidpointLine sketch.line.midpoint
SketchConstrainer sketch.constrainer
ShapeRectangleTwoPoint sketch.rectangle.two_point
ShapeRectangleThreePoint sketch.rectangle.three_point
ShapeRectangleCenter sketch.rectangle.center
CircleCenterRadius sketch.circle.center
CircleTwoPoint sketch.circle.two_point
CircleThreePoint sketch.circle.three_point
CircleTanTanRadius sketch.circle.two_tangent
CircleThreeTangent sketch.circle.three_tangent
ArcThreePoint sketch.arc.three_point
ArcCenterTwoPoint sketch.arc.center_point
ArcTangent sketch.arc.tangent
ShapePolygonCircumscribed sketch.polygon.circumscribed
ShapePolygonInscribed sketch.polygon.inscribed
ShapePolygonEdge sketch.polygon.edge
CircleElipse sketch.ellipse
ShapeSlotCenterToCenter sketch.slot.center_to_center
ShapeSlotOverall sketch.slot.overall
ShapeSlotCenterPoint sketch.slot.center_point
ShapeArcSlotThreePoint sketch.slot.arc_three_point
ShapeArcSlotCenterTwoPoint sketch.slot.arc_center
DrawSpline sketch.spline.fit_point
DrawCVMSpline3D sketch.spline.control_point
DrawCVMSpline5D sketch.spline.control_point_5
ConicCurveCmd sketch.conic
DrawPoint sketch.point
MTextCmd sketch.text
FitCurvesToSectionCommand sketch.fit_curves_to_section
MirrorSketchCommand sketch.mirror
CircularSketchPatternCommand sketch.pattern.circular
RectangularSketchPatternCommand sketch.pattern.rectangular
ProjectNewCmd sketch.project
IntersectCmd sketch.intersect
SpunProfileCmd sketch.spun_profile
Include3DGeometry sketch.include_3d
ProjectToSurface sketch.project_to_surface
IntersectionCurve sketch.intersection_curve
SketchIsoparametricCurve sketch.isoparametric_curve
SketchDimension sketch.dimension
FilletSketchCmd sketch.fillet
ChamferSketchEqualDistance sketch.chamfer.equal_distance
ChamferSketchDistanceAngle sketch.chamfer.distance_angle
ChamferSketchDistanceDistance sketch.chamfer.two_distance
BlendG1CurveSketchCmd sketch.blend_curve
Offset sketch.offset
TrimSketchCmd sketch.trim
ExtendSketchCmd sketch.extend
BreakSketchCmd sketch.break
SketchScaleCmd sketch.scale
SketchAutoConstraintAndDimCmd sketch.auto_constrain
SketchAutoConstraintAndDimFromDatumCmd sketch.auto_constrain_from_datum
ConstraintHorizontalVertical sketch.constraint.horizontal_vertical
ConstraintCoincident sketch.constraint.coincident
ConstraintTangent sketch.constraint.tangent
ConstraintEqual sketch.constraint.equal
ConstraintParallel sketch.constraint.parallel
ConstraintPerpendicular sketch.constraint.perpendicular
ConstraintFix sketch.constraint.fix
ConstraintMidPoint sketch.constraint.midpoint
ConstraintConcentric sketch.constraint.concentric
ConstraintCollinear sketch.constraint.collinear
ConstraintSymmetry sketch.constraint.symmetry
ConstraintSmooth sketch.constraint.curvature
SketchPolygonConstraintCmd sketch.constraint.polygon
SketchStop sketch.finish
SketchAutoConstrainAndFinish sketch.finish_auto_constrain
FusionSurfacePatchCommand surface.patch
FusionSurfaceTrimCommand surface.trim
FusionExtendCommand surface.extend
FusionSurfaceStitchCommand surface.stitch
FusionSheetMetalFlangeCommand sheet.flange
FusionSheetMetalHemFlangeCommand sheet.hem
SheetMetalFoldCmd sheet.fold
ConvertToSheetMetalCmd sheet.convert
FusionSheetMetalFlatPatternCmd sheet.flat_pattern
FusionSheetmetalUnfoldCommand sheet.unfold
FusionSheetMetalRulesCommand sheet.manage_rules
FusionAssignPlasticRuleCommand plastic.assign_rule
FusionManagePlasticRuleCommand plastic.manage_rules
FusionBossCommand plastic.boss
FusionSnapFitCommand plastic.snap_fit
FusionLipCommand plastic.lip
FusionRestCommand plastic.rest
ConstructionPlanePerpendicularToPlaneCommand construct.plane.perpendicular
ParaMeshConvertCommand mesh.convert
1 # Fusion catalog command id -> SolveCraft command id, for `cargo xtask parity` only (observation data).
2 # A catalog command is live when its SolveCraft command is registered.
3 SketchCreate sketch.create
4 Extrude solid.extrude
5 Revolve solid.revolve
6 Sweep solid.sweep
7 SolidLoft solid.loft
8 FusionRibCommand solid.rib
9 FusionWebCommand solid.web
10 EmbossCmd solid.emboss
11 FusionHoleCommand solid.hole
12 FusionThreadCommand solid.thread
13 PrimitiveBox solid.box
14 PrimitiveCylinder solid.cylinder
15 PrimitiveSphere solid.sphere
16 PrimitiveTorus solid.torus
17 PrimitiveCoil solid.coil
18 PrimitivePipe solid.pipe
19 StockModelCommand solid.bounding_solid
20 PatternRectangular solid.pattern.rectangular
21 PatternCircular solid.pattern.circular
22 PatternOnPath solid.pattern.path
23 MirrorCommand solid.mirror
24 FusionSurfaceThickenCommand surface.thicken
25 JointOrigin joint.origin
26 FusionPressPullCommand solid.press_pull
27 FusionFilletEdgesCommand solid.fillet
28 FusionChamferCommand solid.chamfer
29 FusionShellBodyCommand solid.shell
30 FusionDraftCommand solid.draft
31 ModifyScale solid.scale
32 FusionCombineCommand solid.combine
33 FusionOffsetFacesCommand solid.offset_face
34 FusionReplaceFaceCommand solid.replace_face
35 FusionSplitFaceCommand solid.split_face
36 FusionSplitBodyCommand solid.split_body
37 FusionMoveCommand solid.move
38 AlignCmd solid.align
39 FusionDeleteCommand timeline.delete
40 SoftDeleteCommand solid.remove
41 PhysicalMaterialCommand material.assign
42 AppearanceCommand appearance.assign
43 ChangeParameterCommand parameters.change
44 FusionComputeAllCommand timeline.compute_all
45 FusionImportCommandFromToolbar file.insert_step
46 FusionCreateNewComponentCommand component.create
47 JointAssembleCmdNew joint.create
48 JointAsBuiltCmd joint.as_built
49 RigidGroupCmd joint.rigid_group
50 FusionMoveJointsCommand joint.drive
51 FusionMotionRelationshipCommand joint.motion_link
52 FusionMotionStudyCommand motion.study
53 EnableContactSetsCmd contact.enable_sets
54 EnableAllContactCmd contact.enable_all
55 DisableAllContactCmd contact.disable_all
56 ContactSetCmd contact.create
57 FusionStartDesignConfigModeCmd config.configure
58 FusionShowDesignConfigPanelCmd config.table
59 FusionConfigurationRulesCmd config.rules
60 ConstructionPlaneOffsetFromPlaneCommand construct.plane.offset
61 ConstructionPlaneAtAngleCommand construct.plane.at_angle
62 ConstructionTangentPlaneCommand construct.plane.tangent
63 ConstructionMidPlaneCommand construct.plane.midplane
64 ConstructionPlaneFromTwoEdgesCommand construct.plane.two_edges
65 ConstructionPlaneFromThreePointsCommand construct.plane.three_points
66 ConstructionPlaneAlongPathCommand construct.plane.along_path
67 ConstructionAxisThroughCylinderCommand construct.axis.through_cylinder
68 ConstructionAxisNormalToFaceCommand construct.axis.normal_to_face
69 ConstructionAxisFromTwoPlanesCommand construct.axis.two_planes
70 ConstructionAxisThroughTwoPointsCommand construct.axis.two_points
71 ConstructionAxisThroughEdgeCommand construct.axis.edge
72 ConstructionPointFromPointCommand construct.point.vertex
73 ConstructionPointThroughTwoEdgesCommand construct.point.two_edges
74 ConstructionPointFromThreePlanesCommand construct.point.three_planes
75 ConstructionPointFromCircleOrSphereCommand construct.point.center
76 ConstructionPointAtEdgeAndPlaneCommand construct.point.edge_plane
77 ConstructionPointAlongPathCommand construct.point.along_path
78 MeasureCommand inspect.measure
79 InterferenceCheckCommand inspect.interference
80 FusionHalfSectionViewCommand inspect.section
81 FusionCurvatureCombAnalysisCommand inspect.curvature_comb
82 FusionCurvatureMapAnalysisCommand inspect.curvature_map
83 FusionDraftAnalysisCommand inspect.draft
84 FusionEnvironmentMapAnalysisCommand inspect.environment_map
85 FusionIsoCurveAnalysisCommand inspect.isocurve
86 FusionZebraAnalysisCommand inspect.zebra
87 FusionAccessibilityAnalysisCommand inspect.accessibility
88 FusionCenterOfMassCommand inspect.center_of_mass
89 FusionMinimumRadiusAnalysisCommand inspect.minimum_radius
90 FusionAddEditDecalCommand canvas.decal
91 FusionAddCanvasCommand canvas.insert
92 SketchImportSVG sketch.insert_svg
93 ImportDxfFileCommand sketch.insert_dxf
94 ParaMeshInsertAlignCommand file.insert_mesh
95 FusionFastenersCommand parts.fastener
96 SnapshotCmd component.capture_position
97 AsBuiltPositionsCmd component.revert_position
98 DrawPolyline sketch.line
99 SketchMidpointLine sketch.line.midpoint
100 SketchConstrainer sketch.constrainer
101 ShapeRectangleTwoPoint sketch.rectangle.two_point
102 ShapeRectangleThreePoint sketch.rectangle.three_point
103 ShapeRectangleCenter sketch.rectangle.center
104 CircleCenterRadius sketch.circle.center
105 CircleTwoPoint sketch.circle.two_point
106 CircleThreePoint sketch.circle.three_point
107 CircleTanTanRadius sketch.circle.two_tangent
108 CircleThreeTangent sketch.circle.three_tangent
109 ArcThreePoint sketch.arc.three_point
110 ArcCenterTwoPoint sketch.arc.center_point
111 ArcTangent sketch.arc.tangent
112 ShapePolygonCircumscribed sketch.polygon.circumscribed
113 ShapePolygonInscribed sketch.polygon.inscribed
114 ShapePolygonEdge sketch.polygon.edge
115 CircleElipse sketch.ellipse
116 ShapeSlotCenterToCenter sketch.slot.center_to_center
117 ShapeSlotOverall sketch.slot.overall
118 ShapeSlotCenterPoint sketch.slot.center_point
119 ShapeArcSlotThreePoint sketch.slot.arc_three_point
120 ShapeArcSlotCenterTwoPoint sketch.slot.arc_center
121 DrawSpline sketch.spline.fit_point
122 DrawCVMSpline3D sketch.spline.control_point
123 DrawCVMSpline5D sketch.spline.control_point_5
124 ConicCurveCmd sketch.conic
125 DrawPoint sketch.point
126 MTextCmd sketch.text
127 FitCurvesToSectionCommand sketch.fit_curves_to_section
128 MirrorSketchCommand sketch.mirror
129 CircularSketchPatternCommand sketch.pattern.circular
130 RectangularSketchPatternCommand sketch.pattern.rectangular
131 ProjectNewCmd sketch.project
132 IntersectCmd sketch.intersect
133 SpunProfileCmd sketch.spun_profile
134 Include3DGeometry sketch.include_3d
135 ProjectToSurface sketch.project_to_surface
136 IntersectionCurve sketch.intersection_curve
137 SketchIsoparametricCurve sketch.isoparametric_curve
138 SketchDimension sketch.dimension
139 FilletSketchCmd sketch.fillet
140 ChamferSketchEqualDistance sketch.chamfer.equal_distance
141 ChamferSketchDistanceAngle sketch.chamfer.distance_angle
142 ChamferSketchDistanceDistance sketch.chamfer.two_distance
143 BlendG1CurveSketchCmd sketch.blend_curve
144 Offset sketch.offset
145 TrimSketchCmd sketch.trim
146 ExtendSketchCmd sketch.extend
147 BreakSketchCmd sketch.break
148 SketchScaleCmd sketch.scale
149 SketchAutoConstraintAndDimCmd sketch.auto_constrain
150 SketchAutoConstraintAndDimFromDatumCmd sketch.auto_constrain_from_datum
151 ConstraintHorizontalVertical sketch.constraint.horizontal_vertical
152 ConstraintCoincident sketch.constraint.coincident
153 ConstraintTangent sketch.constraint.tangent
154 ConstraintEqual sketch.constraint.equal
155 ConstraintParallel sketch.constraint.parallel
156 ConstraintPerpendicular sketch.constraint.perpendicular
157 ConstraintFix sketch.constraint.fix
158 ConstraintMidPoint sketch.constraint.midpoint
159 ConstraintConcentric sketch.constraint.concentric
160 ConstraintCollinear sketch.constraint.collinear
161 ConstraintSymmetry sketch.constraint.symmetry
162 ConstraintSmooth sketch.constraint.curvature
163 SketchPolygonConstraintCmd sketch.constraint.polygon
164 SketchStop sketch.finish
165 SketchAutoConstrainAndFinish sketch.finish_auto_constrain
166 FusionSurfacePatchCommand surface.patch
167 FusionSurfaceTrimCommand surface.trim
168 FusionExtendCommand surface.extend
169 FusionSurfaceStitchCommand surface.stitch
170 FusionSheetMetalFlangeCommand sheet.flange
171 FusionSheetMetalHemFlangeCommand sheet.hem
172 SheetMetalFoldCmd sheet.fold
173 ConvertToSheetMetalCmd sheet.convert
174 FusionSheetMetalFlatPatternCmd sheet.flat_pattern
175 FusionSheetmetalUnfoldCommand sheet.unfold
176 FusionSheetMetalRulesCommand sheet.manage_rules
177 FusionAssignPlasticRuleCommand plastic.assign_rule
178 FusionManagePlasticRuleCommand plastic.manage_rules
179 FusionBossCommand plastic.boss
180 FusionSnapFitCommand plastic.snap_fit
181 FusionLipCommand plastic.lip
182 FusionRestCommand plastic.rest
183 ConstructionPlanePerpendicularToPlaneCommand construct.plane.perpendicular
184 ParaMeshConvertCommand mesh.convert
+104
View File
@@ -0,0 +1,104 @@
//! `cargo xtask features`: SolidCraft's own feature checklist, `docs/features.md`.
//!
//! The page lists every registered command by area (the first part of its dotted id), with its
//! label, id and toolbar place. It comes only from SolidCraft's command registry
//! (`solvecraft-cli commands`), so it can't drift from what the program does; it compares with
//! nothing else.
use std::path::Path;
use serde_json::Value;
/// Areas in the order the page lists them (id prefix, heading). Other prefixes follow,
/// alphabetically, under their prefix.
const AREAS: &[(&str, &str)] = &[
("sketch", "Sketch"),
("solid", "Solid modelling"),
("surface", "Surfaces"),
("construct", "Construction geometry"),
("sheet", "Sheet metal"),
("plastic", "Plastic parts"),
("component", "Components"),
("joint", "Assembly joints"),
("config", "Configurations"),
("timeline", "Timeline"),
("inspect", "Inspect"),
("file", "Files"),
("doc", "Documents"),
("edit", "Edit"),
];
pub fn run(root: &Path) -> Result<(), String> {
let out = crate::cargo()
.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--", "commands"])
.output()
.map_err(|e| format!("solvecraft-cli: {e}"))?;
if !out.status.success() {
return Err(format!("solvecraft-cli commands failed:\n{}", String::from_utf8_lossy(&out.stderr)));
}
let cmds: Value = serde_json::from_slice(&out.stdout).map_err(|e| format!("commands JSON: {e}"))?;
let list = cmds.as_array().map(Vec::as_slice).unwrap_or_default();
let md = page(list);
std::fs::write(root.join("docs/features.md"), md).map_err(|e| format!("docs/features.md: {e}"))?;
println!("features: {} commands → docs/features.md", list.len());
Ok(())
}
fn area(id: &str) -> &str {
id.split('.').next().unwrap_or_default()
}
/// The checklist page for the registry's commands.
pub fn page(cmds: &[Value]) -> String {
let s = |c: &Value, k: &str| c[k].as_str().unwrap_or_default().to_string();
let mut prefixes: Vec<String> = cmds.iter().map(|c| area(&s(c, "id")).to_string()).collect();
prefixes.sort();
prefixes.dedup();
let mut order: Vec<(String, String)> =
AREAS.iter().filter(|(p, _)| prefixes.iter().any(|x| x == p)).map(|(p, h)| (p.to_string(), h.to_string())).collect();
for p in prefixes.iter().filter(|p| !AREAS.iter().any(|(a, _)| a == p)) {
order.push((p.clone(), format!("`{p}.*`")));
}
let mut md = format!(
"# Features\n\nSolidCraft's commands by area, generated by `cargo xtask features` from the command registry \
(`solvecraft-cli commands`). **{} commands.** Every command runs the same way from the toolbar, a script, \
`solvecraft-cli exec <id> '<json>'`, the control channel and MCP; parameters are in the \
[command reference](book/src/reference/commands.md) (`cargo xtask book`). Status and plans: [ROADMAP](../ROADMAP.md).\n",
cmds.len()
);
for (prefix, heading) in &order {
let in_area: Vec<&Value> = cmds.iter().filter(|c| area(&s(c, "id")) == prefix).collect();
md += &format!("\n## {heading} ({})\n\n| Command | Id | Toolbar |\n|---|---|---|\n", in_area.len());
for c in in_area {
let place = match (s(c, "tab"), s(c, "panel")) {
(t, _) if t.is_empty() => "–".to_string(),
(t, p) if p.is_empty() => t,
(t, p) => format!("{t} › {p}"),
};
let key = c["shortcut"].as_str().map(|k| format!(" ({k})")).unwrap_or_default();
md += &format!("| {}{key} | `{}` | {place} |\n", s(c, "label").replace('|', "/"), s(c, "id"));
}
}
md
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn page_groups_by_area() {
let cmds: Value = serde_json::from_str(
r#"[{"id":"solid.extrude","label":"Extrude","tab":"SOLID","panel":"CREATE","shortcut":"E"},
{"id":"sketch.line","label":"Line","tab":"SKETCH","panel":"CREATE"},
{"id":"view.fit","label":"Fit","tab":"","panel":""}]"#,
)
.unwrap();
let md = page(cmds.as_array().unwrap());
assert!(md.contains("**3 commands.**"));
let (sk, so, other) = (md.find("## Sketch (1)").unwrap(), md.find("## Solid modelling (1)").unwrap(), md.find("## `view.*` (1)").unwrap());
assert!(sk < so && so < other);
assert!(md.contains("| Extrude (E) | `solid.extrude` | SOLID › CREATE |"));
assert!(md.contains("| Fit | `view.fit` | – |"));
}
}
+3 -5
View File
@@ -5,9 +5,9 @@
mod assets;
mod book;
mod features;
mod layers;
mod licences;
mod parity;
mod test;
use std::path::{Path, PathBuf};
@@ -19,9 +19,7 @@ usage: cargo xtask <command>
commands:
layers enforce the crate dependency layering (plan/architecture.md §3)
assets check that every non-code asset file is attributed in ATTRIBUTION.md
parity [--refresh]
recompute Fusion command parity in docs/parity.md (--refresh rebuilds
xtask/data/fusion-catalog.tsv from plan/fusion/menu-tree.json)
features list SolidCraft's commands by area in docs/features.md (from the registry)
oracle [--cli BIN]
replay the reference tests (tests/oracle/*/recipe.json), compare with each
case's expected.json and write docs/oracle.md (--cli: a solvecraft-cli
@@ -46,7 +44,7 @@ fn main() -> ExitCode {
let result = match args.first().map(String::as_str) {
Some("layers") => cmd_layers(),
Some("assets") => assets::run(&root()),
Some("parity") => parity::run(&root(), rest.contains(&"--refresh")),
Some("features") => features::run(&root()),
Some("oracle") => cmd_oracle(rest.iter().position(|a| *a == "--cli").and_then(|i| rest.get(i + 1)).copied()),
Some("book") => book::run(&root(), !rest.contains(&"--no-build")),
Some("licences") => licences::run(&root(), rest.contains(&"--check")),
-220
View File
@@ -1,220 +0,0 @@
//! `cargo xtask parity`: Fusion Design-workspace command parity.
//!
//! `xtask/data/fusion-catalog.tsv` lists the toolbar commands of Fusion's Design workspace as
//! `tab \t panel \t command id \t command name` (ids and names only, nothing else). It is
//! derived from the local, uncommitted `plan/fusion/menu-tree.json` with `--refresh`. A catalog
//! entry is live when SolidCraft registers the command `xtask/data/fusion-ids.tsv` maps its id to
//! (SolidCraft uses its own ids).
use std::path::Path;
use std::process::Command;
use serde_json::Value;
/// Design workspace tabs in the catalog (menu-tree tab id, display name).
const TABS: &[(&str, &str)] = &[
("SolidTab", "SOLID"),
("SketchTab", "SKETCH"),
("SurfaceTab", "SURFACE"),
("ParaMeshOuterTab", "MESH"),
("FormTab", "FORM"),
("SheetMetalTab", "SHEET METAL"),
("PlasticTab", "PLASTIC"),
("AssemblyTab", "ASSEMBLY"),
("ManageTab", "MANAGE"),
("ToolsTab", "UTILITIES"),
];
/// The tabs the headline number counts (now: SOLID and SKETCH).
const HEADLINE: &[&str] = &["SOLID", "SKETCH"];
/// The owner's scope: these tabs (and the PLASTIC subset below) count toward the in-scope
/// figure; the rest of Fusion is deferred and listed separately.
const IN_SCOPE_TABS: &[&str] = &["SOLID", "SKETCH", "ASSEMBLY", "SHEET METAL"];
/// The PLASTIC commands in scope (enclosure features).
/// (SolidCraft ids, matched through the catalog-id map.)
const PLASTIC_SUBSET: &[&str] = &["plastic.boss", "solid.rib", "solid.web", "plastic.lip", "plastic.snap_fit"];
/// Catalog id → SolidCraft id.
fn id_map(s: &str) -> std::collections::HashMap<String, String> {
s.lines()
.filter(|l| !l.starts_with('#') && !l.trim().is_empty())
.filter_map(|l| l.split_once('\t').map(|(a, b)| (a.trim().to_string(), b.trim().to_string())))
.collect()
}
fn in_plastic_subset(e: &Entry, map: &std::collections::HashMap<String, String>) -> bool {
e.tab == "PLASTIC" && map.get(&e.id).is_some_and(|ours| PLASTIC_SUBSET.contains(&ours.as_str()))
}
#[derive(Clone, Debug)]
pub struct Entry {
pub tab: String,
pub panel: String,
pub id: String,
pub name: String,
}
fn clean(s: &str) -> String {
s.replace(['\t', '\n', '\r'], " ").trim().to_string()
}
fn walk(controls: &[Value], defs: &[Value], tab: &str, panel: &str, out: &mut Vec<Entry>) {
for c in controls {
match c["type"].as_str() {
Some("CommandControl") => {
let id = c["command"]["id"].as_str().or(c["id"].as_str()).unwrap_or("");
if id.is_empty() {
continue;
}
let name = c["command"]["name"]
.as_str()
.filter(|n| !n.is_empty())
.or_else(|| defs.iter().find(|d| d["id"].as_str() == Some(id)).and_then(|d| d["name"].as_str()))
.unwrap_or(id);
if !out.iter().any(|e| e.tab == tab && e.id == id) {
out.push(Entry { tab: tab.into(), panel: panel.into(), id: clean(id), name: clean(name) });
}
}
Some("DropDownControl") => walk(c["controls"].as_array().map(Vec::as_slice).unwrap_or(&[]), defs, tab, panel, out),
_ => {}
}
}
}
/// Catalog entries from Fusion's menu-tree JSON.
pub fn from_menu_tree(v: &Value) -> Vec<Entry> {
let defs = v["commandDefinitions"].as_array().map(Vec::as_slice).unwrap_or(&[]);
let mut out = Vec::new();
for (tid, tname) in TABS {
let tab = &v["tabs"][format!("DesignProductType/{tid}")];
for p in tab["panels"].as_array().into_iter().flatten() {
let panel = clean(p["name"].as_str().unwrap_or("")).to_uppercase();
walk(p["controls"].as_array().map(Vec::as_slice).unwrap_or(&[]), defs, tname, &panel, &mut out);
}
}
out
}
pub fn parse_catalog(s: &str) -> Vec<Entry> {
s.lines()
.filter(|l| !l.starts_with('#') && !l.trim().is_empty())
.filter_map(|l| {
let mut it = l.split('\t');
Some(Entry { tab: it.next()?.into(), panel: it.next()?.into(), id: it.next()?.into(), name: it.next().unwrap_or("").into() })
})
.collect()
}
pub fn run(root: &Path, refresh: bool) -> Result<(), String> {
let cat_path = root.join("xtask/data/fusion-catalog.tsv");
if refresh {
let mt = root.join("plan/fusion/menu-tree.json");
let s = std::fs::read_to_string(&mt).map_err(|e| format!("{}: {e}", mt.display()))?;
let v: Value = serde_json::from_str(&s).map_err(|e| format!("menu-tree.json: {e}"))?;
let entries = from_menu_tree(&v);
let mut out = String::from(
"# Fusion Design workspace toolbar: tab, panel, command id, command name (ids and names only).\n# Regenerate with `cargo xtask parity --refresh` (needs the local plan/fusion/menu-tree.json).\n",
);
for e in &entries {
out += &format!("{}\t{}\t{}\t{}\n", e.tab, e.panel, e.id, e.name);
}
std::fs::create_dir_all(root.join("xtask/data")).map_err(|e| e.to_string())?;
std::fs::write(&cat_path, out).map_err(|e| format!("{}: {e}", cat_path.display()))?;
println!("parity: catalog refreshed with {} entries", entries.len());
}
let catalog = parse_catalog(&std::fs::read_to_string(&cat_path).map_err(|e| format!("{}: {e}", cat_path.display()))?);
let out = Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
.current_dir(root)
.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--", "commands"])
.output()
.map_err(|e| format!("solvecraft-cli: {e}"))?;
let cmds: Value = serde_json::from_slice(&out.stdout).map_err(|e| format!("commands JSON: {e}"))?;
let ids: Vec<String> = cmds.as_array().into_iter().flatten().filter_map(|c| c["id"].as_str().map(str::to_string)).collect();
let map_path = root.join("xtask/data/fusion-ids.tsv");
let map = id_map(&std::fs::read_to_string(&map_path).map_err(|e| format!("{}: {e}", map_path.display()))?);
let live = |e: &Entry| map.get(&e.id).is_some_and(|ours| ids.contains(ours));
let in_scope = |e: &Entry| IN_SCOPE_TABS.contains(&e.tab.as_str()) || in_plastic_subset(e, &map);
let pct = |a: usize, b: usize| if b == 0 { 0.0 } else { 100.0 * a as f64 / b as f64 };
let head: Vec<&Entry> = catalog.iter().filter(|e| HEADLINE.contains(&e.tab.as_str())).collect();
let head_live = head.iter().filter(|e| live(e)).count();
let all_live = catalog.iter().filter(|e| live(e)).count();
let scope: Vec<&Entry> = catalog.iter().filter(|e| in_scope(e)).collect();
let scope_live = scope.iter().filter(|e| live(e)).count();
let mut md = format!(
"# Fusion command parity\n\nGenerated by `cargo xtask parity` from `xtask/data/fusion-catalog.tsv` (the toolbar commands of Fusion's Design workspace, ids and names only) and the live command registry (`solvecraft-cli commands`). A command counts as live when SolidCraft registers the same command id. This measures breadth, not depth; see ROADMAP.md and docs/oracle.md for depth.\n\n**In scope (SOLID, SKETCH, ASSEMBLY, SHEET METAL, PLASTIC enclosure subset): {scope_live} / {} commands live ({:.0}%).** SOLID + SKETCH: {head_live} / {} ({:.0}%). Registered commands: {}.\n\nDeferred until further notice (not in the in-scope figure): MESH, FORM, SURFACE beyond what solids need, PCB, render, animation, simulation, manufacture, drawings, MANAGE, UTILITIES and the rest of PLASTIC. All Design tabs together: {all_live} / {} ({:.0}%).\n\n| Tab | Panel | Live | Total | % |\n|---|---|---:|---:|---:|\n",
scope.len(),
pct(scope_live, scope.len()),
head.len(),
pct(head_live, head.len()),
ids.len(),
catalog.len(),
pct(all_live, catalog.len()),
);
let mut groups: Vec<(String, String, usize, usize)> = Vec::new();
for e in &catalog {
let l = usize::from(live(e));
match groups.iter_mut().find(|g| g.0 == e.tab && g.1 == e.panel) {
Some(g) => {
g.2 += l;
g.3 += 1;
}
None => groups.push((e.tab.clone(), e.panel.clone(), l, 1)),
}
}
for (t, p, l, n) in groups.iter().filter(|g| IN_SCOPE_TABS.contains(&g.0.as_str())) {
md += &format!("| {t} | {p} | {l} | {n} | {:.0}% |\n", pct(*l, *n));
}
let plastic: Vec<&Entry> = catalog.iter().filter(|e| in_plastic_subset(e, &map)).collect();
md += &format!(
"| PLASTIC | enclosure subset | {} | {} | {:.0}% |\n",
plastic.iter().filter(|e| live(e)).count(),
plastic.len(),
pct(plastic.iter().filter(|e| live(e)).count(), plastic.len())
);
md += "\n### Deferred tabs\n\n| Tab | Panel | Live | Total | % |\n|---|---|---:|---:|---:|\n";
for (t, p, l, n) in groups.iter().filter(|g| !IN_SCOPE_TABS.contains(&g.0.as_str())) {
md += &format!("| {t} | {p} | {l} | {n} | {:.0}% |\n", pct(*l, *n));
}
md += "\n## Live (SOLID, SKETCH)\n\n";
for e in head.iter().filter(|e| live(e)) {
md += &format!("- {} › {} › {}\n", e.tab, e.panel, e.name);
}
md += "\n## Not yet (SOLID, SKETCH)\n\n";
for e in head.iter().filter(|e| !live(e)) {
md += &format!("- {} › {} › {}\n", e.tab, e.panel, e.name);
}
std::fs::write(root.join("docs/parity.md"), md).map_err(|e| format!("docs/parity.md: {e}"))?;
println!(
"parity: in scope {scope_live}/{} ({:.0}%), SOLID+SKETCH {head_live}/{} ({:.0}%), all tabs {all_live}/{} → docs/parity.md",
scope.len(),
pct(scope_live, scope.len()),
head.len(),
pct(head_live, head.len()),
catalog.len()
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn catalog_from_menu_tree() {
let v: Value = serde_json::from_str(
r#"{"commandDefinitions":[{"id":"B","name":"Bee"}],"tabs":{"DesignProductType/SolidTab":{"panels":[{"name":"Create","controls":[
{"type":"CommandControl","id":"A","command":{"id":"A","name":"Aye"}},
{"type":"SeparatorControl","id":"s"},
{"type":"DropDownControl","id":"d","controls":[{"type":"CommandControl","id":"B","command":{"id":"B"}}]}]}]}}}"#,
)
.unwrap();
let e = from_menu_tree(&v);
assert_eq!(e.len(), 2);
assert_eq!((e[0].tab.as_str(), e[0].panel.as_str(), e[0].id.as_str(), e[0].name.as_str()), ("SOLID", "CREATE", "A", "Aye"));
assert_eq!(e[1].name, "Bee");
let tsv = "# c\nSOLID\tCREATE\tA\tAye\n";
assert_eq!(parse_catalog(tsv).len(), 1);
}
}