forgecad 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +2 -11
  2. package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-DAu1C1ST.js} +250 -151
  3. package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
  4. package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-Gc_BCdqC.js} +269 -143
  5. package/dist/assets/EditorApp-D9bJvtf7.js +11338 -0
  6. package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-DG1-oUSV.css} +459 -87
  7. package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-CEO8XbV8.js} +2 -4
  8. package/dist/assets/LandingPage-CdCuEOdC.js +451 -0
  9. package/dist/assets/PricingPage-BSrxu6d7.js +232 -0
  10. package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-FUCSIRq6.js} +129 -5
  11. package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-KoR0SNKq.js} +6770 -2914
  12. package/dist/assets/{index-2hfs_ub0.css → index-CyVd1D4D.css} +227 -53
  13. package/dist/assets/{Viewport-CoB46f5R.js → index-wTEK39at.js} +31385 -6439
  14. package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
  15. package/dist/assets/{manifold-CqNMHHKO.js → manifold-B1sGWdYk.js} +4 -3
  16. package/dist/assets/{manifold-Cce9wRFz.js → manifold-D7o0N50J.js} +1 -1
  17. package/dist/assets/{manifold-D6BeHIOo.js → manifold-G5sBaXzi.js} +1 -1
  18. package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-DYcRHhv9.js} +6798 -3341
  19. package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
  20. package/dist/docs-raw/generated/assembly.md +691 -112
  21. package/dist/docs-raw/generated/concepts.md +1225 -1400
  22. package/dist/docs-raw/generated/core.md +464 -1412
  23. package/dist/docs-raw/generated/curves.md +593 -117
  24. package/dist/docs-raw/generated/lib.md +38 -748
  25. package/dist/docs-raw/generated/output.md +139 -245
  26. package/dist/docs-raw/generated/sheet-metal.md +473 -21
  27. package/dist/docs-raw/generated/sketch.md +553 -349
  28. package/dist/docs-raw/generated/viewport.md +345 -303
  29. package/dist/docs-raw/generated/wood.md +104 -0
  30. package/dist/index.html +2 -2
  31. package/dist/sitemap.xml +6 -6
  32. package/dist-cli/chunk-PZ5AY32C.js +10 -0
  33. package/dist-cli/chunk-PZ5AY32C.js.map +1 -0
  34. package/dist-cli/forgecad.js +9435 -5407
  35. package/dist-cli/forgecad.js.map +1 -0
  36. package/dist-cli/solver-FV7TJZGI.js +365 -0
  37. package/dist-cli/solver-FV7TJZGI.js.map +1 -0
  38. package/dist-skill/CONTEXT.md +3186 -7145
  39. package/dist-skill/SKILL-dev.md +21 -63
  40. package/dist-skill/SKILL.md +12 -56
  41. package/dist-skill/docs/API/core/concepts.md +16 -98
  42. package/dist-skill/docs/CLI/export.md +91 -0
  43. package/dist-skill/docs/CLI/projects.md +107 -0
  44. package/dist-skill/docs/CLI/studio_publishing.md +52 -0
  45. package/dist-skill/docs/CLI/validation.md +66 -0
  46. package/dist-skill/docs/generated/assembly.md +691 -112
  47. package/dist-skill/docs/generated/core.md +464 -1412
  48. package/dist-skill/docs/generated/curves.md +593 -117
  49. package/dist-skill/docs/generated/lib.md +38 -748
  50. package/dist-skill/docs/generated/output.md +139 -245
  51. package/dist-skill/docs/generated/sheet-metal.md +473 -21
  52. package/dist-skill/docs/generated/sketch.md +553 -349
  53. package/dist-skill/docs/generated/viewport.md +345 -303
  54. package/dist-skill/docs/generated/wood.md +104 -0
  55. package/dist-skill/docs/guides/coordinate-system.md +11 -17
  56. package/dist-skill/docs/guides/geometry-conventions.md +13 -70
  57. package/dist-skill/docs/guides/modeling-recipes.md +22 -195
  58. package/dist-skill/docs/guides/positioning.md +88 -147
  59. package/dist-skill/docs-dev/API/core/concepts.md +51 -0
  60. package/dist-skill/docs-dev/API/core/sdf-advanced.md +92 -0
  61. package/dist-skill/docs-dev/API/core/sdf-primitives.md +58 -0
  62. package/dist-skill/docs-dev/API/core/sdf-workflow.md +42 -0
  63. package/dist-skill/docs-dev/CLI/export.md +91 -0
  64. package/dist-skill/docs-dev/CLI/projects.md +107 -0
  65. package/dist-skill/docs-dev/CLI/studio_publishing.md +52 -0
  66. package/dist-skill/docs-dev/CLI/validation.md +66 -0
  67. package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
  68. package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
  69. package/dist-skill/{docs → docs-dev}/coding.md +1 -3
  70. package/dist-skill/docs-dev/generated/assembly.md +771 -0
  71. package/dist-skill/docs-dev/generated/core.md +775 -0
  72. package/dist-skill/docs-dev/generated/curves.md +688 -0
  73. package/dist-skill/docs-dev/generated/lib.md +50 -0
  74. package/dist-skill/docs-dev/generated/output.md +234 -0
  75. package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
  76. package/dist-skill/docs-dev/generated/sketch.md +801 -0
  77. package/dist-skill/docs-dev/generated/viewport.md +486 -0
  78. package/dist-skill/docs-dev/generated/wood.md +104 -0
  79. package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
  80. package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
  81. package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
  82. package/dist-skill/docs-dev/guides/positioning.md +151 -0
  83. package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
  84. package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
  85. package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
  86. package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
  87. package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
  88. package/examples/api/attachTo-basics.forge.js +5 -5
  89. package/examples/api/boolean-operations.forge.js +3 -3
  90. package/examples/api/bounding-box-visualizer.forge.js +2 -2
  91. package/examples/api/clone-duplicate.forge.js +1 -1
  92. package/examples/api/colors-union-vs-array.forge.js +6 -6
  93. package/examples/api/connector-assembly.forge.js +4 -4
  94. package/examples/api/connector-basics.forge.js +2 -2
  95. package/examples/api/extrude-options.forge.js +4 -10
  96. package/examples/api/feature-created-faces.forge.js +6 -10
  97. package/examples/api/fillet-showcase.forge.js +1 -1
  98. package/examples/api/folded-service-panel-cover.forge.js +2 -2
  99. package/examples/api/group-test.forge.js +1 -1
  100. package/examples/api/group-vs-union.forge.js +1 -1
  101. package/examples/api/highlight-debug.forge.js +4 -0
  102. package/examples/api/js-module-pillars.js +1 -1
  103. package/examples/api/js-module-scene.js +2 -2
  104. package/examples/api/mesh-import-slats.forge.js +1 -1
  105. package/examples/api/pointAlong-orientation.forge.js +1 -1
  106. package/examples/api/profile-2020-b-slot6.forge.js +0 -1
  107. package/examples/api/route-perimeter-flange.forge.js +1 -1
  108. package/examples/api/sdf-rover-demo.forge.js +10 -10
  109. package/examples/api/sketch-on-face-demo.forge.js +2 -2
  110. package/examples/api/sketch-regions.forge.js +4 -4
  111. package/examples/api/transition-curves.forge.js +1 -1
  112. package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
  113. package/examples/api/variable-sweep-test.forge.js +2 -2
  114. package/examples/api/wood-joinery.forge.js +60 -0
  115. package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
  116. package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
  117. package/examples/experiments/drone-arm.forge.js +53 -0
  118. package/examples/furniture/adjustable-table.forge.js +2 -2
  119. package/examples/furniture/bathroom.forge.js +11 -11
  120. package/examples/furniture/chair.forge.js +1 -1
  121. package/examples/generative/crystal-growth.forge.js +2 -2
  122. package/examples/generative/frost-spires.forge.js +3 -3
  123. package/examples/generative/golden-spiral-tower.forge.js +3 -3
  124. package/examples/mechanical/3d-printer.forge.js +28 -28
  125. package/examples/mechanical/5-finger-robot-hand.forge.js +15 -15
  126. package/examples/mechanical/airplane-propeller.forge.js +2 -2
  127. package/examples/mechanical/fillet-enclosure.forge.js +1 -1
  128. package/examples/mechanical/headphone-hanger-v2.forge.js +2 -2
  129. package/examples/mechanical/robot_hand.forge.js +15 -15
  130. package/examples/mechanical/robot_hand_2.forge.js +9 -9
  131. package/examples/products/bottle.forge.js +1 -1
  132. package/examples/products/chess-set.forge.js +19 -19
  133. package/examples/products/classical-piano.forge.js +11 -11
  134. package/examples/products/clock.forge.js +12 -12
  135. package/examples/products/iphone.forge.js +8 -8
  136. package/examples/products/laptop.forge.js +15 -15
  137. package/examples/products/liquid-soap-dispenser.forge.js +18 -18
  138. package/examples/products/origami-fish.forge.js +8 -6
  139. package/examples/products/spiderman-cake.forge.js +4 -4
  140. package/examples/toolbox/bolted-joint.forge.js +2 -2
  141. package/package.json +7 -4
  142. package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
  143. package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
  144. package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
  145. package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
  146. package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
  147. package/dist/assets/index-1CYp3zUp.js +0 -1455
  148. package/dist/docs-raw/CLI.md +0 -865
  149. package/dist-skill/docs/API/API.md +0 -1666
  150. package/dist-skill/docs/API/README.md +0 -37
  151. package/dist-skill/docs/API/assembly/assembly.md +0 -617
  152. package/dist-skill/docs/API/core/edge-queries.md +0 -130
  153. package/dist-skill/docs/API/core/parameters.md +0 -122
  154. package/dist-skill/docs/API/core/reserved-terms.md +0 -137
  155. package/dist-skill/docs/API/core/sdf.md +0 -326
  156. package/dist-skill/docs/API/core/skill-cli.md +0 -194
  157. package/dist-skill/docs/API/core/skill-guide.md +0 -205
  158. package/dist-skill/docs/API/core/specs.md +0 -186
  159. package/dist-skill/docs/API/core/topology.md +0 -372
  160. package/dist-skill/docs/API/entities.md +0 -268
  161. package/dist-skill/docs/API/output/bom.md +0 -58
  162. package/dist-skill/docs/API/output/brep-export.md +0 -87
  163. package/dist-skill/docs/API/output/dimensions.md +0 -67
  164. package/dist-skill/docs/API/output/export.md +0 -110
  165. package/dist-skill/docs/API/output/gcode.md +0 -195
  166. package/dist-skill/docs/API/runtime/viewport.md +0 -420
  167. package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
  168. package/dist-skill/docs/API/sketch/anchor.md +0 -37
  169. package/dist-skill/docs/API/sketch/booleans.md +0 -91
  170. package/dist-skill/docs/API/sketch/core.md +0 -73
  171. package/dist-skill/docs/API/sketch/extrude.md +0 -62
  172. package/dist-skill/docs/API/sketch/on-face.md +0 -104
  173. package/dist-skill/docs/API/sketch/operations.md +0 -78
  174. package/dist-skill/docs/API/sketch/path.md +0 -75
  175. package/dist-skill/docs/API/sketch/primitives.md +0 -146
  176. package/dist-skill/docs/API/sketch/regions.md +0 -80
  177. package/dist-skill/docs/API/sketch/text.md +0 -108
  178. package/dist-skill/docs/API/sketch/transforms.md +0 -65
  179. package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
  180. package/dist-skill/docs/CLI.md +0 -865
  181. package/dist-skill/docs/INDEX.md +0 -94
  182. package/dist-skill/docs/RELEASING.md +0 -55
  183. package/dist-skill/docs/cli-monetization.md +0 -111
  184. package/dist-skill/docs/deployment.md +0 -281
  185. package/dist-skill/docs/generated/concepts.md +0 -2112
  186. package/dist-skill/docs/internals/shape-from-slices.md +0 -152
  187. package/dist-skill/docs/platform/admin.md +0 -45
  188. package/dist-skill/docs/platform/architecture.md +0 -79
  189. package/dist-skill/docs/platform/auth.md +0 -110
  190. package/dist-skill/docs/platform/email.md +0 -67
  191. package/dist-skill/docs/platform/projects.md +0 -111
  192. package/dist-skill/docs/platform/sharing.md +0 -90
  193. package/dist-skill/docs/runbook.md +0 -345
