forgecad 0.10.5 → 0.11.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.
- package/dist/assets/{AdminPage-raksfnNA.js → AdminPage-B1nIvqLS.js} +1 -1
- package/dist/assets/{BenchmarkPage-DP3RxhPs.js → BenchmarkPage-YZJbw5nd.js} +1 -1
- package/dist/assets/{BlogPage-D7Dos-vl.js → BlogPage-DIWRApKS.js} +1 -1
- package/dist/assets/{DocsPage-DO1kvBns.js → DocsPage-ClL6X1hR.js} +2 -22
- package/dist/assets/{EditorApp-DQJmcmRT.js → EditorApp-CYBDvSyT.js} +575 -119
- package/dist/assets/{EmbedViewer-DFDUhOma.js → EmbedViewer-Dmfu_LIw.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-DbE_tp8-.js → LandingPageProofDriven-XYTiYxfM.js} +1 -1
- package/dist/assets/{LegalPage-CominSso.js → LegalPage-D5Z3CscF.js} +1 -1
- package/dist/assets/{PricingPage-CcVIN9yj.js → PricingPage-BP4lIGio.js} +1 -1
- package/dist/assets/{SettingsPage-DLWcP289.js → SettingsPage-D3bcPBsC.js} +1 -1
- package/dist/assets/{app-xW3hOdq9.js → app-BKjogwIZ.js} +2192 -231
- package/dist/assets/{backendInit-mDHk97u7.js → backendInit-6a9-ilom.js} +76448 -75066
- package/dist/assets/cli/{render--SIU27W_.js → render-CMNudGb0.js} +3 -3
- package/dist/assets/{constructionHistoryWorker-uEe_Q7Kg.js → constructionHistoryWorker-BuZgc606.js} +6985 -6706
- package/dist/assets/{evalWorker-BqyDHDcI.js → evalWorker-DQ82ueGu.js} +40862 -39497
- package/dist/assets/{inspectWorker-UXMxlcR8.js → inspectWorker-Cuby2qfT.js} +2078 -478
- package/dist/assets/{jointPose-bYMlwU3v.js → jointPose-CFql5I-u.js} +1 -1
- package/dist/assets/{manifold-CyOV5B9S.js → manifold-02pmr7O7.js} +2 -2
- package/dist/assets/{manifold-BR7UYI4P.js → manifold-C6KU0oII.js} +1 -1
- package/dist/assets/{manifold-D4d5NQst.js → manifold-P1yF3GKn.js} +1 -1
- package/dist/assets/{reportWorker-DsaICZsn.js → reportWorker-kg065BVL.js} +85183 -78309
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/AI/usage.md +6 -8
- package/dist/docs-raw/CLI.md +10 -10
- package/dist/docs-raw/component-model.md +28 -9
- package/dist/docs-raw/generated/concepts.md +13 -4
- package/dist/docs-raw/generated/core.md +244 -56
- package/dist/docs-raw/generated/curves.md +13 -0
- package/dist/docs-raw/generated/runtime-names.md +2 -2
- package/dist/docs-raw/guides/inspection-bundles.md +1 -1
- package/dist/docs-raw/guides/structural-fea.md +11 -0
- package/dist/docs-raw/skills/forgecad-build-model.md +70 -147
- package/dist/docs-raw/skills/forgecad-image-prompt.md +1 -1
- package/dist/docs-raw/skills/forgecad-project-sync.md +3 -3
- package/dist/docs-raw/skills/forgecad-reconstruct-cad-file.md +2 -2
- package/dist/docs-raw/skills/forgecad-reconstruct-from-images.md +4 -5
- package/dist/docs-raw/skills/forgecad.md +3 -1
- package/dist/docs-raw/skills/index.md +1 -5
- package/dist/docs-raw/welcome.md +3 -4
- package/dist/index.html +1 -1
- package/dist/llms.txt +1 -2
- package/dist/sitemap.xml +15 -15
- package/dist-cli/{check-compiler-7YAHVXYM.js → check-compiler-UJWUEIDC.js} +1 -1
- package/dist-cli/{check-query-propagation-ZRR6IOJW.js → check-query-propagation-O2EPDJSY.js} +1 -1
- package/dist-cli/{chunk-VNM67DIV.js → chunk-MNDROM7T.js} +77145 -75767
- package/dist-cli/forgecad.js +1145 -441
- package/dist-skill/CONTEXT.md +429 -64
- package/dist-skill/SKILL.md +3 -1
- package/dist-skill/docs/API/core/concepts.md +31 -4
- package/dist-skill/docs/CLI.md +10 -10
- package/dist-skill/docs/generated/core.md +240 -57
- package/dist-skill/docs/generated/curves.md +13 -0
- package/dist-skill/docs/generated/runtime-names.md +2 -2
- package/dist-skill/docs/guides/inspection-bundles.md +1 -1
- package/dist-skill/docs/guides/manual-parameters.md +130 -0
- package/dist-skill/docs/guides/structural-fea.md +11 -0
- package/dist-skill/library/README.md +0 -4
- package/dist-skill/library/forgecad-build-model/SKILL.md +57 -150
- package/dist-skill/library/forgecad-build-model/references/inspection-feedback.md +58 -0
- package/dist-skill/library/forgecad-build-model/references/module-contracts.md +53 -0
- package/dist-skill/library/forgecad-build-model/references/parameter-controls.md +22 -0
- package/dist-skill/library/forgecad-build-model/references/readiness-review.md +43 -0
- package/dist-skill/library/forgecad-build-model/references/simulation-feedback.md +49 -0
- package/dist-skill/library/forgecad-build-model/references/stage-1-design-intent.md +21 -0
- package/dist-skill/library/forgecad-build-model/references/stage-2-architecture-plan.md +23 -0
- package/dist-skill/library/forgecad-build-model/references/stage-3-build-slices.md +39 -0
- package/dist-skill/library/forgecad-build-model/references/stage-4-feedback-iteration.md +24 -0
- package/dist-skill/library/forgecad-build-model/references/stage-5-readiness-package.md +34 -0
- package/dist-skill/library/forgecad-image-prompt/SKILL.md +1 -1
- package/dist-skill/library/forgecad-project-sync/SKILL.md +3 -3
- package/dist-skill/library/forgecad-reconstruct-cad-file/SKILL.md +2 -2
- package/dist-skill/library/forgecad-reconstruct-from-images/SKILL.md +4 -5
- package/dist-skill/website/skills/forgecad-build-model.md +70 -147
- package/dist-skill/website/skills/forgecad-image-prompt.md +1 -1
- package/dist-skill/website/skills/forgecad-project-sync.md +3 -3
- package/dist-skill/website/skills/forgecad-reconstruct-cad-file.md +2 -2
- package/dist-skill/website/skills/forgecad-reconstruct-from-images.md +4 -5
- package/dist-skill/website/skills/forgecad.md +3 -1
- package/dist-skill/website/skills/index.md +1 -5
- package/examples/api/param-path2d.forge.js +65 -0
- package/examples/api/param-placement2d.forge.js +80 -0
- package/examples/api/param-spline2d-g-continuity.forge.js +57 -0
- package/examples/api/spoon-full-tang-handle.forge.js +57 -17
- package/examples/api/surface-variable-thickness-panel.forge.js +62 -0
- package/examples/mechanical/airplane-propeller.forge.js +81 -28
- package/package.json +2 -2
- package/dist/docs-raw/skills/forgecad-design-spec.md +0 -145
- package/dist/docs-raw/skills/forgecad-grade-model.md +0 -84
- package/dist/docs-raw/skills/forgecad-inspect-model.md +0 -80
- package/dist/docs-raw/skills/forgecad-verify-mujoco.md +0 -78
- package/dist-skill/library/forgecad-design-spec/SKILL.md +0 -132
- package/dist-skill/library/forgecad-design-spec/references/default-profiles.md +0 -99
- package/dist-skill/library/forgecad-design-spec/references/master-prompt.md +0 -73
- package/dist-skill/library/forgecad-grade-model/SKILL.md +0 -72
- package/dist-skill/library/forgecad-grade-model/agents/openai.yaml +0 -4
- package/dist-skill/library/forgecad-inspect-model/SKILL.md +0 -68
- package/dist-skill/library/forgecad-verify-mujoco/SKILL.md +0 -66
- package/dist-skill/website/skills/forgecad-design-spec.md +0 -145
- package/dist-skill/website/skills/forgecad-grade-model.md +0 -84
- package/dist-skill/website/skills/forgecad-inspect-model.md +0 -80
- package/dist-skill/website/skills/forgecad-verify-mujoco.md +0 -78
- /package/dist-skill/library/{forgecad-verify-mujoco → forgecad-build-model}/scripts/mujoco_verify.py +0 -0
- /package/dist-skill/library/{forgecad-inspect-model → forgecad-build-model/scripts}/summarize_manifest.py +0 -0
package/dist-skill/CONTEXT.md
CHANGED
|
@@ -28,7 +28,8 @@ Author or modify ForgeCAD models, sketches, assemblies, and CLI workflows. Prefe
|
|
|
28
28
|
|
|
29
29
|
### Import and composition
|
|
30
30
|
|
|
31
|
-
- Always include the extension in relative imports: `require("./file.forge.js"
|
|
31
|
+
- Always include the extension in relative imports: `require("./file.forge.js")` for model files, `require("./helpers.js")` for plain helper modules. Extensionless imports such as `require("./file")` do not resolve; ForgeCAD resolves project imports by exact path.
|
|
32
|
+
- Reusable `.forge.js` part files should return builder functions such as `return { buildPart }`; direct-run preview params belong inside `if (require.main === module)`.
|
|
32
33
|
- ForgeCAD APIs are injected globals in `.forge.js` files. Use `bom()`, `box()`, `scene()`, `Shape`, etc. directly; never destructure those names from helpers (`const { bom } = require("./bom.js")`). Import helper files under a project-specific name such as `const bomHelpers = require("./bom.js")`.
|
|
33
34
|
- For static multi-part models, connectors + `matchTo()` are the default way to assemble touching parts.
|
|
34
35
|
- Top-level scripts can return `Assembly` or `SolvedAssembly` directly. Do not call `.toGroup()` just to render an assembly; use it only when you need `ShapeGroup` composition, transforms, or named-child lookup.
|
|
@@ -77,10 +78,10 @@ A `.forge.js` script is plain JavaScript that returns geometry. The entire forge
|
|
|
77
78
|
|
|
78
79
|
All geometry operations are **immutable** — shapes, sketches, groups, assemblies, and boards return new values, never mutate in place.
|
|
79
80
|
|
|
80
|
-
A script
|
|
81
|
+
A script should return one of three shapes:
|
|
81
82
|
|
|
82
83
|
1. **A single renderable** — `Shape`, `Sketch`, `ShapeGroup`, `Assembly`, `SolvedAssembly`, or `SdfShape`.
|
|
83
|
-
2. **An array** of renderables or named descriptors `{ name, tags?, shape | sketch | group, color? }
|
|
84
|
+
2. **An array** of renderables or named descriptors `{ name, tags?, shape | sketch | group, color? }`, usually for direct-run previews and multi-object display:
|
|
84
85
|
|
|
85
86
|
```javascript
|
|
86
87
|
return [
|
|
@@ -89,11 +90,38 @@ A script must return one of three shapes:
|
|
|
89
90
|
];
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
3. **A
|
|
93
|
+
3. **A module interface object** — usually builder functions, optionally a built shape plus interface data:
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
return { buildBracket };
|
|
97
|
+
// or, when the file's useful output is already built:
|
|
98
|
+
return { shape, connectors, boltPattern };
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For reusable part files, prefer a builder export and keep direct-run preview controls inside the entry guard:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
function buildThing(props) {
|
|
105
|
+
return box(props.width, props.depth, props.height);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (require.main === module) {
|
|
109
|
+
const previewProps = {
|
|
110
|
+
width: param("Width", 80),
|
|
111
|
+
depth: param("Depth", 40),
|
|
112
|
+
height: param("Height", 12),
|
|
113
|
+
};
|
|
114
|
+
return buildThing(previewProps);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { buildThing };
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
When a plain object is returned directly, renderable values are shown in the viewport and non-renderable values are available to importers through `require()`.
|
|
93
121
|
|
|
94
122
|
Return an unsolved `Assembly` directly — ForgeCAD solves it at default joint values for display. Use `assembly.solve(state)` for a specific pose. Never call `.toGroup()` just to make an assembly render; use it only when you need `ShapeGroup` composition or named-child lookup.
|
|
95
123
|
|
|
96
|
-
For multi-file projects
|
|
124
|
+
For multi-file projects, import path rules, and reusable builder modules, see the [`require()` docs](../../generated/core.md).
|
|
97
125
|
|
|
98
126
|
## Identity
|
|
99
127
|
|
|
@@ -145,14 +173,144 @@ rect, Rectangle2D, roundedRect, Route3D, scene, Sculpt, sdf, SdfShape
|
|
|
145
173
|
selectEdge, selectEdges, self, setActiveBackend, setImmediate, setInterval, setTimeout, Shape
|
|
146
174
|
ShapeGroup, sheetMetal, SheetMetalPart, sheetStock, Sim, Sketch, sketchToDxf, sketchToSvg
|
|
147
175
|
slot, SolvedAssembly, spec, sphere, spline2d, stroke, Surface, SurfaceBody
|
|
148
|
-
SurfaceMembers, sweep, text2d, textWidth, torus, toShape, Transform
|
|
149
|
-
union2d, variableSweep, verify, Viewport, window, Wood, Wrap
|
|
176
|
+
SurfaceMembers, sweep, text2d, textWidth, Thickness, torus, toShape, Transform
|
|
177
|
+
union, union2d, variableSweep, verify, Viewport, window, Wood, Wrap
|
|
150
178
|
```
|
|
151
179
|
|
|
152
180
|
`showLabels` is also a runtime global, but it is not part of the top-level collision check. Avoid reusing it unless you intentionally want a local value with that name.
|
|
153
181
|
|
|
154
182
|
---
|
|
155
183
|
|
|
184
|
+
<!-- guides/manual-parameters.md -->
|
|
185
|
+
|
|
186
|
+
# Manual Parameter Sheets
|
|
187
|
+
|
|
188
|
+
Manual parameters are constrained design data: the script owns the structure and
|
|
189
|
+
the user edits only the declared values. They are for cases where a numeric
|
|
190
|
+
slider is the wrong shape of input.
|
|
191
|
+
|
|
192
|
+
## Contents
|
|
193
|
+
|
|
194
|
+
- Decision Ladder
|
|
195
|
+
- Path2D
|
|
196
|
+
- Spline2D
|
|
197
|
+
- Placement2D
|
|
198
|
+
- Spatial Anchors
|
|
199
|
+
- Saving
|
|
200
|
+
|
|
201
|
+
## Decision Ladder
|
|
202
|
+
|
|
203
|
+
Use the smallest parameter type that matches the design intent:
|
|
204
|
+
|
|
205
|
+
| Intent | Use |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| One scalar dimension, count, angle, or toggle | `Param.number()`, `Param.bool()`, `Param.choice()` |
|
|
208
|
+
| A repeated table of named scalar fields | `Param.list()` |
|
|
209
|
+
| A hand-shaped polygon, section outline, or open centerline | `Param.path2d()` |
|
|
210
|
+
| A smooth hand-shaped curve with tangent/curvature intent | `Param.spline2d()` |
|
|
211
|
+
| Named semantic blocks arranged in zones | `Param.placement2d()` |
|
|
212
|
+
|
|
213
|
+
Do not use `path2d` or `spline2d` as a generic table. Use them when dragging
|
|
214
|
+
points is meaningfully better than editing numbers.
|
|
215
|
+
|
|
216
|
+
## Path2D
|
|
217
|
+
|
|
218
|
+
`Param.path2d(name, points, opts)` returns a `Path2DParamValue`.
|
|
219
|
+
|
|
220
|
+
- Closed paths are filled profile intent: call `.toSketch()`.
|
|
221
|
+
- Open paths are centerline intent: call `.toStroke(width)`.
|
|
222
|
+
- `x` and `y` ranges define the initial editor frame, not hard movement limits.
|
|
223
|
+
- Override keys are `Name[0].x`, `Name[0].y`, and `Name.__count__`.
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
const outline = Param.path2d('Outline', [[-30, -15], [30, -15], [24, 18], [-28, 16]], {
|
|
227
|
+
closed: true,
|
|
228
|
+
minPoints: 3,
|
|
229
|
+
maxPoints: 12,
|
|
230
|
+
unit: 'mm',
|
|
231
|
+
anchor: Param.anchor.sheetOnXY([0, 0, 8], { label: 'Top outline' }),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return outline.toSketch().extrude(4);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Spline2D
|
|
238
|
+
|
|
239
|
+
`Param.spline2d(name, points, opts)` returns a `Spline2DParamValue`.
|
|
240
|
+
|
|
241
|
+
- Each point has `g`: `G0` for a hard break, `G1` for tangent smooth, `G2` for
|
|
242
|
+
curvature smooth.
|
|
243
|
+
- Use `.toCurveOnXY()`, `.toCurveOnXZ()`, or `.toCurveOnYZ()` for sweeps and
|
|
244
|
+
curve consumers.
|
|
245
|
+
- Use `.toPathOnXY()`, `.toPathOnXZ()`, or `.toPathOnYZ()` when an API expects
|
|
246
|
+
sampled points.
|
|
247
|
+
- Override keys are `Name[0].x`, `Name[0].y`, `Name[0].g`, and `Name.__count__`.
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
const sideProfile = Param.spline2d('Side Profile', [
|
|
251
|
+
{ x: 0, y: 0, g: 'G2' },
|
|
252
|
+
{ x: 35, y: 8, g: 'G2' },
|
|
253
|
+
{ x: 70, y: 3, g: 'G1' },
|
|
254
|
+
], {
|
|
255
|
+
unit: 'mm',
|
|
256
|
+
anchor: Param.anchor.sheetOnXZ([0, -20, 0], { label: 'Side profile' }),
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const rail = sideProfile.toCurveOnXZ();
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Placement2D
|
|
263
|
+
|
|
264
|
+
`Param.placement2d(name, spec)` returns a `Placement2DParamValue`.
|
|
265
|
+
|
|
266
|
+
- The script declares stable item IDs, footprints, optional zones, and rules.
|
|
267
|
+
- The user moves named items; the model decides what each item creates.
|
|
268
|
+
- Use `.item(id)` for one placement or `.positions()` for keyed lookup.
|
|
269
|
+
- Override keys are item based: `Layout.battery.x`, `Layout.battery.y`,
|
|
270
|
+
`Layout.battery.angle`, and `Layout.battery.zone`.
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
const layout = Param.placement2d('Internal Layout', {
|
|
274
|
+
frame: { size: [120, 80] },
|
|
275
|
+
zones: [{ id: 'electronics', size: [70, 70], center: [-20, 0] }],
|
|
276
|
+
items: [
|
|
277
|
+
{ id: 'battery', footprint: { type: 'rect', size: [42, 24] }, zone: 'electronics', at: [-25, 0] },
|
|
278
|
+
{ id: 'speaker', footprint: { type: 'circle', radius: 12 }, at: [32, 8] },
|
|
279
|
+
],
|
|
280
|
+
rules: { bounds: 'prevent', collisions: 'warn', snap: 1 },
|
|
281
|
+
anchor: Param.anchor.sheetOnXY([0, 0, 12], { label: 'Internal layout' }),
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const battery = layout.item('battery');
|
|
285
|
+
const batteryBlock = box(42, 24, 6).translate(battery.x, battery.y, 3);
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Spatial Anchors
|
|
289
|
+
|
|
290
|
+
Every parameter type can carry optional viewport metadata through `anchor`.
|
|
291
|
+
Anchors do not change geometry.
|
|
292
|
+
|
|
293
|
+
- `Param.anchor.point([x, y, z])` creates a clickable pin for scalar, string,
|
|
294
|
+
list, boolean, or choice parameters.
|
|
295
|
+
- `Param.anchor.sheetOnXY([x, y, z])` places a 2D sheet in the XY plane at
|
|
296
|
+
fixed Z.
|
|
297
|
+
- `Param.anchor.sheetOnXZ([x, y, z])` places a 2D sheet in the XZ plane at
|
|
298
|
+
fixed Y.
|
|
299
|
+
- `Param.anchor.sheetOnYZ([x, y, z])` places a 2D sheet in the YZ plane at
|
|
300
|
+
fixed X.
|
|
301
|
+
|
|
302
|
+
The parameter still appears in the parameter panel when `anchor` is omitted; it
|
|
303
|
+
just has no 3D pin or spatial sheet.
|
|
304
|
+
|
|
305
|
+
## Saving
|
|
306
|
+
|
|
307
|
+
Dragging a manual sheet writes parameter overrides first. The source model keeps
|
|
308
|
+
the declared defaults until those overrides are intentionally folded back into
|
|
309
|
+
code. Use snapshots for named parameter states, and use the parameter panel's
|
|
310
|
+
AI handoff for manual canvas edits when the desired result should become source.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
156
314
|
<!-- generated/core.md -->
|
|
157
315
|
|
|
158
316
|
# Core API
|
|
@@ -176,6 +334,9 @@ union2d, variableSweep, verify, Viewport, window, Wood, Wrap
|
|
|
176
334
|
- [SurfacePattern](#surfacepattern)
|
|
177
335
|
- [Pattern2D](#pattern2d)
|
|
178
336
|
- [Pattern2DBuilder](#pattern2dbuilder)
|
|
337
|
+
- [Path2DParamValue](#path2dparamvalue)
|
|
338
|
+
- [Spline2DParamValue](#spline2dparamvalue)
|
|
339
|
+
- [Placement2DParamValue](#placement2dparamvalue)
|
|
179
340
|
- [CurveNetBuilder](#curvenetbuilder)
|
|
180
341
|
- [MatchEdgeBuilder](#matchedgebuilder)
|
|
181
342
|
- [BridgeBuilder](#bridgebuilder)
|
|
@@ -504,11 +665,11 @@ for (const edge of coalesceEdges(topEdges)) {
|
|
|
504
665
|
|
|
505
666
|
### Imports & Composition
|
|
506
667
|
|
|
507
|
-
#### `require(path: string
|
|
668
|
+
#### `require(path: string): any` — Import a ForgeCAD or helper module. Returns the file's returned value.
|
|
508
669
|
|
|
509
|
-
When importing a `.forge.js` file,
|
|
670
|
+
When importing a `.forge.js` file, return values are passed through exactly as the script returns them, except for unsolved assemblies: a returned [`Assembly`](/docs/assembly#assembly) is wrapped as an [`ImportedAssembly`](/docs/assembly#importedassembly), preserving `solve(state)` and `mergeInto()` across file boundaries. A returned [`SolvedAssembly`](/docs/assembly#solvedassembly) stays a [`SolvedAssembly`](/docs/assembly#solvedassembly).
|
|
510
671
|
|
|
511
|
-
**Script return contract:** a `.forge.js` script
|
|
672
|
+
**Script return contract:** a `.forge.js` script should return one of three shapes: a single renderable (Shape, ShapeGroup, Sketch, SdfShape, Assembly), an array of renderables or named descriptors (`{ name, shape|sketch|group }`) for previews and multi-object display, or a module interface object. Reusable part files should return builders such as `return { buildBracket }`; files that already build useful geometry may return `{ shape, connectors, boltPattern }`. When a script runs directly, renderable entries of a plain object are rendered under their key names and non-renderable entries are skipped.
|
|
512
673
|
|
|
513
674
|
**Assembly return contract**
|
|
514
675
|
|
|
@@ -521,52 +682,56 @@ When importing a `.forge.js` file, most return values are passed through exactly
|
|
|
521
682
|
|
|
522
683
|
**Path rule:** Always include the file extension in relative imports: use `require("./part.forge.js")` for model files and `require("./helpers.js")` for plain helper modules. ForgeCAD does not apply Node-style extension inference, so `require("./part")` will not find `part.forge.js` or `part.js`.
|
|
523
684
|
|
|
524
|
-
**
|
|
525
|
-
|
|
526
|
-
**Parameter overrides:** When passing overrides, use the bare param name (not the scoped name). Overrides are type-checked — unrecognized keys throw an error with typo suggestions.
|
|
527
|
-
|
|
528
|
-
**Multi-file assembly pattern** — pass cross-cutting design values from the assembly to parts:
|
|
685
|
+
**Multi-file assembly pattern** — the assembly owns params and passes ordinary props to child builders:
|
|
529
686
|
|
|
530
687
|
```js
|
|
531
688
|
// assembly.forge.js — owns cross-cutting params, passes to parts
|
|
532
689
|
const wall = param("Wall", 3);
|
|
533
690
|
const baseH = param("Base Height", 20);
|
|
534
691
|
|
|
535
|
-
const
|
|
536
|
-
const
|
|
692
|
+
const mountModule = require('./motor-mount.forge.js');
|
|
693
|
+
const baseModule = require('./base-body.forge.js');
|
|
694
|
+
|
|
695
|
+
const mount = mountModule.buildMount({ wall });
|
|
696
|
+
const base = baseModule.buildBase({ wall, height: baseH });
|
|
537
697
|
```
|
|
538
698
|
|
|
539
|
-
**
|
|
699
|
+
**Builder result pattern** — parts publish interface data alongside geometry:
|
|
540
700
|
|
|
541
701
|
```js
|
|
542
702
|
// motor-mount.forge.js
|
|
543
|
-
|
|
703
|
+
function buildMount({ wall }) {
|
|
704
|
+
const shape = box(80, 40, wall);
|
|
705
|
+
return { shape, boltPattern: { dia: 5.3, positions: [[-25, 0], [25, 0]] } };
|
|
706
|
+
}
|
|
544
707
|
|
|
545
708
|
// base-body.forge.js
|
|
546
709
|
const mount = require('./motor-mount.forge.js');
|
|
547
|
-
mount.
|
|
548
|
-
|
|
710
|
+
const built = mount.buildMount({ wall: 3 });
|
|
711
|
+
built.boltPattern // access interface data
|
|
712
|
+
built.shape // access geometry
|
|
549
713
|
```
|
|
550
714
|
|
|
551
715
|
**Forge-aware builder module pattern** — use `.forge.js` modules for reusable sketch, profile, shape, or assembly builders that need ForgeCAD runtime APIs:
|
|
552
716
|
|
|
553
717
|
```js
|
|
554
|
-
// profiles.forge.js
|
|
718
|
+
// profiles.forge.js
|
|
555
719
|
function wheelProfile() {
|
|
556
720
|
return circle2d(40).subtract(circle2d(18));
|
|
557
721
|
}
|
|
558
722
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
723
|
+
if (require.main === module) {
|
|
724
|
+
return [{ name: 'Wheel profile', sketch: wheelProfile() }];
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return { wheelProfile };
|
|
563
728
|
|
|
564
729
|
// main.forge.js
|
|
565
730
|
const profiles = require('./profiles.forge.js');
|
|
566
|
-
const wheel = profiles.
|
|
731
|
+
const wheel = profiles.wheelProfile().extrude(8);
|
|
567
732
|
```
|
|
568
733
|
|
|
569
|
-
Keep
|
|
734
|
+
Keep returned builders pure over top-level constants or explicit function arguments. Put preview-only `param()` values inside `if (require.main === module)` so parent assemblies stay in charge of design parameters. Use plain `.js` modules only for pure constants, tables, math helpers, and formatting code that does not construct ForgeCAD geometry.
|
|
570
735
|
|
|
571
736
|
**Entry detection (Node semantics):** `require.main` is the entry script's module object, so `require.main === module` is true only in the file being run directly. Part files use it to build standalone preview geometry only when opened directly — importers then skip that work entirely:
|
|
572
737
|
|
|
@@ -574,16 +739,30 @@ Keep exported builders pure over top-level constants, top-level `param()` values
|
|
|
574
739
|
// part.forge.js
|
|
575
740
|
function bracket() { ... }
|
|
576
741
|
if (require.main === module) {
|
|
577
|
-
return {
|
|
742
|
+
return bracket({ width: param('Width', 80), height: param('Height', 40) });
|
|
578
743
|
}
|
|
579
|
-
return {
|
|
744
|
+
return { bracket };
|
|
580
745
|
```
|
|
581
746
|
|
|
582
747
|
### Parameters
|
|
583
748
|
|
|
584
|
-
#### `Param.
|
|
749
|
+
#### `Param.anchor: { ... }` — Viewport anchor builders for spatial parameter editing.
|
|
750
|
+
|
|
751
|
+
Anchors are metadata only: they do not change geometry. The editor uses them to show clickable parameter pins and manual-editing sheets in the 3D viewport. Use point anchors for scalar/text/list parameters and sheet anchors for `path2d`, [`spline2d`](/docs/curves#spline2d), and `placement2d` editors.
|
|
752
|
+
|
|
753
|
+
A sheet anchor's origin is a world/model-space point. Its plane selects how the 2D editor coordinates map into the viewport:
|
|
754
|
+
|
|
755
|
+
- `sheetOnXY([x, y, z])`: editor x/y map to world X/Y at fixed Z.
|
|
756
|
+
- `sheetOnXZ([x, y, z])`: editor x/y map to world X/Z at fixed Y.
|
|
757
|
+
- `sheetOnYZ([x, y, z])`: editor x/y map to world Y/Z at fixed X.
|
|
758
|
+
|
|
759
|
+
Omitting `anchor` still registers the parameter in the parameter panel; it just will not create a viewport pin/sheet.
|
|
760
|
+
|
|
761
|
+
`ParamAnchorOptions`: `{ label?: string, color?: string }`
|
|
762
|
+
|
|
763
|
+
#### `Param.number(name: string, defaultValue: number, opts?: NumberParamOptions): number` — Declare a numeric parameter that renders as a slider in the UI.
|
|
585
764
|
|
|
586
|
-
Each call registers a slider control. When the user moves the slider the entire script re-executes with the new value.
|
|
765
|
+
Each call registers a slider control. When the user moves the slider the entire script re-executes with the new value. The `name` string is the UI label and the CLI `--param` key.
|
|
587
766
|
|
|
588
767
|
Default range rules when options are omitted:
|
|
589
768
|
|
|
@@ -599,38 +778,34 @@ const angle = Param.number("Angle", 45, { min: 0, max: 180, unit: "°" });
|
|
|
599
778
|
const sides = Param.number("Sides", 6, { min: 3, max: 12, integer: true });
|
|
600
779
|
```
|
|
601
780
|
|
|
602
|
-
|
|
781
|
+
CLI overrides use the parameter name:
|
|
603
782
|
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
const bracket = require("./bracket.forge.js", { Width: 80 });
|
|
607
|
-
|
|
608
|
-
// Via CLI
|
|
609
|
-
// forgecad run model.forge.js --param "Wall Thickness=3"
|
|
783
|
+
```bash
|
|
784
|
+
forgecad run model.forge.js --param "Wall Thickness=3"
|
|
610
785
|
```
|
|
611
786
|
|
|
612
787
|
Also available as the shorthand alias `param()`.
|
|
613
788
|
|
|
614
|
-
|
|
789
|
+
`ParamAnchorableOptions`: `{ anchor?: ParamAnchorDef }`
|
|
615
790
|
|
|
616
|
-
|
|
791
|
+
`NumberParamOptions`: `{ min?: number, max?: number, step?: number, unit?: string, integer?: boolean, reverse?: boolean }`
|
|
617
792
|
|
|
618
|
-
|
|
619
|
-
const label = Param.string("Label", "Hello World");
|
|
620
|
-
const name = Param.string("Name", "Part-001", { maxLength: 20 });
|
|
621
|
-
```
|
|
793
|
+
#### `Param.string(name: string, defaultValue: string, opts?: StringParamOptions): string` — Declare a string parameter that renders as a text input in the UI.
|
|
622
794
|
|
|
623
|
-
|
|
795
|
+
String parameters let users type free-form text — labels, names, inscriptions, file paths, etc.
|
|
624
796
|
|
|
625
797
|
```ts
|
|
626
|
-
const
|
|
798
|
+
const label = Param.string("Label", "Hello World");
|
|
799
|
+
const name = Param.string("Name", "Part-001", { maxLength: 20 });
|
|
627
800
|
```
|
|
628
801
|
|
|
629
802
|
Only available as `Param.string()` — no standalone alias.
|
|
630
803
|
|
|
631
|
-
|
|
804
|
+
`StringParamOptions`: `{ maxLength?: number }`
|
|
632
805
|
|
|
633
|
-
|
|
806
|
+
#### `Param.bool(name: string, defaultValue: boolean, opts?: ParamAnchorableOptions): boolean` — Declare a boolean parameter that renders as a checkbox in the UI.
|
|
807
|
+
|
|
808
|
+
Internally stored as `0`/`1` for CLI overrides. Pass `1` for true and `0` for false.
|
|
634
809
|
|
|
635
810
|
```ts
|
|
636
811
|
const showHoles = Param.bool("Show Holes", true);
|
|
@@ -638,29 +813,17 @@ if (showHoles) return difference(plate, cylinder(10, 5).translate(50, 30, 0));
|
|
|
638
813
|
return plate;
|
|
639
814
|
```
|
|
640
815
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
```ts
|
|
644
|
-
const pan = require("./pan.forge.js", { "Show Lid": 0 });
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
#### `Param.choice(name: string, defaultValue: string, choices: string[]): string` — Declare a choice parameter that renders as a dropdown in the UI.
|
|
816
|
+
#### `Param.choice(name: string, defaultValue: string, choices: string[], opts?: ParamAnchorableOptions): string` — Declare a choice parameter that renders as a dropdown in the UI.
|
|
648
817
|
|
|
649
818
|
`defaultValue` must exactly match one entry in `choices`. Returns the selected string label. Prefer `Param.choice` over `Param.number` when a slider would hide intent — named choices like `"wok"` are self-describing.
|
|
650
819
|
|
|
651
|
-
|
|
820
|
+
CLI overrides may be passed as the choice label string (preferred) or as a numeric index.
|
|
652
821
|
|
|
653
822
|
```ts
|
|
654
823
|
const panStyle = Param.choice("Pan Style", "frying-pan", ["frying-pan", "saute-pan", "wok"]);
|
|
655
824
|
if (panStyle === "wok") return buildWok();
|
|
656
825
|
```
|
|
657
826
|
|
|
658
|
-
Override via import:
|
|
659
|
-
|
|
660
|
-
```ts
|
|
661
|
-
const pan = require("./pan.forge.js", { "Pan Style": "wok" });
|
|
662
|
-
```
|
|
663
|
-
|
|
664
827
|
Override via CLI:
|
|
665
828
|
|
|
666
829
|
```bash
|
|
@@ -679,6 +842,90 @@ Field types:
|
|
|
679
842
|
|
|
680
843
|
`ListParamFieldDef`: `{ min?: number, max?: number, step?: number, unit?: string, integer?: boolean, boolean?: boolean, choices?: string[] }`
|
|
681
844
|
|
|
845
|
+
#### `Param.path2d(name: string, defaultPoints: Path2DPointInput[], opts?: Path2DParamOptions): Path2DParamValue` — Declare an editable 2D path parameter.
|
|
846
|
+
|
|
847
|
+
Use this for hand-shaped 2D profile data: plate outlines, slice profiles, stroke centerlines, and sweep rails. The returned value keeps the model code deterministic while the editor can render a drag-handle path UI.
|
|
848
|
+
|
|
849
|
+
Override keys use the same explicit row-field form as list params: `Path Name[0].x`, `Path Name[0].y`, and `Path Name.__count__`.
|
|
850
|
+
|
|
851
|
+
```ts
|
|
852
|
+
const outline = Param.path2d("Bracket Outline", [
|
|
853
|
+
[-40, -20],
|
|
854
|
+
[40, -20],
|
|
855
|
+
[36, 24],
|
|
856
|
+
[-30, 28],
|
|
857
|
+
], {
|
|
858
|
+
closed: true,
|
|
859
|
+
anchor: Param.anchor.sheetOnXY([0, 0, 8], { label: "Bracket outline" }),
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
return outline.toSketch().filletCorners(4).extrude(5);
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
**`Path2DParamOptions`** extends ParamAnchorableOptions: `closed?: boolean`, `minPoints?: number`, `maxPoints?: number`, `x?: Partial<Path2DParamAxisDef>`, `y?: Partial<Path2DParamAxisDef>`, `unit?: string`
|
|
866
|
+
|
|
867
|
+
**`Path2DParamAxisDef`**
|
|
868
|
+
- `min: number` — Initial editor-frame minimum. Points may move outside this range on the infinite canvas.
|
|
869
|
+
- `max: number` — Initial editor-frame maximum. Points may move outside this range on the infinite canvas.
|
|
870
|
+
- Also: `step: number`.
|
|
871
|
+
|
|
872
|
+
#### `Param.spline2d(name: string, defaultPoints: Spline2DPointInput[], opts?: Spline2DParamOptions): Spline2DParamValue` — Declare an editable 2D spline parameter.
|
|
873
|
+
|
|
874
|
+
Use this when the model wants hand-shaped smooth curve data instead of a numeric table: handle spines, bowl station curves, sweep rails, and class-A guide profiles. Each node stores `g`, a continuity intent:
|
|
875
|
+
|
|
876
|
+
- `"G0"` starts/ends a hard curve segment at that point
|
|
877
|
+
- `"G1"` keeps the point in a tangent-smooth run
|
|
878
|
+
- `"G2"` keeps the point in a curvature-smooth cubic run
|
|
879
|
+
|
|
880
|
+
Override keys use explicit row-field form: `Curve Name[0].x`, `Curve Name[0].y`, `Curve Name[0].g`, and `Curve Name.__count__`.
|
|
881
|
+
|
|
882
|
+
```ts
|
|
883
|
+
const spine = Param.spline2d("Handle Spine", [
|
|
884
|
+
{ x: 0, y: 0, g: "G2" },
|
|
885
|
+
{ x: 35, y: 8, g: "G2" },
|
|
886
|
+
{ x: 80, y: 2, g: "G1" },
|
|
887
|
+
], {
|
|
888
|
+
anchor: Param.anchor.sheetOnXZ([0, -18, 0], { label: "Side-view spine" }),
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
return sweep(circle2d(2), spine.toCurveOnXZ());
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
**`Spline2DParamOptions`** extends ParamAnchorableOptions: `closed?: boolean`, `degree?: number`, `defaultContinuity?: Spline2DContinuity`, `minPoints?: number`, `maxPoints?: number`, `x?: Partial<Path2DParamAxisDef>`, `y?: Partial<Path2DParamAxisDef>`, `unit?: string`
|
|
895
|
+
|
|
896
|
+
#### `Param.placement2d(name: string, spec: Placement2DParamOptions): Placement2DParamValue` — Declare an editable 2D placement sheet parameter.
|
|
897
|
+
|
|
898
|
+
Use this when the user should arrange named model roles rather than draw geometry: batteries inside an enclosure, rooms across floors, controls on a panel, robot modules on a chassis, or other semantic blockouts.
|
|
899
|
+
|
|
900
|
+
The script declares stable item IDs, footprints, optional rectangular zones, and interaction rules. The returned value exposes named placements as data; the model code decides what those placements mean geometrically.
|
|
901
|
+
|
|
902
|
+
Override keys are item-ID based: `Layout.battery.x`, `Layout.battery.y`, `Layout.battery.angle`, and `Layout.battery.zone`.
|
|
903
|
+
|
|
904
|
+
```ts
|
|
905
|
+
const layout = Param.placement2d("Internal Layout", {
|
|
906
|
+
frame: { size: [120, 80] },
|
|
907
|
+
items: [
|
|
908
|
+
{ id: "battery", footprint: { type: "rect", size: [42, 24] }, at: [-25, 0] },
|
|
909
|
+
{ id: "speaker", footprint: { type: "circle", radius: 12 }, at: [32, 8] },
|
|
910
|
+
],
|
|
911
|
+
rules: { bounds: "prevent", collisions: "warn", snap: 1 },
|
|
912
|
+
anchor: Param.anchor.sheetOnXY([0, 0, 12], { label: "Internal layout" }),
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
const battery = layout.item("battery");
|
|
916
|
+
const batteryPocket = box(42, 24, 6).translate(battery.x, battery.y, 3);
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
**`Placement2DParamOptions`** extends ParamAnchorableOptions: `frame?: Placement2DFrameInput`, `zones?: Placement2DZoneInput[]`, `items: Placement2DItemInput[]`, `rules?: Partial<Placement2DRulesDef>`, `unit?: string`
|
|
920
|
+
|
|
921
|
+
`Placement2DFrameInput`: `{ width?: number, height?: number, size?: Vec2, center?: Placement2DPointInput, at?: Placement2DPointInput }`
|
|
922
|
+
|
|
923
|
+
`Placement2DZoneInput`: `{ id: string, label?: string, frame?: Placement2DFrameInput }`
|
|
924
|
+
|
|
925
|
+
**`Placement2DItemInput`**: `id: string`, `label?: string`, `footprint: Placement2DFootprintInput`, `at?: Placement2DPointInput`, `center?: Placement2DPointInput`, `angle?: number`, `zone?: string`, `locked?: boolean`
|
|
926
|
+
|
|
927
|
+
`Placement2DRulesDef`: `{ bounds: Placement2DRuleMode, collisions: Placement2DRuleMode, snap: number }`
|
|
928
|
+
|
|
682
929
|
### Grouping & Local Coordinates
|
|
683
930
|
|
|
684
931
|
#### `group(...items: GroupInput[]): ShapeGroup` — Group multiple shapes/sketches for joint transforms without merging into a single mesh.
|
|
@@ -1356,7 +1603,7 @@ cylinder(60, 20).wrapTexture(label, Wrap.aroundCylinder({ axis: 'z' })); // wra
|
|
|
1356
1603
|
|
|
1357
1604
|
#### `ref(path: string): ShapeRef` — Resolve a semantic reference path like `lid`, `lid/back`, or a midpoint selector on `lid/back`.
|
|
1358
1605
|
|
|
1359
|
-
#### `thicken(thickness:
|
|
1606
|
+
#### `thicken(thickness: ThicknessInput): Shape` — Offset-thicken an exact open surface or shell into a solid.
|
|
1360
1607
|
|
|
1361
1608
|
#### `getMesh(): ShapeRuntimeMesh` — Extract triangle mesh for Three.js rendering
|
|
1362
1609
|
|
|
@@ -1596,6 +1843,99 @@ const bracket = group(
|
|
|
1596
1843
|
| `depth?` | `number` | Thread groove depth in millimeters. Default: 0.8. |
|
|
1597
1844
|
| `underScale?` | `number` | Relative height of the under-crossing thread. Default: 0.15. |
|
|
1598
1845
|
|
|
1846
|
+
### `Path2DParamValue`
|
|
1847
|
+
|
|
1848
|
+
Runtime value returned by `Param.path2d()`.
|
|
1849
|
+
|
|
1850
|
+
Use closed paths as editable profile outlines via `toSketch()`. Use open paths as editable centerlines via `toStroke(width)`.
|
|
1851
|
+
|
|
1852
|
+
**Properties:**
|
|
1853
|
+
|
|
1854
|
+
| Property | Type | Description |
|
|
1855
|
+
|----------|------|-------------|
|
|
1856
|
+
| `closed` | `boolean` | True when this path is intended to close back to its first point. |
|
|
1857
|
+
|
|
1858
|
+
**Methods:**
|
|
1859
|
+
|
|
1860
|
+
#### `points(): Vec2[]` — Return the current points as `[x, y]` pairs in the editor coordinate system.
|
|
1861
|
+
|
|
1862
|
+
#### `toSketch(): Sketch` — Convert a closed editable path into a sketch profile.
|
|
1863
|
+
|
|
1864
|
+
This is the common path for hand-edited plates, outlines, and 2D section profiles that will be extruded, subtracted, or used in sketch booleans. Throws for open paths; use `toStroke(width)` for editable centerlines.
|
|
1865
|
+
|
|
1866
|
+
#### `toStroke(width: number, join?: "Round" | "Square"): Sketch` — Convert an editable path into a stroked sketch with physical width.
|
|
1867
|
+
|
|
1868
|
+
Use this for rails, ribs, cable routes, gasket paths, and other open centerlines. Closed paths can also be stroked when the intent is a looped band rather than a filled profile.
|
|
1869
|
+
|
|
1870
|
+
### `Spline2DParamValue`
|
|
1871
|
+
|
|
1872
|
+
Runtime value returned by `Param.spline2d()`.
|
|
1873
|
+
|
|
1874
|
+
Spline params preserve both editable point coordinates and each point's continuity intent (`G0`, `G1`, or `G2`). Convert them to curves for sweeps and loft rails, or to sampled paths when an API expects plain points.
|
|
1875
|
+
|
|
1876
|
+
**Properties:**
|
|
1877
|
+
|
|
1878
|
+
| Property | Type | Description |
|
|
1879
|
+
|----------|------|-------------|
|
|
1880
|
+
| `closed` | `boolean` | True when this spline is intended to close back to its first point. |
|
|
1881
|
+
| `degree` | `number` | Requested fitting degree before any automatic reduction for short spans. |
|
|
1882
|
+
|
|
1883
|
+
**Methods:**
|
|
1884
|
+
|
|
1885
|
+
#### `points(): Vec2[]` — Return the current control nodes as `[x, y]` pairs without continuity metadata.
|
|
1886
|
+
|
|
1887
|
+
#### `nodes(): Spline2DPointDef[]` — Return the current editable nodes, including per-point `g` continuity values.
|
|
1888
|
+
|
|
1889
|
+
#### `continuities(): Spline2DContinuity[]` — Return only the per-node continuity intents in point order.
|
|
1890
|
+
|
|
1891
|
+
#### `toPolyline(samples?: number): Vec2[]` — Sample the spline into 2D `[x, y]` points.
|
|
1892
|
+
|
|
1893
|
+
Use this when downstream code needs a polyline instead of a curve object.
|
|
1894
|
+
|
|
1895
|
+
#### `toCurveOnXY(z?: number, options?: Spline2DCurveOptions): NurbsCurve3D` — Fit the editable spline as a 3D curve on the XY plane at constant `z`.
|
|
1896
|
+
|
|
1897
|
+
The point's `x` maps to world X and `y` maps to world Y.
|
|
1898
|
+
|
|
1899
|
+
`Spline2DCurveOptions`: `{ degree?: number, tolerance?: number, samples?: number }`
|
|
1900
|
+
|
|
1901
|
+
#### `toCurveOnXZ(y?: number, options?: Spline2DCurveOptions): NurbsCurve3D` — Fit the editable spline as a 3D curve on the XZ plane at constant `y`.
|
|
1902
|
+
|
|
1903
|
+
The point's `x` maps to world X and `y` maps to world Z. This is useful for side-view height/depth profiles such as spoon bowls, handles, and rails.
|
|
1904
|
+
|
|
1905
|
+
#### `toCurveOnYZ(x?: number, options?: Spline2DCurveOptions): NurbsCurve3D` — Fit the editable spline as a 3D curve on the YZ plane at constant `x`.
|
|
1906
|
+
|
|
1907
|
+
The point's `x` maps to world Y and `y` maps to world Z.
|
|
1908
|
+
|
|
1909
|
+
#### `toCurveSegmentsOnXY(z?: number, options?: Spline2DCurveOptions): NurbsCurve3D[]` — Fit the spline on XY and return separate curve segments split at `G0` nodes.
|
|
1910
|
+
|
|
1911
|
+
Use segment output when a hard break should remain visible to downstream code instead of being joined into one continuous curve.
|
|
1912
|
+
|
|
1913
|
+
#### `toCurveSegmentsOnXZ(y?: number, options?: Spline2DCurveOptions): NurbsCurve3D[]` — Fit the spline on XZ and return separate curve segments split at `G0` nodes.
|
|
1914
|
+
|
|
1915
|
+
#### `toCurveSegmentsOnYZ(x?: number, options?: Spline2DCurveOptions): NurbsCurve3D[]` — Fit the spline on YZ and return separate curve segments split at `G0` nodes.
|
|
1916
|
+
|
|
1917
|
+
#### `toPathOnXY(z?: number, options?: Spline2DCurveOptions): Vec3[]` — Sample the spline as 3D points on the XY plane at constant `z`.
|
|
1918
|
+
|
|
1919
|
+
This is useful for sweeps and surface helpers that accept point paths.
|
|
1920
|
+
|
|
1921
|
+
#### `toPathOnXZ(y?: number, options?: Spline2DCurveOptions): Vec3[]` — Sample the spline as 3D points on the XZ plane at constant `y`.
|
|
1922
|
+
|
|
1923
|
+
#### `toPathOnYZ(x?: number, options?: Spline2DCurveOptions): Vec3[]` — Sample the spline as 3D points on the YZ plane at constant `x`.
|
|
1924
|
+
|
|
1925
|
+
### `Placement2DParamValue`
|
|
1926
|
+
|
|
1927
|
+
Runtime value returned by `Param.placement2d()`.
|
|
1928
|
+
|
|
1929
|
+
Placement sheets return semantic item positions. The model decides what each item means geometrically, so users can drag named blocks without editing the construction code.
|
|
1930
|
+
|
|
1931
|
+
#### `items(): Placement2DItemPlacement[]` — Return all current item placements as immutable copies.
|
|
1932
|
+
|
|
1933
|
+
#### `positions(): Record<string, Placement2DItemPlacement>` — Return current placements keyed by item id for table-style lookup.
|
|
1934
|
+
|
|
1935
|
+
#### `item(id: string): Placement2DItemPlacement` — Return one named item placement.
|
|
1936
|
+
|
|
1937
|
+
Throws if `id` was not declared in the sheet, which keeps model code tied to stable semantic item IDs rather than fragile list indices.
|
|
1938
|
+
|
|
1599
1939
|
### `CurveNetBuilder`
|
|
1600
1940
|
|
|
1601
1941
|
#### `alongRails(railA: CurveInput, railB: CurveInput): this` — Use two lengthwise boundary curves as guide rails.
|
|
@@ -1667,6 +2007,7 @@ Pass `{ edge }` to match an adjacent sheet's tangent (G1) or curvature (G2), or
|
|
|
1667
2007
|
- `pathAlongU(v: number, options?: SheetPathAlongOptions): Vec3[]`
|
|
1668
2008
|
- `pathAlongV(u: number, options?: SheetPathAlongOptions): Vec3[]`
|
|
1669
2009
|
- `thicken(wall: number, options?: { resolution?: number; }): Shape`
|
|
2010
|
+
- `thickenInsideBy(thickness: ThicknessInput, options?: { resolution?: number; }): Shape`
|
|
1670
2011
|
- `matchEdge(edge: SheetEdge): MatchEdgeBuilder`
|
|
1671
2012
|
|
|
1672
2013
|
**`SheetFrameOptions`**
|
|
@@ -2884,6 +3225,7 @@ Smooth curves, lofted surfaces, swept solids, splines, and high-level product sk
|
|
|
2884
3225
|
- [Surface](#surface)
|
|
2885
3226
|
- [Blend](#blend)
|
|
2886
3227
|
- [Analysis](#analysis)
|
|
3228
|
+
- [Thickness](#thickness)
|
|
2887
3229
|
- [Product](#product)
|
|
2888
3230
|
- [Carrier](#carrier)
|
|
2889
3231
|
- [SurfaceMembers](#surfacemembers)
|
|
@@ -3493,6 +3835,10 @@ Use this when the guide path runs in the surface V direction and the sketch prof
|
|
|
3493
3835
|
|
|
3494
3836
|
#### `thicken(wall: number, options?: { resolution?: number; }): Shape` — Offset the sheet along its analytic normals into a watertight solid shell of the given wall thickness. Throws if the wall would self-intersect on a concave region (no silent degenerate solid).
|
|
3495
3837
|
|
|
3838
|
+
#### `thickenInsideBy(thickness: ThicknessInput, options?: { resolution?: number; }): Shape` — Thicken this sheet inward by a scalar UV thickness field.
|
|
3839
|
+
|
|
3840
|
+
Numeric input delegates to `Sheet.thicken()`. `Thickness.*` fields produce a sampled solid because a variable normal offset is not generally an exact NURBS surface.
|
|
3841
|
+
|
|
3496
3842
|
#### `matchEdge(edge: SheetEdge): MatchEdgeBuilder` — Per-edge continuity match against a neighbor (returns a NEW Sheet).
|
|
3497
3843
|
|
|
3498
3844
|
- `get rearEdge(): SheetEdge`
|
|
@@ -4368,6 +4714,14 @@ Members (full entries under [Curves & Surfacing](#curves-surfacing)): `Curve.Ble
|
|
|
4368
4714
|
- `SurfaceHealth(shape: Shape, options?: { tinyEdgeThreshold?: number; sliverThreshold?: number; }): SurfaceHealthReport`
|
|
4369
4715
|
- `BRepValidity(shape: Shape, options?: BRepValidityOptions): BRepValidityReport` — Validate B-rep/shell/solid structure and return closedness, manifoldness, orientation, and issue diagnostics.
|
|
4370
4716
|
|
|
4717
|
+
### `Thickness`
|
|
4718
|
+
|
|
4719
|
+
- `constant: (thickness: number) => ThicknessField` — Use the same wall thickness everywhere on the sheet.
|
|
4720
|
+
- `alongU: (profile: ThicknessStation[] | ThicknessStationProfile) => ThicknessField` — Vary wall thickness across the sheet U direction.
|
|
4721
|
+
- `alongV: (profile: ThicknessStation[] | ThicknessStationProfile) => ThicknessField` — Vary wall thickness across the sheet V direction.
|
|
4722
|
+
- `grid: (values: number[][], options?: ThicknessGridOptions) => ThicknessField` — Bilinearly interpolate wall thickness from a rectangular UV grid.
|
|
4723
|
+
- `nurbs: (values: number[][], options?: ThicknessNurbsOptions) => ThicknessField` — Interpolate wall thickness from a scalar tensor-product B-spline over sheet UV.
|
|
4724
|
+
|
|
4371
4725
|
### `Product`
|
|
4372
4726
|
|
|
4373
4727
|
- `skin(name: string): ProductSkinBuilder` — Start a named product skin builder.
|
|
@@ -5388,6 +5742,17 @@ Use structural FEA when you want a ForgeCAD model to answer a load-case question
|
|
|
5388
5742
|
|
|
5389
5743
|
ForgeCAD owns the authoring contract, solver orchestration, result feedback, and inspection report. The numerical solve is done out of process with Gmsh and CalculiX. Users author a study in the model, run `forgecad fea run`, and inspect a result bundle.
|
|
5390
5744
|
|
|
5745
|
+
## Contents
|
|
5746
|
+
|
|
5747
|
+
- What You Get
|
|
5748
|
+
- What You Need Installed
|
|
5749
|
+
- Author The Study
|
|
5750
|
+
- Choose Stable Regions
|
|
5751
|
+
- Run The Flow
|
|
5752
|
+
- Read The Results
|
|
5753
|
+
- Current Scope
|
|
5754
|
+
- Troubleshooting
|
|
5755
|
+
|
|
5391
5756
|
## What You Get
|
|
5392
5757
|
|
|
5393
5758
|
A solved FEA result bundle can produce:
|