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,205 +0,0 @@
1
- ---
2
- skill-group: core
3
- skill-order: 0
4
- skill-tiers: [one-file]
5
- ---
6
-
7
- # ForgeCAD Skill Guide — Concepts & Patterns
8
-
9
- Conceptual knowledge that complements the auto-generated API index. The API index covers every function signature; this file covers the patterns, gotchas, and composition strategies that signatures alone cannot convey.
10
-
11
- ## Core Concepts
12
-
13
- ForgeCAD scripts are JavaScript code that returns geometry. The forge API is globally available — no imports needed.
14
-
15
- ### Basic Structure
16
- ```javascript
17
- const width = param("Width", 50, { min: 20, max: 100, unit: "mm" });
18
- const shape = box(width, 30, 10);
19
- return shape;
20
- ```
21
-
22
- ### Execution Model
23
- - Scripts execute on every parameter change (400ms debounce)
24
- - All operations are **immutable** — they return new shapes, never modify in place
25
- - Must return one of:
26
- - A `Shape` (3D solid)
27
- - A `Sketch` (2D profile — rendered flat on XY plane)
28
- - A `TrackedShape` (3D solid with named faces/edges — auto-unwrapped)
29
- - A `ShapeGroup` (multiple shapes/sketches grouped for joint transforms)
30
- - An `Array` of shapes/sketches/groups (multi-object scene)
31
- - An `Array` of `{ name, shape?, sketch?, color? }` objects (named multi-object scene)
32
-
33
- ### Unions Remove Colors
34
-
35
- `union()` merges into a single solid — individual colors are lost. Return an array of named objects instead:
36
-
37
- ```javascript
38
- // BAD: colors lost after union
39
- return union(red, blue);
40
-
41
- // GOOD: each object keeps its color
42
- return [
43
- { name: "Red Box", shape: red, color: '#ff0000' },
44
- { name: "Blue Box", shape: blue, color: '#0066ff' },
45
- ];
46
- ```
47
-
48
- ### Coordinate System
49
- Z-up right-handed: X = left/right, Y = forward/back, Z = up/down.
50
-
51
- ## Returning Multiple Objects
52
-
53
- ```javascript
54
- return [
55
- { name: "Base", shape: box(100, 100, 5), color: "#888888" },
56
- { name: "Column", shape: cylinder(50, 10).translate(50, 50, 5), color: "#4488cc" },
57
- ];
58
- ```
59
-
60
- Each object must have `name` (string) and `shape` or `sketch`. Optional `color` sets display color.
61
-
62
- ## Positioning & Connectors
63
-
64
- ### Connectors + `.matchTo()` — Primary positioning method
65
-
66
- Define named connectors on parts, then use `matchTo()` for automatic alignment. Connectors are stable (don't shift with geometry changes), semantic (typed and gendered), and oriented (full coordinate frame).
67
-
68
- ```javascript
69
- const bracket = box(40, 10, 60, true).withConnectors({
70
- mount: connector.male("bolt", { origin: [0, -5, 0], axis: [0, -1, 0] }),
71
- });
72
- const wall = box(200, 5, 200, true).withConnectors({
73
- slot: connector.female("bolt", { origin: [50, 2.5, 30], axis: [0, 1, 0] }),
74
- });
75
- const placed = bracket.matchTo(wall, "mount", "slot");
76
- ```
77
-
78
- Query connector distances to derive dimensions:
79
- ```javascript
80
- const pipeLen = frame.connectorDistance('inlet', 'outlet');
81
- ```
82
-
83
- ### `.attachTo()` — Quick bounding-box positioning
84
-
85
- For simple stacking where connectors aren't needed. Uses bounding-box anchors — fast but fragile.
86
-
87
- ```javascript
88
- const column = cylinder(50, 8).attachTo(base, 'top', 'bottom');
89
- ```
90
-
91
- ### `.onFace(parent, face, opts?)`
92
-
93
- Place a shape on a specific face of a parent. Face-local coordinates: `u`/`v` offset from center, `protrude` outward.
94
-
95
- ```javascript
96
- const vent = box(80, 2, 12, true)
97
- .onFace(body, 'front', { v: -15, protrude: 2 });
98
- ```
99
-
100
- **When to use:** `onFace()` for surface details (vents, displays). Connectors for assembly interfaces. `attachTo()` for quick prototyping.
101
-
102
- ## Multi-File Projects
103
-
104
- ### File Types
105
- - `.forge.js` — parametric part/assembly script
106
- - `.forge-notebook.json` — multi-cell notebook
107
- - `.svg` — vector artwork, imported as sketch geometry
108
-
109
- ### Import Function
110
-
111
- Use `require(path, paramOverrides?)` to import any `.forge.js` file. The second argument is optional param overrides.
112
-
113
- ```javascript
114
- const bracket = require("./bracket.forge.js");
115
- const bracket2 = require("./bracket.forge.js", { Width: 100, Thickness: 3 });
116
- ```
117
-
118
- The return value matches what the imported file exports:
119
- - File `return`s a `Shape` → you get a `Shape`
120
- - File `return`s an `Assembly` → you get an `ImportedAssembly`
121
- - File `return`s a `ShapeGroup` → you get a `ShapeGroup`
122
- - File uses `exports.name = value` → you get an object with named properties
123
-
124
- Use `importSvgSketch()` for SVG files (separate function — SVG is a file format loader, not a module import).
125
-
126
- ### Import Rules
127
- - Paths: `./file.forge.js` resolves relative to caller; bare paths resolve from project root
128
- - Param overrides only affect that import call
129
- - Circular imports throw an error
130
- - Each import call is a fresh execution
131
-
132
- ### Placement References
133
-
134
- Attach named reference points/edges/surfaces to shapes for precise cross-file positioning:
135
-
136
- ```javascript
137
- // In part file:
138
- return union(base, post).withReferences({
139
- points: { mount: [0, -16, -4] },
140
- surfaces: { mountingFace: { center: [0, -16, 0], normal: [0, -1, 0] } },
141
- objects: { base, post },
142
- });
143
-
144
- // In assembly file:
145
- const widget = require("./widget.forge.js")
146
- .placeReference("mount", [120, 40, 0]);
147
- const cap = box(18, 18, 8, true)
148
- .attachTo(widget, "objects.post.top", "bottom");
149
- ```
150
-
151
- References survive transforms and import round-trips.
152
-
153
- ### Plain JS Module Imports
154
-
155
- Regular `import`/`require()` works for utility modules. Don't mix explicit exports with top-level `return` in the same module.
156
-
157
- ### Typical Project Structure
158
- ```
159
- my-project/
160
- ├── base-profile.forge.js ← 2D cross-section (returns Sketch)
161
- ├── bracket.forge.js ← extrudes the sketch, adds holes
162
- └── assembly.forge.js ← imports multiple parts, positions them
163
- ```
164
-
165
- ## Compiler-Owned Operations
166
-
167
- ### `shape.shell(thickness, options?)`
168
- Hollows out a solid. Supports `box()`, `cylinder()`, straight `extrude()`. Optional `openFaces: ['top' | 'bottom']`.
169
-
170
- ```javascript
171
- const cup = roundedRect(80, 50, 6, true)
172
- .extrude(30).shell(2.5, { openFaces: ['top'] });
173
- ```
174
-
175
- ### `shape.hole(face, options)`
176
- Circular hole anchored to a face. `depth` omitted = through-hole. Supports `counterbore`/`countersink`, `upToFace`, two-sided `extent`.
177
-
178
- ```javascript
179
- const body = block
180
- .hole('front', { diameter: 8, u: 0, v: 2 })
181
- .hole('top', { diameter: 6, u: -18, v: 10, depth: 10 })
182
- .hole('top', { diameter: 5, u: 18, v: 10, upToFace: exitFace,
183
- counterbore: { diameter: 9, depth: 4 } });
184
- ```
185
-
186
- ### `shape.cutout(sketch, options?)`
187
- Cut-extrude using a sketch placed with `Sketch.onFace(...)`. Same extent options as `hole()`. Supports `taperScale` on circle/rect/roundedRect profiles.
188
-
189
- ### `sheetMetal(options)`
190
- Sheet-metal builder: base panel → `.flange()` → `.cutout()` → `.folded()` or `.flatPattern()`.
191
-
192
- ## Group Patterns
193
-
194
- `group()` combines shapes without merging — colors and identities preserved.
195
-
196
- ```javascript
197
- const housing = group(
198
- { name: 'Shell', shape: shell },
199
- { name: 'Lid', shape: lid },
200
- ).withReferences({
201
- points: { mountCenter: [0, 30, 20] },
202
- });
203
- ```
204
-
205
- ShapeGroup supports all transforms, placement references, and child access (`.child("Name")`).
@@ -1,186 +0,0 @@
1
- # Specs — Named Requirement Bundles
2
-
3
- A **Spec** is a named, reusable group of `verify.*` checks. When you call `spec.check(shape)`, every `verify` call inside the check function is tagged with the spec name and displayed as a collapsible section in the Checks panel.
4
-
5
- ## Why Specs
6
-
7
- Bare `verify.*` calls produce a flat list. With 15 checks across 3 different concerns, the panel becomes hard to scan. Specs add structure:
8
-
9
- - **Grouping** — related checks appear under a named, collapsible header
10
- - **Reusability** — one spec, applied to many shapes: `printable.check(bracket); printable.check(standoff);`
11
- - **Composability** — combine independent specs: check fit, strength, and printability separately
12
- - **Separation** — define what "good" looks like before building geometry (spec-first / TDD workflow)
13
-
14
- ## Quick Start
15
-
16
- ```javascript
17
- // Define a spec
18
- const printable = spec("Fits printer bed", (shape) => {
19
- verify.notEmpty("Has geometry", shape);
20
- const bb = shape.boundingBox();
21
- const size = [bb.max[0] - bb.min[0], bb.max[1] - bb.min[1], bb.max[2] - bb.min[2]];
22
- verify.lessThan("Width < 220mm", size[0], 220);
23
- verify.lessThan("Depth < 220mm", size[1], 220);
24
- verify.lessThan("Height < 250mm", size[2], 250);
25
- });
26
-
27
- // Build something
28
- const part = box(100, 80, 40);
29
-
30
- // Check it
31
- printable.check(part);
32
-
33
- return part;
34
- ```
35
-
36
- The Checks panel shows:
37
-
38
- ```
39
- ▼ ✓ Fits printer bed — 4/4
40
- ✓ Has geometry
41
- ✓ Width < 220mm
42
- ✓ Depth < 220mm
43
- ✓ Height < 250mm
44
- ```
45
-
46
- ## API
47
-
48
- ### `spec(name, checkFn)`
49
-
50
- Create a named spec.
51
-
52
- | Parameter | Type | Description |
53
- |-----------|------|-------------|
54
- | `name` | `string` | Display name in the Checks panel |
55
- | `checkFn` | `(...args) => void` | Function that calls `verify.*` methods |
56
-
57
- Returns a `Spec` object with a `.check()` method.
58
-
59
- ### `Spec.check(...args)`
60
-
61
- Run the spec's check function. Any `verify.*` calls inside are grouped under the spec name.
62
-
63
- Returns a `SpecResult`:
64
-
65
- ```typescript
66
- interface SpecResult {
67
- name: string; // Spec name
68
- passed: number; // Checks that passed
69
- total: number; // Total checks
70
- results: VerificationResult[];
71
- }
72
- ```
73
-
74
- The return value is optional — you can ignore it and just let the Checks panel show the results.
75
-
76
- ## Patterns
77
-
78
- ### Reusable Spec — Apply to Multiple Shapes
79
-
80
- ```javascript
81
- const structural = spec("Structural", (shape) => {
82
- verify.greaterThan("Min volume", shape.volume(), 500);
83
- verify.notEmpty("Not degenerate", shape);
84
- });
85
-
86
- structural.check(bracket);
87
- structural.check(plate);
88
- structural.check(standoff);
89
- // Each call adds a "Structural" group to the panel
90
- ```
91
-
92
- ### Multi-Shape Spec — Check Relationships
93
-
94
- Specs can accept multiple arguments for checking relationships between parts:
95
-
96
- ```javascript
97
- const fitSpec = spec("Assembly fit", (partA, partB) => {
98
- verify.notColliding("No interference", partA, partB, 10);
99
- verify.minClearance("Min gap 0.3mm", partA, partB, 0.3, 10);
100
- verify.parallel("Mating faces aligned",
101
- partA.face('top'), partB.face('bottom'));
102
- });
103
-
104
- fitSpec.check(bracket, standoff);
105
- ```
106
-
107
- ### Importable Spec Library
108
-
109
- Specs can live in separate `.forge.js` files and be imported via `require()`:
110
-
111
- ```javascript
112
- // specs/printers.forge.js
113
- const prusaMK3S = spec("Prusa MK3S", (shape) => {
114
- const bb = shape.boundingBox();
115
- const size = [bb.max[0]-bb.min[0], bb.max[1]-bb.min[1], bb.max[2]-bb.min[2]];
116
- verify.lessThan("X", size[0], 220);
117
- verify.lessThan("Y", size[1], 220);
118
- verify.lessThan("Z", size[2], 250);
119
- });
120
-
121
- return { prusaMK3S };
122
- ```
123
-
124
- ```javascript
125
- // my-part.forge.js
126
- const { prusaMK3S } = require("./specs/printers.forge.js");
127
- const part = box(100, 80, 40);
128
- prusaMK3S.check(part);
129
- return part;
130
- ```
131
-
132
- ### Reference Geometry in Specs
133
-
134
- Specs can create shapes internally as test fixtures — these are used only for checking and never rendered:
135
-
136
- ```javascript
137
- const fitsInEnclosure = spec("Fits in enclosure", (shape) => {
138
- // Reference geometry — not returned, not rendered
139
- const enclosure = box(200, 150, 100);
140
- const overlap = shape.intersect(enclosure);
141
-
142
- verify.that("Fully contained", () =>
143
- Math.abs(overlap.volume() - shape.volume()) < 1
144
- );
145
- verify.minClearance("2mm clearance", shape, enclosure, 2.0, 20);
146
- });
147
- ```
148
-
149
- ### Spec-First Workflow (TDD for CAD)
150
-
151
- Write specs before geometry. Watch checks go from red to green as you build:
152
-
153
- ```javascript
154
- // Step 1: Define what we need
155
- const caseSpec = spec("Phone case", (shape) => {
156
- verify.notEmpty("Has geometry", shape);
157
- verify.that("Is hollow (< 40% fill)", () => {
158
- const bb = shape.boundingBox();
159
- const bboxVol = (bb.max[0]-bb.min[0]) * (bb.max[1]-bb.min[1]) * (bb.max[2]-bb.min[2]);
160
- return shape.volume() < bboxVol * 0.4;
161
- });
162
- verify.greaterThan("Weighs under 30g (PLA)", 30, shape.volume() * 0.00124);
163
- });
164
-
165
- // Step 2: Build iteratively — specs tell you when you're done
166
- const myCase = box(75, 150, 12).shell(2, { openFaces: ['top'] });
167
- caseSpec.check(myCase);
168
- return myCase;
169
- ```
170
-
171
- ## Mixing Specs and Plain Verify Calls
172
-
173
- Plain `verify.*` calls (outside any spec) still work. They appear ungrouped below the spec sections:
174
-
175
- ```javascript
176
- // Grouped under spec name
177
- printable.check(part);
178
-
179
- // Ungrouped — shown separately
180
- verify.greaterThan("Custom check", someValue, 10);
181
- ```
182
-
183
- ## See Also
184
-
185
- - **[Verification demo](../../../examples/api/verification-demo.forge.js)** — all `verify.*` methods
186
- - **[Spec demo](../../../examples/api/spec-demo.forge.js)** — `spec()` in action