@@ -1,865 +0,0 @@
1
- ---
2
- skill-group: cli
3
- skill-order: 1
4
- skill-tiers: [standard]
5
- ---
6
-
7
- # ForgeCAD CLI
8
-
9
- ## Architecture
10
-
11
- All CLI tools share the **same forge engine** as the browser UI. There is one source of truth for geometry logic — no code duplication. See [CODING.md → Project Structure](CODING.md#project-structure) for the full source tree.
12
-
13
- **Browser** imports via `src/forge/index.ts` → re-exports from `headless.ts`.
14
- **CLI tools** import directly from `src/forge/headless.ts`.
15
-
16
- The key function is `runScript(code, fileName, allFiles)` — it wraps user code in a `Function()` sandbox with the entire forge API injected, and transpiles project files so standard JS `import` / `export` / `require(...)` work for shared utility modules. CLI scripts just call `init()` + `runScript()` and work with the results.
17
-
18
- ## When to use what
19
-
20
- ForgeCAD has two overlapping interfaces. Use the right one for each context.
21
-
22
- | Context | Use | Avoid |
23
- |---------|-----|-------|
24
- | **Using ForgeCAD as a tool** | `forgecad *` commands | `npm run *` |
25
- | **Developing ForgeCAD itself** | `npm run dev` (live reload), `npm run build` (prod) | — |
26
- | **CI / publishing** | `npm run build && npm run test` | forgecad CLI (not installed in CI) |
27
- | **AI agents in this repo** | `forgecad *` commands only | `npm run build`, `npm run build:cli` |
28
-
29
- The CLI is always available after `npm install` — no explicit build step needed.
30
-
31
- ### Dev server vs production server
32
-
33
- | Command | What it does | Requires |
34
- |---------|-------------|---------|
35
- | `forgecad dev [path]` | Vite dev server, live reload | nothing beyond `npm install` |
36
- | `forgecad studio [path]` | Fast static server for the production build | `dist/` built via `npm run build` |
37
- | `npm run dev` | Same as `forgecad dev` — standard JS project entry point | nothing |
38
-
39
- Use `forgecad dev` during active development of forge scripts. Use `forgecad studio` to verify the production build or serve it to others.
40
-
41
- ## Install
42
-
43
- ```bash
44
- npm install -g forgecad
45
- ```
46
-
47
- For developers working on ForgeCAD itself:
48
-
49
- ```bash
50
- npm install
51
- npm link
52
- ```
53
-
54
- The npm package ships a minified JS bundle (`cli.js`) — no source maps. A compiled native binary build script exists (`npm run build:binary`) for future Homebrew distribution but is not the primary channel.
55
-
56
- ## Licensing
57
-
58
- Some commands require a ForgeCAD Pro license. Free-tier commands work without any key.
59
-
60
- ```bash
61
- forgecad license # Show current license status
62
- forgecad license activate <key> # Activate a license key
63
- forgecad license deactivate # Remove license from this machine
64
- ```
65
-
66
- | Tier | What's included |
67
- |------|----------------|
68
- | **Free** | dev, studio, run, render, export stl/3mf/svg, all checks, debug |
69
- | **Pro** | export step/brep, render-hq, capture gif/mp4, gcode, report, cutting-layout, sdf, urdf, sketch-pdf |
70
-
71
- Pro commands show a `[Pro]` badge in `forgecad help` and display a clear upgrade message when invoked without a license.
72
-
73
- See [cli-monetization.md](project/cli-monetization.md) for the full monetization strategy.
74
-
75
- ### Shell Autocomplete
76
-
77
- ForgeCAD now ships shell completion scripts in the usual modern-tool style:
78
-
79
- ```bash
80
- forgecad completion bash
81
- forgecad completion zsh
82
- forgecad completion fish
83
- ```
84
-
85
- Quick install:
86
-
87
- ```bash
88
- # bash
89
- echo 'source <(forgecad completion bash)' >> ~/.bashrc
90
-
91
- # zsh
92
- mkdir -p ~/.zsh/completions
93
- forgecad completion zsh > ~/.zsh/completions/_forgecad
94
- echo 'fpath=(~/.zsh/completions $fpath)' >> ~/.zshrc
95
- echo 'autoload -Uz compinit && compinit' >> ~/.zshrc
96
-
97
- # fish
98
- mkdir -p ~/.config/fish/completions
99
- forgecad completion fish > ~/.config/fish/completions/forgecad.fish
100
- ```
101
-
102
- The completions are contextual:
103
-
104
- - nested subcommands such as `forgecad notebook view` and `forgecad export step`
105
- - command-specific flags and common enum values
106
- - ForgeCAD file suggestions where a command expects `.forge.js` or `.forge-notebook.json`
107
-
108
- ## Available Commands
109
-
110
- ### Authentication & Account
111
-
112
- ```bash
113
- forgecad login # Interactive email/password login
114
- forgecad login --server http://localhost:5174 # Login to local dev server
115
- forgecad logout # Clear stored credentials
116
- forgecad whoami # Show user, server, and license status
117
- ```
118
-
119
- Credentials are stored in `~/.forgecad/auth.json`.
120
-
121
- ### Project Management
122
-
123
- ```bash
124
- # Create and sync
125
- forgecad project init "My Project" # Create on server + link current directory
126
- forgecad project init "My Project" --slug my-project --visibility public
127
- forgecad project clone my-project # Download into ./my-project/
128
- forgecad project push [--force] # Upload local changes
129
- forgecad project pull [--force] # Download remote changes
130
- forgecad project status # Show local vs remote diff
131
-
132
- # Inspect and modify
133
- forgecad project list # List all your projects
134
- forgecad project info # Show current project details (name, visibility, files, URL)
135
- forgecad project rename "New Name" # Rename the project
136
- forgecad project set-visibility public # Change visibility (private|shared|public)
137
- forgecad project delete [--force] # Permanently delete project and all files
138
- forgecad project open # Open in browser
139
- ```
140
-
141
- Projects are stored on forgecad.io. Local projects are linked to their remote counterpart via `forgecad.json`.
142
-
143
- ### File Management (Remote)
144
-
145
- Operate directly on remote project files without the push/pull cycle:
146
-
147
- ```bash
148
- forgecad file list [path] # List remote files (optional path prefix filter)
149
- forgecad file read <path> # Print file contents to stdout
150
- forgecad file save <path> # Upload local file to remote (same relative path)
151
- forgecad file save <path> --content "code here" # Save inline content
152
- cat model.forge.js | forgecad file save model.forge.js --stdin # Pipe content from stdin
153
- forgecad file delete <path> [--force] # Delete remote file
154
- forgecad file rename <old> <new> # Rename or move a remote file
155
- forgecad file mkdir <path> # Create a remote directory
156
- forgecad file copy <source-slug> <path> [--dest <dest-path>] # Copy from another project
157
- ```
158
-
159
- These commands require the current directory to be an initialized ForgeCAD project (has `forgecad.json`).
160
-
161
- ### Member Management
162
-
163
- ```bash
164
- forgecad project members # List project members
165
- forgecad project add-member alice@example.com # Add as editor (default)
166
- forgecad project add-member bob@example.com --role viewer
167
- forgecad project remove-member alice@example.com
168
- forgecad project set-role bob@example.com editor
169
- ```
170
-
171
- Roles: **owner** (full control, manage members), **editor** (read/write files), **viewer** (read-only).
172
-
173
- ### Publishing & Sharing
174
-
175
- ```bash
176
- forgecad publish model.forge.js --title "My Model" # Publish model, get shareable URL
177
- forgecad publish model.forge.js --no-sync # Publish without auto-pushing project
178
- forgecad shares list # List all published models with URLs
179
- forgecad shares delete <share-id> [--force] # Unpublish a shared model
180
- forgecad link <gist-url-or-id> # Generate share link from GitHub Gist
181
- ```
182
-
183
- Published models are viewable at `forgecad.io/m/<shareId>`. Shares are **live references** to project files — they always reflect the current version, not a frozen snapshot. Publishing requires being inside a project directory. The project is auto-synced first (unless `--no-sync`).
184
-
185
- ### New File from Template
186
-
187
- ```bash
188
- forgecad new mypart # Part template (default)
189
- forgecad new bracket --template sketch # Constrained sketch template
190
- forgecad new robot --template assembly # Multi-part assembly template
191
- ```
192
-
193
- ### Studio & Dev Server
194
-
195
- ```bash
196
- # Development — Vite dev server, live reload, no build needed
197
- forgecad dev
198
- forgecad dev ~/cad/gearbox
199
- forgecad dev --blank --port 4173
200
-
201
- # Production — static server, requires dist/ (npm run build)
202
- forgecad studio
203
- forgecad studio ~/cad/gearbox
204
- forgecad studio --blank --port 4173
205
-
206
- # Web / embeddable mode — always dev server, no filesystem
207
- forgecad web
208
- forgecad web --open
209
- ```
210
-
211
- Both `forgecad dev` and `forgecad studio` accept the same options:
212
- - `--blank` — open without any project folder
213
- - `--port <n>` — bind to a specific port (default: 5173)
214
- - `--host [host]` — expose on the network
215
- - `--open` — open a browser tab automatically
216
- - `--strict-port` — fail if the port is already in use
217
-
218
- `forgecad open` is an alias for `forgecad studio`.
219
-
220
- ### Notebook Cells (server-backed)
221
-
222
- Forge notebooks live in `.forge-notebook.json` files and behave like lightweight Jupyter notebooks for ForgeCAD code cells.
223
-
224
- The browser and CLI both use the Vite server for notebook execution. The CLI does not run Forge locally for notebook cells; it auto-starts or reuses the Forge server, sends the cell code, then prints the returned output summary.
225
-
226
- Append a new code cell and run it immediately in one command:
227
-
228
- ```bash
229
- forgecad notebook examples/demo.forge-notebook.json --code "show(box(40, 20, 10));"
230
- ```
231
-
232
- If the target notebook file does not exist yet, append mode auto-creates it first with the default ForgeCAD notebook structure, then adds the new cell.
233
-
234
- Or pipe a larger cell in through stdin:
235
-
236
- ```bash
237
- cat /tmp/cell.js | forgecad notebook examples/demo.forge-notebook.json
238
- ```
239
-
240
- Re-run the last preview cell, or a specific cell id:
241
-
242
- ```bash
243
- forgecad notebook examples/demo.forge-notebook.json
244
- forgecad notebook run examples/demo.forge-notebook.json <cell-id>
245
- ```
246
-
247
- View the notebook in the terminal without dumping raw JSON:
248
-
249
- ```bash
250
- forgecad notebook view examples/demo.forge-notebook.json
251
- forgecad notebook view examples/demo.forge-notebook.json preview
252
- forgecad notebook view examples/demo.forge-notebook.json 2
253
- ```
254
-
255
- `view` is local-only. It parses the notebook JSON and renders notebook metadata, numbered source lines, and stored outputs for each cell. The optional selector accepts a 1-based cell number, an exact cell id, or `preview`.
256
-
257
- `run`/`view` expect the notebook file to already exist. Auto-creation only applies to append flows (`--code`, `--file`, stdin, or the explicit `append` subcommand).
258
-
259
- Export a notebook into a plain `.forge.js` script:
260
-
261
- ```bash
262
- forgecad notebook export examples/demo.forge-notebook.json
263
- forgecad notebook export examples/demo.forge-notebook.json out/demo-from-notebook.forge.js
264
- ```
265
-
266
- If you already have a Forge server running, point the CLI at it:
267
-
268
- ```bash
269
- forgecad notebook examples/demo.forge-notebook.json --server http://localhost:5173 --code "show(box(40, 20, 10));"
270
- ```
271
-
272
- Notebook paths are resolved from the shell working directory before the CLI calls the server, so the server's opened project root does not add an extra path prefix.
273
-
274
- Notebook cell behavior:
275
-
276
- - Cells share state top-to-bottom
277
- - `show(value)` pins the geometry that should stay visible in the viewport
278
- - A trailing expression is also treated as the cell value
279
- - Cell outputs are written back into the notebook JSON, similar to Jupyter
280
-
281
- For the `forgecad` entrypoints below, passing a `.forge-notebook.json` uses that notebook's preview cell. That means you can inspect with `view`, validate with `run`, and render or capture the current preview without exporting first.
282
-
283
- ### Script Validation
284
-
285
- ```bash
286
- forgecad run examples/cup.forge.js
287
- forgecad run examples/api/notebook-iteration.forge-notebook.json
288
- forgecad run examples/cup.forge.js --debug-imports
289
- forgecad run examples/cup.forge.js --param "Wall Thickness=3"
290
- forgecad run examples/cup.forge.js --param "Show Lid=0"
291
- forgecad run examples/cup.forge.js --param "Pan Style=wok"
292
- forgecad run examples/constraints/06-complex-spectrogram.forge.js --solver-debug-out tmp/spectrogram-debug
293
- ```
294
-
295
- Runs a `.forge.js` or notebook preview cell in the real runtime and prints object stats, diagnostics, and execution time.
296
-
297
- `--param "Key=Value"` overrides script parameters for that run. It supports:
298
-
299
- - numeric `param()` values such as `"Wall Thickness=3"`
300
- - boolean `boolParam()` values using `1` or `0`
301
- - string `choiceParam()` values using the displayed label, such as `"Pan Style=wok"`
302
-
303
- `--debug-imports` adds an import trace (source file, target file, overrides, return type, success/error phase), useful when debugging `require()` import behavior.
304
-
305
- `--solver-debug-out <dir>` enables the Rust planner's constructive transcript and SVG snapshots for every solved sketch in that run, then writes a reusable artifact bundle to disk:
306
-
307
- - `README.md` summary at the output root
308
- - one subdirectory per sketch
309
- - `constructive-transcript.md` with the step-by-step planner story
310
- - `svg/*.svg` snapshots keyed to transcript steps
311
-
312
- ### SVG Export (no browser needed)
313
-
314
- ```bash
315
- forgecad export svg examples/constraints/01-fully-constrained-rect.forge.js [output.svg]
316
- ```
317
-
318
- Runs a sketch `.forge.js` script in Node.js using the real forge engine and outputs SVG. No browser, no Puppeteer — pure Node.
319
-
320
- **How it works:** Initializes the Manifold WASM kernel, runs the script through `runScript()`, extracts the Sketch result, converts polygons to SVG paths.
321
-
322
- ### STEP / BREP Export (exact subset, Python + CadQuery)
323
-
324
- ```bash
325
- forgecad export step examples/api/brep-exportable.forge.js
326
- forgecad export brep examples/api/brep-exportable.forge.js
327
-
328
- # Optional overrides:
329
- forgecad export step examples/api/brep-exportable.forge.js --output out/demo.step
330
- forgecad export step examples/api/brep-exportable.forge.js --python 3.11
331
- forgecad export step examples/api/brep-exportable.forge.js --uv /custom/path/to/uv
332
- forgecad export step examples/chess-set.forge.js --allow-faceted
333
- ```
334
-
335
- This exporter is `uv`-first. `cli/forge-brep-export.py` carries inline dependency metadata, so `uv run` provisions CadQuery automatically for the exporter environment.
336
-
337
- By default this exporter is exact-subset only. It does **not** silently convert arbitrary triangle meshes back into fake BREP. Instead, Forge lowers compile-covered geometry into the `cadquery-occt` compiler target and exports that exact subset through CadQuery/OpenCascade.
338
-
339
- If you pass `--allow-faceted`, unsupported closed mesh solids are exported as explicit faceted OCCT solids. This keeps mesh-heavy designs exportable to STEP/BREP, but that fallback is tessellation-driven rather than exact replay.
340
-
341
- The maintained feature matrix lives in [`docs/permanent/API/output/brep-export.md`](API/output/brep-export.md).
342
-
343
- If any returned solid object falls outside the exact subset, the CLI fails with a reason instead of silently exporting degraded geometry. When a scene mixes solids and 2D sketches, the exact solids export and the sketch-only objects are skipped with a warning.
344
-
345
- With `--allow-faceted`, mesh-solid blockers that still lack an exact replay plan are exported as faceted solids instead of failing. The CLI prints which objects used the fallback.
346
-
347
- For coverage runs across many examples, use the `uv` matrix scripts:
348
-
349
- ```bash
350
- uv run scripts/brep/matrix.py --format step examples
351
- uv run scripts/brep/matrix.py --format brep examples
352
- uv run scripts/brep/rerun_failures.py tmp/brep-matrix-step-20260306T120000Z.json
353
- ```
354
-
355
- These scripts use the repo-local `.venv-brep/.venv/bin/python` by default, run exports through a bounded parallel worker pool, and write JSON reports under `tmp/`.
356
-
357
- ### G-code Toolpath Export
358
-
359
- ```bash
360
- forgecad export gcode examples/gcode/parametric-vase.forge.js
361
- forgecad export gcode examples/gcode/parametric-vase.forge.js --output out/vase.gcode
362
- ```
363
-
364
- Exports a G-code toolpath script directly to `.gcode` for FDM 3D printing. The script must return a `GCodeBuilder` instance (created via the `gcode()` factory function).
365
-
366
- This is a **toolpath scripting API**, not a slicer. You define print movements directly in code — enabling parametric vases, mathematical surfaces, non-planar paths, and other geometries that conventional slicers cannot produce.
367
-
368
- **How it works:** Initializes the forge kernel, runs the script, extracts the `GCodeBuilder` result, and writes the generated G-code text to disk. Prints segment count, estimated time, filament usage, and bounding box.
369
-
370
- **Options:**
371
- - `--output <path>` / `-o <path>` — Output file path (default: replaces `.forge.js` with `.gcode`)
372
-
373
- **Demo scripts:**
374
- - `examples/gcode/parametric-vase.forge.js` — Sine-wave modulated continuous spiral vase
375
- - `examples/gcode/spiral-tower.forge.js` — Twisted hexagonal polygon tower
376
- - `examples/gcode/math-surface.forge.js` — Non-planar bowl with wave rim
377
- - `examples/gcode/lissajous-vase.forge.js` — Lissajous curve vase with morphing profile
378
-
379
- Preview these scripts in ForgeCAD's interactive viewport. The current `forgecad render` CLI expects shape outputs and does not render `GCodeBuilder` scenes yet.
380
-
381
- See [`docs/permanent/API/output/gcode.md`](API/output/gcode.md) for the dedicated G-code mode guide and full `GCodeBuilder` API reference.
382
-
383
- ### SDF Robot Export (Gazebo package)
384
-
385
- ```bash
386
- forgecad export sdf examples/api/sdf-rover-demo.forge.js
387
-
388
- # Optional output directory:
389
- forgecad export sdf examples/api/sdf-rover-demo.forge.js --output out/forge_scout
390
- ```
391
-
392
- This exporter writes a Gazebo-friendly package workspace:
393
-
394
- - `models/<model-name>/model.sdf`
395
- - `models/<model-name>/model.config`
396
- - `models/<model-name>/meshes/*.stl`
397
- - `worlds/<world-name>.sdf` when the script requests a demo world
398
- - `manifest.json` with topic names, link/joint mappings, and exporter warnings
399
-
400
- The script must call `robotExport({...})` with an `assembly(...)` graph. The exporter uses the declared parts + joints directly; it does **not** try to infer a robot from flattened scene meshes.
401
-
402
- When `world.generateDemoWorld` and `world.keyboardTeleop.enabled` are on, the exported world includes both:
403
-
404
- - Gazebo's GUI `KeyPublisher` plugin
405
- - server-side `TriggeredPublisher` bindings that map arrow keys to the diff-drive `cmd_vel` topic
406
-
407
- Recommended launch flow:
408
-
409
- ```bash
410
- export GZ_SIM_RESOURCE_PATH="$PWD/out/forge_scout/models${GZ_SIM_RESOURCE_PATH:+:$GZ_SIM_RESOURCE_PATH}"
411
-
412
- # Terminal 1: server
413
- gz sim -s -r out/forge_scout/worlds/forge_scout_trial.sdf
414
-
415
- # Terminal 2: GUI client using the same world layout
416
- gz sim -g out/forge_scout/worlds/forge_scout_trial.sdf
417
- ```
418
-
419
- Notes:
420
-
421
- - On macOS, use the split `-s` / `-g` flow above. `gz sim <world.sdf>` is not supported there.
422
- - Click the 3D view so it has keyboard focus, then use `W` / `X` for forward / reverse, `A` / `D` to rotate, `Q` / `E` / `Z` / `C` for diagonals, and `S` or `Space` to stop.
423
- - For older exports created before the GUI plugin was added, load `Key Publisher` manually from the Gazebo GUI plugins menu.
424
-
425
- Current behavior:
426
-
427
- - Per-link geometry is exported as STL mesh assets
428
- - Collision geometry reuses the same mesh unless `collision: 'none'` is set on a link
429
- - Link mass comes from `massKg`, else `densityKgM3 * volume`, else a default density
430
- - Inertia is an approximate box fit based on link bounds
431
- - Coupled joints are currently rejected
432
- - Parts without geometry are currently rejected
433
-
434
- ### PNG Render (requires Chrome)
435
-
436
- ```bash
437
- forgecad render examples/cup.forge.js [output.png]
438
- forgecad render examples/api/notebook-iteration.forge-notebook.json [output.png]
439
- forgecad render examples/cup.forge.js out/scene.png --scene '{"camera":{"projectionMode":"perspective","position":[200,-160,120],"target":[0,0,20],"up":[0,0,1]},"objects":{"obj-2":{"visible":false},"obj-3":{"opacity":0.35}}}'
440
- ```
441
-
442
- Renders 3D shapes to PNG images from multiple camera angles. Uses Puppeteer to launch headless Chrome with WebGL for Three.js rendering.
443
-
444
- When the input is a notebook, `forgecad render` renders the notebook's preview cell.
445
-
446
- **How it works:**
447
- 1. `cli/forge-render.mjs` — Node launcher script. Auto-starts Vite dev server if not running, launches Puppeteer.
448
- 2. `cli/render.html` + `cli/render.ts` — Loaded in the browser by Puppeteer. Imports from `src/forge/headless.ts`, runs the script, builds a Three.js scene, renders from multiple angles.
449
- 3. Screenshots are captured as base64 PNG and saved to disk.
450
-
451
- **Environment variables:**
452
-
453
- | Variable | Default | Description |
454
- |----------|---------|-------------|
455
- | `FORGE_ANGLES` | `front,side,top,iso` | Camera angles to render |
456
- | `FORGE_SIZE` | `1024` | Image size in pixels |
457
- | `FORGE_PORT` | `5173` | Vite dev server port |
458
- | `CHROME_PATH` | Auto-detected | Chrome/Chromium executable path |
459
-
460
- **CLI options:**
461
- - `--angles <front,side,top,iso>` — standard angles to render
462
- - `--size <px>` — output size override
463
- - `--port <n>` — Vite port override
464
- - `--camera <spec>` — exact camera pose, e.g. `proj=perspective;pos=120,80,120;target=0,0,0;up=0,0,1`
465
- - `--scene <json>` — full scene state copied from the viewport, including camera plus object visibility/opacity/color overrides
466
- - `--background <color>` — background override
467
- - `--chrome-path <path>` — Chrome executable path override
468
-
469
- **Camera angles:** `front` (−Y), `back` (+Y), `side` (+X), `top` (+Z), `iso` (diagonal)
470
-
471
- ### Animated Capture (GIF or MP4, requires Chrome)
472
-
473
- ```bash
474
- forgecad capture gif examples/cup.forge.js [output.gif]
475
- forgecad capture mp4 examples/cup.forge.js [output.mp4]
476
- forgecad capture gif examples/api/notebook-assembly-debug.forge-notebook.json --list
477
- forgecad capture mp4 examples/api/runtime-joints-view.forge.js out/step.mp4 --capture animation --animation Step
478
- forgecad capture gif examples/3d-printer.forge.js out/section.gif --cut-plane "Front Section"
479
- ```
480
-
481
- Creates high-quality animated captures from the real Forge viewport renderer:
482
- - Orbit captures with optional wireframe pass
483
- - Fixed-camera animation captures for `jointsView()` clips
484
- - Named cut-plane captures
485
- - Exact camera replay via `--camera`
486
- - Full viewport scene replay via `--scene`
487
-
488
- When the input is a notebook, `forgecad capture gif` / `forgecad capture mp4` capture the notebook's preview cell.
489
-
490
- **How it works:**
491
- 1. Auto-starts (or reuses) the Vite dev server.
492
- 2. Loads `cli/render.html` in headless Chrome.
493
- 3. Runs the script once, then captures frames from the same scene while applying the selected animation, cut planes, and camera pose.
494
- 4. Encodes with `ffmpeg` when available:
495
- - GIF: palettegen/paletteuse for much better colors
496
- - MP4: H.264 via `libx264`
497
- 5. Falls back to the pure-JS GIF encoder only when `ffmpeg` is unavailable.
498
-
499
- **Options:**
500
- - `--format <gif|mp4>` — output format
501
- - `--capture <orbit|animation>` — moving orbit camera or fixed animation camera
502
- - `--animation <name>` — select one `jointsView()` clip
503
- - `--animation-loops <n>` — repeat the chosen clip
504
- - `--cut-plane <name>` — enable a named cut plane (repeatable)
505
- - `--camera <spec>` — exact camera pose, e.g. `proj=perspective;pos=120,80,120;target=0,0,0;up=0,0,1`
506
- - `--scene <json>` — full scene state copied from the viewport, including camera plus object visibility/opacity/color overrides
507
- - `--render-mode <solid|wireframe>` — primary render mode
508
- - `--wireframe-pass` / `--no-wireframe-pass` — enable/disable the extra wireframe pass (off by default)
509
- - `--size <px>` — output frame resolution (default `960`)
510
- - `--pixel-ratio <n>` — render supersampling factor (default `2`)
511
- - `--fps <n>` — capture frame rate (default `24`)
512
- - `--frames-per-turn <n>` — frames per full orbit pass (default `100`)
513
- - `--hold-frames <n>` — freeze frames before each pass (default `6`)
514
- - `--pitch <deg>` — orbit elevation override
515
- - `--background <color>` — background color (default `#252526`)
516
- - `--quality <default|live|high>` — Forge geometry quality preset for export (default `high`)
517
- - `--encoder <auto|ffmpeg|js>` — GIF encoder strategy
518
- - `--crf <n>` — MP4 quality for `libx264` (default `18`)
519
- - `--list` — print the script's available animation clips and cut planes
520
- - `--port <n>` — Vite port (default `5173`)
521
- - `--chrome-path <path>` — Chrome executable path override
522
- - `--ffmpeg-path <path>` — ffmpeg executable path override
523
-
524
- **Environment variables:**
525
- - `FORGE_CAPTURE_SIZE`
526
- - `FORGE_CAPTURE_PIXEL_RATIO`
527
- - `FORGE_CAPTURE_FPS`
528
- - `FORGE_CAPTURE_FRAMES_PER_TURN`
529
- - `FORGE_CAPTURE_HOLD_FRAMES`
530
- - `FORGE_CAPTURE_PITCH_DEG`
531
- - `FORGE_CAPTURE_BACKGROUND`
532
- - `FORGE_CAPTURE_QUALITY`
533
- - `FORGE_CAPTURE_ANIMATION_LOOPS`
534
- - `FORGE_CAPTURE_CRF`
535
- - `FFMPEG_PATH`
536
- - Legacy `FORGE_GIF_*` vars are still honored as fallbacks
537
- - `FORGE_PORT`
538
- - `CHROME_PATH`
539
-
540
- **UI scene handoff:**
541
- - The View Panel exposes a `Camera` section.
542
- - Use `Copy CLI --scene` to grab the current viewport framing plus per-object scene overrides and paste it directly into `render`, `capture gif`, or `capture mp4`.
543
-
544
- ### PDF Report (2D drawing pack)
545
-
546
- ```bash
547
- forgecad export report examples/cup.forge.js [output.pdf]
548
- forgecad export report examples/cup.forge.js [output.pdf] --dim-angle-tol 18
549
- ```
550
-
551
- Generates a searchable-text PDF report with multiple projected drawing views:
552
- - Bill of Materials page (auto-summed from script `bom()` entries)
553
- - Combined model page (front/right/top/isometric)
554
- - Disassembled component pages (same view set per unique component geometry; repeated identical items collapse into one page)
555
- - Auto-generated detail continuation pages for elongated/high-detail views (separate pages, not overlayed)
556
- - `dim()` annotations included per view only when their axis aligns with that view's projection plane axes
557
-
558
- BOM aggregation rules:
559
- - Each `bom(quantity, description, { unit })` call contributes one raw entry
560
- - Report export groups by `key` (if provided) else by normalized `description + unit`
561
- - Quantities are summed per group and rendered as line items in the BOM table
562
-
563
- Component dimension ownership for disassembled pages:
564
- - Preferred: explicit binding via `dim(..., { component: \"Part Name\" })`
565
- - Imported-part ownership: `dim(..., { currentComponent: true })` to pin to the owning returned component instance (no bbox heuristic)
566
- - Other-component ownership: `dim(..., { component: \"Tabletop\" })`
567
- - If multiple owners are bound (e.g. `currentComponent: true` plus another component), it is treated as shared and stays on the overview page
568
- - Fallback: automatic ownership only when both dimension endpoints are unambiguously inside exactly one returned component bounding box
569
- - Ambiguous dimensions are intentionally skipped for disassembled pages
570
-
571
- Optional report flag:
572
- - `--dim-angle-tol <degrees>`: include dimensions whose projected direction is within this many degrees of the nearest view axis (default: `12`)
573
-
574
- ### STL Export (from browser)
575
-
576
- STL export is available in the browser UI via the Export panel. Binary STL format.
577
-
578
- ### Parameter Validation
579
-
580
- ```bash
581
- forgecad check params examples/shoe-rack-doors.forge.js [--samples 10]
582
- ```
583
-
584
- Samples each parameter across its range and checks for runtime errors, degenerate geometry (volume ≈ 0), and new collisions between parts. Skips intra-group collisions when assembly groups are used.
585
-
586
- **Options:**
587
- - `--samples N` — Number of sample points per parameter (default: 8)
588
-
589
- **Output example:**
590
- ```
591
- ✓ Baseline: 6 objects, 12 params
592
- ✓ Checked 91 parameter samples (8 per param)
593
-
594
- ⚠ Found 8 issues across 4 parameters:
595
-
596
- Parameter "Bottom Left Door":
597
- 💥 New collision at values: -120.0, -102.9
598
- Bottom Left Door ∩ Frame (shared vol: 2561.9mm³)
599
- ```
600
-
601
- ### Transform/Assembly Invariant Check
602
-
603
- ```bash
604
- forgecad check transforms
605
- ```
606
-
607
- Runs fast math-level invariants to catch transform order and frame composition regressions before they leak into examples.
608
-
609
- ### Compiler Snapshot Check
610
-
611
- ```bash
612
- forgecad check compiler
613
- forgecad check compiler --case segmented-runtime-hints
614
- forgecad check compiler --update
615
- ```
616
-
617
- Runs curated compiler regression cases and compares them against committed snapshots.
618
- This is a unit-style invariant check, not just a debugger convenience.
619
- The ordinary multi-feature part corpus lives in [`examples/compiler-corpus/README.md`](../../examples/compiler-corpus/README.md).
620
-
621
- Each snapshot records:
622
- - Forge compile plans
623
- - CadQuery/OCCT lowerings
624
- - export routing decisions
625
- - quantized runtime Manifold mesh summaries
626
- - quantized compiler-lowered Manifold mesh summaries
627
-
628
- This check also fails if:
629
- - a plan-covered shape or sketch no longer matches its compiler-lowered runtime output
630
- - export manifests drift away from the per-object compiler routing decisions
631
- - exact/faceted support claims stop matching the lowered artifacts and diagnostics
632
-
633
- ### Query Propagation Snapshot Check
634
-
635
- ```bash
636
- forgecad check query-propagation
637
- forgecad check query-propagation --update
638
- ```
639
-
640
- Runs focused topology-rewrite query-propagation snapshots without dumping the
641
- entire compiler scene. This keeps supported, ambiguous, and intentionally
642
- unsupported rewrite semantics reviewable as the propagation layer evolves.
643
-
644
- Each snapshot records:
645
- - the propagated shape objects that actually carry topology-rewrite metadata
646
- - exact versus faceted routing outcomes for those objects
647
- - deterministic rewrite-operation ordering
648
- - preserved and created query summaries
649
- - explicit ambiguity/unsupported diagnostic codes
650
-
651
- This check also fails if:
652
- - a defended propagation case loses the expected preserved or created query shape
653
- - a known unsupported rewrite stops reporting its explicit diagnostic boundary
654
- - a multi-feature corpus part stops surfacing the expected rewrite ordering
655
-
656
- ### Example Architecture Gate
657
-
658
- ```bash
659
- forgecad check examples
660
- forgecad check examples --family api-parts --family compiler-corpus
661
- forgecad check examples --example examples/api/brep-exportable.forge.js
662
- ```
663
-
664
- Runs the checked example manifest for the entire `examples/` tree.
665
-
666
- The manifest currently lives in `cli/example-manifest/` and covers every:
667
-
668
- - `.forge.js`
669
- - `.forge-notebook.json`
670
-
671
- The command always verifies manifest coverage first, so it fails if:
672
-
673
- - a new example file was added without classification
674
- - a checked manifest entry points at a missing file
675
- - an example's assigned validation path fails
676
- - a `part` example's declared route expectation no longer matches the compiler report
677
-
678
- Current example classes:
679
-
680
- - `part`: runtime execution plus optional exact/faceted route assertions on the selected primary shapes
681
- - `assembly`: runtime solve + scene emission, not exact-route parity
682
- - `runtime-scene`: viewport/report/runtime examples that still need to execute successfully
683
- - `sketch`: sketch payload validation via the sketch export path
684
- - `notebook`: preview-cell validation for `.forge-notebook.json`
685
- - `experimental`: temporary fenced examples that still have to run
686
-
687
- The gate dispatches by declared validation path, not just by class label:
688
-
689
- - `part-runtime`: execute and then enforce any declared exact/faceted route contract
690
- - `assembly-runtime`: execute and validate solved-scene/assembly-owned runtime behavior
691
- - `runtime-scene`: execute as a viewport/report/runtime scene without treating it as part-route evidence
692
- - `sketch-svg`: render returned sketch payloads through the sketch SVG path
693
- - `notebook-preview`: materialize and execute the notebook preview cell
694
- - `experimental-runtime`: execute only, while the example stays outside the active architecture claim
695
-
696
- For non-part entries, the manifest can also pin specific runtime surfaces that
697
- must remain available to repo checks, such as BOM entries, cut planes,
698
- `jointsView()` controls, grouped scene structure, or collected
699
- `robotExport(...)` data.
700
-
701
- Current part route states:
702
-
703
- - `exact`: selected primary shapes must stay on the exact compiler route
704
- - `faceted`: exact must stay blocked and allow-faceted must succeed with diagnostics
705
- - `holdout`: runtime-checked, but intentionally outside the exact-route claim because the example still mixes route outcomes or depends on a documented unsupported capability; this is a temporary recovery state and should normally trend back to zero
706
-
707
- Successful runs also print the current temporary fence list, including each
708
- remaining `holdout` or `experimental` entry's blocker and follow-up task, so
709
- the command output can be used directly in a phase-entry review.
710
-
711
- Use `--family` when a task owns only one manifest lane, and `--example` when you
712
- want to debug a single checked artifact.
713
-
714
- ### Invariant Test Suite
715
-
716
- ```bash
717
- forgecad check suite
718
- npm test
719
- npm run test:examples
720
- npm run test:compiler
721
- npm run test:compiler:update
722
- npm run test:query-propagation
723
- npm run test:query-propagation:update
724
- ```
725
-
726
- ForgeCAD's current unit-test surface is assertion-based CLI checks, not a separate Vitest/Jest harness.
727
-
728
- The important entrypoints are:
729
- - `npm test` runs the repo invariant suite (`transforms`, `dimensions`, `placement`, `js-modules`, `brep`, `compiler`, `query-propagation`, `examples`, `api`)
730
- - `npm run test:examples` runs the example architecture gate across the checked `examples/` manifest
731
- - `npm run test:compiler` runs just the compiler snapshot/invariant suite
732
- - `npm run test:compiler:update` refreshes committed compiler snapshots after an intentional change
733
- - `npm run test:query-propagation` runs the focused topology-rewrite query-propagation snapshots
734
- - `npm run test:query-propagation:update` refreshes those query-propagation snapshots after an intentional change
735
- - `forgecad check suite` is the CLI equivalent of the invariant suite runner
736
-
737
- ### Dimension Propagation Invariant Check
738
-
739
- ```bash
740
- forgecad check dimensions
741
- ```
742
-
743
- Runs shape-level invariants for dimension metadata propagation across:
744
- - transform APIs (`translate`, `rotate`, `transform`, `scale`, `mirror`, `rotateAround`)
745
- - copy/style APIs (`clone`, `color`, `setColor`)
746
- - boolean APIs (`add/subtract/intersect`, plus `union/difference/intersection`)
747
- - import runtime path (`require(...).color(...).translate(...)`)
748
-
749
- ### Dimension Debugger
750
-
751
- ```bash
752
- forgecad debug dimensions /path/to/file.forge.js [--all]
753
- forgecad debug dimensions /path/to/file.forge.js [--all] [--dim-angle-tol 12]
754
- ```
755
-
756
- Prints:
757
- - total object count
758
- - total dimension count
759
- - per-view visibility counts (`front/right/top/iso`) using report angle tolerance
760
- - report ownership routing (`combined` vs `component:<name>`) per dimension
761
- - per-object approximate dimension ownership (both endpoints inside object bbox)
762
- - a dimension coordinate list (first 20 by default, `--all` for full dump)
763
-
764
- ### Compiler Debugger
765
-
766
- ```bash
767
- forgecad debug compiler /path/to/file.forge.js
768
- forgecad debug compiler /path/to/file.forge.js --compact
769
- ```
770
-
771
- Prints JSON for the current script's compiler state, including:
772
- - per-object compile plans
773
- - CadQuery/OCCT lowering diagnostics and lowered plans
774
- - faceted fallback eligibility
775
- - runtime Manifold summaries
776
- - compiler-lowered Manifold summaries
777
-
778
- ### Local Branch Cleanup
779
-
780
- ```bash
781
- uv run cli/forge-prune-local-branches.py
782
- uv run cli/forge-prune-local-branches.py --dry-run
783
- uv run cli/forge-prune-local-branches.py --base mainline
784
- ```
785
-
786
- This is a `uv`-backed Python utility for repository housekeeping. It finds local branches with no matching remote branch that are already merged into the selected base ref, shows them in a Rich terminal UI, then prompts one by one before deleting anything.
787
-
788
- Behavior:
789
- - Deletes with `git branch -d`, not force-delete
790
- - Removes linked worktrees first when the branch is checked out in a secondary worktree
791
- - Requires an explicit `force` choice if one of those linked worktrees is dirty
792
- - Refuses to touch the current worktree, the primary worktree, or prunable/missing worktree entries
793
- - `--path` lets you point at any location inside the target repository
794
-
795
- ## Adding New CLI Commands
796
-
797
- 1. Create or extend a module under `cli/`
798
- 2. Import from `../src/forge/headless`
799
- 3. Call `await init()` to load the WASM kernel
800
- 4. Use `runScript(code, fileName, allFiles)` to execute user scripts
801
- 5. Register the new subcommand in `cli/forgecad.ts`
802
-
803
- ### Minimal Example
804
-
805
- ```typescript
806
- #!/usr/bin/env node
807
- import { readFileSync } from 'fs';
808
- import { init, runScript } from '../src/forge/headless';
809
-
810
- const code = readFileSync(process.argv[2], 'utf-8');
811
-
812
- await init();
813
- const result = runScript(code, 'main.forge.js', {});
814
-
815
- if (result.error) {
816
- console.error(result.error);
817
- process.exit(1);
818
- }
819
-
820
- for (const obj of result.objects) {
821
- if (obj.shape) {
822
- console.log(`${obj.name}: volume=${obj.shape.volume().toFixed(1)}mm³`);
823
- }
824
- if (obj.sketch) {
825
- console.log(`${obj.name}: area=${obj.sketch.area().toFixed(1)}mm²`);
826
- }
827
- if (obj.toolpath) {
828
- console.log(`${obj.name}: ${obj.toolpath.segments.length} G-code segments`);
829
- }
830
- }
831
- ```
832
-
833
- ### Cross-file imports
834
-
835
- When running scripts that use `require()` / `importSvgSketch()` or plain JS module imports, pass all project files (or at least all files reachable by imports), keyed by project-relative path. This supports root-relative and relative imports, utility `.js` modules, and `.svg` assets (`./assets/logo.svg`):
836
-
837
- ```typescript
838
- import { readdirSync, readFileSync } from 'fs';
839
-
840
- const allFiles: Record<string, string> = {};
841
- for (const f of readdirSync(scriptDir)) {
842
- if (f.endsWith('.forge.js') || f.endsWith('.js') || f.endsWith('.svg')) {
843
- allFiles[f] = readFileSync(join(scriptDir, f), 'utf-8');
844
- }
845
- }
846
-
847
- const result = runScript(code, 'main.forge.js', allFiles);
848
- ```
849
-
850
- For utility modules that want explicit ForgeCAD imports instead of globals, use the virtual runtime module:
851
-
852
- ```javascript
853
- import { box, union } from "forgecad";
854
- ```
855
-
856
- Use `require("./file.forge.js", { Param: value })` for model/sketch files when you want ForgeCAD-specific behavior like param override scopes. Use `importSvgSketch()` for SVG assets.
857
-
858
- ## Dependencies
859
-
860
- | Package | Purpose | Context |
861
- |---------|---------|---------|
862
- | `forgecad` | Installable CLI binary (`forgecad ...`) | Runtime package |
863
- | `puppeteer-core` | Headless Chrome for PNG/GIF/MP4 rendering | Runtime dependency |
864
- | `manifold-3d` | Geometry kernel (WASM) | Works in both Node and browser |
865
- | `three` | 3D rendering (used by render.ts) | Loaded in browser context by Puppeteer |