forgecad 0.7.0 → 0.8.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/README.md +1 -1
- package/dist/assets/{AdminPage-DAu1C1ST.js → AdminPage-D4bocK4E.js} +1 -1
- package/dist/assets/{DocsPage-Gc_BCdqC.js → DocsPage-D3A_g8V3.js} +85 -45
- package/dist/assets/{EditorApp-DG1-oUSV.css → EditorApp-BWYUSpUN.css} +133 -51
- package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
- package/dist/assets/{EmbedViewer-CEO8XbV8.js → EmbedViewer-kWjKaC_t.js} +1 -1
- package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
- package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
- package/dist/assets/{PricingPage-BSrxu6d7.js → PricingPage-BsU5vzEx.js} +1 -1
- package/dist/assets/{SettingsPage-FUCSIRq6.js → SettingsPage-PqvpAKIs.js} +1 -1
- package/dist/assets/{evalWorker-KoR0SNKq.js → evalWorker-C-hzNUMy.js} +2218 -286
- package/dist/assets/{index-wTEK39at.js → index-Pz321YAt.js} +7416 -1481
- package/dist/assets/{index-CyVd1D4D.css → index-ay13WNfa.css} +501 -2
- package/dist/assets/{manifold-B1sGWdYk.js → manifold-BcbjWLIo.js} +3 -3
- package/dist/assets/{manifold-D7o0N50J.js → manifold-DBckbFgx.js} +1 -1
- package/dist/assets/{manifold-G5sBaXzi.js → manifold-O2AAGXyj.js} +1 -1
- package/dist/assets/{reportWorker-DYcRHhv9.js → reportWorker-Dxr-5A7w.js} +2003 -259
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +488 -0
- package/dist/docs-raw/generated/assembly.md +19 -11
- package/dist/docs-raw/generated/concepts.md +1023 -360
- package/dist/docs-raw/generated/core.md +1165 -264
- package/dist/docs-raw/generated/curves.md +168 -1
- package/dist/docs-raw/generated/lib.md +10 -5
- package/dist/docs-raw/generated/output.md +1 -1
- package/dist/docs-raw/generated/sdf.md +208 -0
- package/dist/docs-raw/generated/sketch.md +1281 -329
- package/dist/docs-raw/generated/viewport.md +29 -2
- package/dist/index.html +2 -2
- package/dist/landing/proof-ams-adapter.png +0 -0
- package/dist/landing/proof-bolt-and-nut.png +0 -0
- package/dist/landing/proof-fillet-enclosure.png +0 -0
- package/dist/landing/proof-glasses.png +0 -0
- package/dist/landing/proof-gyroid.png +0 -0
- package/dist/sitemap.xml +6 -6
- package/dist-cli/forgecad.js +3148 -555
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-cli/{solver-FV7TJZGI.js → solver-46FFSK2U.js} +1 -3
- package/dist-cli/{solver-FV7TJZGI.js.map → solver-46FFSK2U.js.map} +1 -1
- package/dist-skill/CONTEXT.md +3700 -1153
- package/dist-skill/SKILL-dev.md +15 -17
- package/dist-skill/SKILL.md +14 -9
- package/dist-skill/docs/API/core/concepts.md +28 -1
- package/dist-skill/docs/CLI.md +488 -0
- package/dist-skill/docs/generated/assembly.md +19 -11
- package/dist-skill/docs/generated/core.md +1165 -264
- package/dist-skill/docs/generated/curves.md +168 -1
- package/dist-skill/docs/generated/lib.md +10 -5
- package/dist-skill/docs/generated/output.md +1 -1
- package/dist-skill/docs/generated/sdf.md +208 -0
- package/dist-skill/docs/generated/sketch.md +1281 -329
- package/dist-skill/docs/generated/viewport.md +29 -2
- package/dist-skill/docs/guides/joint-design.md +78 -0
- package/dist-skill/docs-dev/API/core/concepts.md +28 -1
- package/dist-skill/docs-dev/CLI.md +488 -0
- package/dist-skill/docs-dev/coding.md +1 -1
- package/dist-skill/docs-dev/component-model.md +164 -0
- package/dist-skill/docs-dev/generated/assembly.md +19 -11
- package/dist-skill/docs-dev/generated/core.md +1165 -264
- package/dist-skill/docs-dev/generated/curves.md +168 -1
- package/dist-skill/docs-dev/generated/lib.md +10 -5
- package/dist-skill/docs-dev/generated/output.md +1 -1
- package/dist-skill/docs-dev/generated/sdf.md +208 -0
- package/dist-skill/docs-dev/generated/sketch.md +1281 -329
- package/dist-skill/docs-dev/generated/viewport.md +29 -2
- package/dist-skill/docs-dev/guides/joint-design.md +78 -0
- package/examples/api/attachTo-basics.forge.js +3 -3
- package/examples/api/bill-of-materials.forge.js +9 -9
- package/examples/api/bolt-pattern.forge.js +5 -5
- package/examples/api/boolean-operations.forge.js +2 -2
- package/examples/api/bounding-box-visualizer.forge.js +1 -1
- package/examples/api/clone-duplicate.forge.js +1 -1
- package/examples/api/connector-assembly.forge.js +4 -2
- package/examples/api/connector-basics.forge.js +5 -5
- package/examples/api/constrained-sketch-mechanical.forge.js +4 -4
- package/examples/api/elbow-test.forge.js +3 -3
- package/examples/api/extrude-options.forge.js +4 -4
- package/examples/api/fillet-showcase.forge.js +1 -1
- package/examples/api/gears-tier1.forge.js +5 -5
- package/examples/api/group-test.forge.js +2 -2
- package/examples/api/mesh-import-slats.forge.js +3 -3
- package/examples/api/patterns.forge.js +3 -3
- package/examples/api/pointAlong-orientation.forge.js +2 -2
- package/examples/api/profile-2020-b-slot6.forge.js +4 -4
- package/examples/api/sketch-rounding-strategies.forge.js +1 -1
- package/examples/api/smooth-curve-connections.forge.js +1 -1
- package/examples/api/transition-curves.forge.js +3 -3
- package/examples/constraints/01-fully-constrained-rect.forge.js +2 -2
- package/examples/constraints/02-underconstrained-triangle.forge.js +1 -1
- package/examples/constraints/03-redundant-constraints.forge.js +2 -2
- package/examples/constraints/05-parallel-with-linedistance.forge.js +2 -2
- package/examples/constraints/06-complex-spectrogram.forge.js +1 -1
- package/examples/constraints/07-perpendicular-chain.forge.js +4 -4
- package/examples/constraints/08-symmetric-bracket.forge.js +4 -4
- package/examples/constraints/09-stress-spiral.forge.js +1 -1
- package/examples/constraints/10-stress-honeycomb.forge.js +1 -1
- package/examples/constraints/11-surface-grid.forge.js +2 -2
- package/examples/constraints/12-surface-nested.forge.js +4 -4
- package/examples/constraints/13-surface-complex.forge.js +1 -1
- package/examples/exact-arc-housing.forge.js +12 -0
- package/examples/furniture/adjustable-table.forge.js +13 -13
- package/examples/furniture/bathroom.forge.js +15 -15
- package/examples/furniture/chair.forge.js +12 -12
- package/examples/furniture/picture-frame.forge.js +6 -6
- package/examples/furniture/shoe-rack-doors.forge.js +8 -8
- package/examples/furniture/shoe-rack.forge.js +7 -7
- package/examples/furniture/table-lamp.forge.js +8 -8
- package/examples/gcode/lissajous-vase.forge.js +4 -4
- package/examples/gcode/math-surface.forge.js +3 -3
- package/examples/gcode/parametric-vase.forge.js +4 -4
- package/examples/gcode/spiral-tower.forge.js +4 -4
- package/examples/generative/crystal-growth.forge.js +7 -7
- package/examples/generative/frost-spires.forge.js +6 -6
- package/examples/generative/golden-spiral-tower.forge.js +8 -8
- package/examples/generative/molten-forge.forge.js +6 -6
- package/examples/generative/neon-coral.forge.js +7 -7
- package/examples/mechanical/3d-printer.forge.js +9 -9
- package/examples/mechanical/5-finger-robot-hand.forge.js +4 -4
- package/examples/mechanical/airplane-propeller.forge.js +7 -7
- package/examples/mechanical/bolt-and-nut.forge.js +10 -10
- package/examples/mechanical/door-with-hinges.forge.js +7 -7
- package/examples/mechanical/fillet-enclosure.forge.js +14 -10
- package/examples/mechanical/headphone-hanger-v2.forge.js +9 -9
- package/examples/mechanical/robot_hand.forge.js +10 -10
- package/examples/mechanical/robot_hand_2.forge.js +17 -17
- package/examples/nurbs-surface.forge.js +8 -0
- package/examples/nurbs-tube.forge.js +7 -0
- package/examples/products/bottle.forge.js +7 -7
- package/examples/products/chess-set.forge.js +6 -6
- package/examples/products/classical-piano.forge.js +9 -9
- package/examples/products/clock.forge.js +21 -21
- package/examples/products/cup.forge.js +5 -5
- package/examples/products/iphone.forge.js +12 -12
- package/examples/products/laptop.forge.js +9 -9
- package/examples/products/laser-cut-box.forge.js +6 -6
- package/examples/products/laser-cut-tray.forge.js +6 -6
- package/examples/products/liquid-soap-dispenser.forge.js +5 -5
- package/examples/products/origami-fish.forge.js +6 -6
- package/examples/products/spiderman-cake.forge.js +2 -2
- package/examples/shelf/container.forge.js +5 -5
- package/examples/shelf/shelf-unit.forge.js +6 -6
- package/examples/toolbox/bolted-joint.forge.js +5 -5
- package/package.json +3 -1
- package/dist/assets/EditorApp-D9bJvtf7.js +0 -11338
- package/dist/assets/LandingPage-CdCuEOdC.js +0 -451
- package/dist-cli/chunk-PZ5AY32C.js +0 -10
- package/dist-cli/chunk-PZ5AY32C.js.map +0 -1
- package/dist-skill/docs/CLI/export.md +0 -91
- package/dist-skill/docs/CLI/projects.md +0 -107
- package/dist-skill/docs/CLI/studio_publishing.md +0 -52
- package/dist-skill/docs/CLI/validation.md +0 -66
- package/dist-skill/docs-dev/API/core/sdf-advanced.md +0 -92
- package/dist-skill/docs-dev/API/core/sdf-primitives.md +0 -58
- package/dist-skill/docs-dev/API/core/sdf-workflow.md +0 -42
- package/dist-skill/docs-dev/CLI/export.md +0 -91
- package/dist-skill/docs-dev/CLI/projects.md +0 -107
- package/dist-skill/docs-dev/CLI/studio_publishing.md +0 -52
- package/dist-skill/docs-dev/CLI/validation.md +0 -66
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
# API by Concept
|
|
2
2
|
|
|
3
|
-
> **Auto-generated** from `@concept` tags in `src/forge/forge-public-api.ts`. Do not edit by hand — run `npm run gen:docs` to regenerate.
|
|
4
|
-
|
|
5
3
|
Every public API function belongs to one of 16 fundamental concepts. This document groups them by concept rather than by module, making it easy to see the full set of operations for each idea.
|
|
6
4
|
|
|
7
5
|
## Concepts
|
|
8
6
|
|
|
9
|
-
- **[C1: Primitive Construction](#c1-primitive-construction)** — Create geometry from parameters — no input geometry required. *(
|
|
7
|
+
- **[C1: Primitive Construction](#c1-primitive-construction)** — Create geometry from parameters — no input geometry required. *(50 functions)*
|
|
10
8
|
- **[C2: Boolean Combination](#c2-boolean-combination)** — Combine same-dimension geometry using CSG set operations. *(6 functions)*
|
|
11
9
|
- **[C3: Rigid Transform](#c3-rigid-transform)** — Reposition or reorient geometry without changing its shape. *(3 functions)*
|
|
12
|
-
- **[C4: Dimensional Promotion](#c4-dimensional-promotion)** — Convert a 2D profile into a 3D solid (extrude, revolve, loft, sweep). *(
|
|
10
|
+
- **[C4: Dimensional Promotion](#c4-dimensional-promotion)** — Convert a 2D profile into a 3D solid (extrude, revolve, loft, sweep). *(12 functions)*
|
|
13
11
|
- **[C5: Topology Query](#c5-topology-query)** — Select or inspect named faces and edges on a shape. *(3 functions)*
|
|
14
12
|
- **[C6: Edge Feature](#c6-edge-feature)** — Modify edges of a solid — fillets, chamfers, draft, offset. *(7 functions)*
|
|
15
13
|
- **[C7: Pattern Replication](#c7-pattern-replication)** — Duplicate geometry in regular arrangements (linear, circular, mirror). *(6 functions)*
|
|
16
|
-
- **[C8: Constraint Solving](#c8-constraint-solving)** — Define geometry by relationships and let a solver find positions. *(
|
|
17
|
-
- **[C9: Spatial Placement](#c9-spatial-placement)** — Position geometry relative to other geometry using semantic anchors. *(
|
|
14
|
+
- **[C8: Constraint Solving](#c8-constraint-solving)** — Define geometry by relationships and let a solver find positions. *(17 functions)*
|
|
15
|
+
- **[C9: Spatial Placement](#c9-spatial-placement)** — Position geometry relative to other geometry using semantic anchors. *(6 functions)*
|
|
18
16
|
- **[C10: Assembly & Kinematics](#c10-assembly-kinematics)** — Compose parts with joints for kinematic simulation. *(4 functions)*
|
|
19
|
-
- **[C11: Parameterization & UI](#c11-parameterization-ui)** — Declare user-facing controls that drive model geometry. *(
|
|
17
|
+
- **[C11: Parameterization & UI](#c11-parameterization-ui)** — Declare user-facing controls that drive model geometry. *(7 functions)*
|
|
20
18
|
- **[C12: Dimensional Demotion](#c12-dimensional-demotion)** — Extract 2D geometry from a 3D solid (section, projection). *(3 functions)*
|
|
21
19
|
- **[C13: Export & Output](#c13-export-output)** — Convert geometry to external formats (STL, 3MF, SVG, DXF, G-code, PDF). *(5 functions)*
|
|
22
|
-
- **[C14: Visual & Debugging](#c14-visual-debugging)** — Control viewport appearance and debugging aids. *(
|
|
20
|
+
- **[C14: Visual & Debugging](#c14-visual-debugging)** — Control viewport appearance and debugging aids. *(26 functions)*
|
|
23
21
|
- **[C15: Import & Composition](#c15-import-composition)** — Bring external geometry or other ForgeCAD modules into the current script. *(1 functions)*
|
|
24
|
-
- **[C16: Part Library](#c16-part-library)** — Pre-built parametric parts accessible via `lib.*`. *(
|
|
22
|
+
- **[C16: Part Library](#c16-part-library)** — Pre-built parametric parts accessible via `lib.*`. *(4 functions)*
|
|
25
23
|
|
|
26
24
|
---
|
|
27
25
|
|
|
@@ -29,41 +27,280 @@ Every public API function belongs to one of 16 fundamental concepts. This docume
|
|
|
29
27
|
|
|
30
28
|
Create geometry from parameters — no input geometry required.
|
|
31
29
|
|
|
32
|
-
#### `
|
|
30
|
+
#### `sdf.sphere()` — Create an SDF sphere centered at the origin.
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
```ts
|
|
33
|
+
sdf.sphere(radius: number): SdfShape
|
|
34
|
+
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
#### `sdf.box()` — Create an SDF box centered at the origin with given full dimensions (not half-extents).
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
sdf.box(x: number, y: number, z: number): SdfShape
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### `sdf.cylinder()` — Create an SDF cylinder centered at the origin, axis along Z.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
sdf.cylinder(height: number, radius: number): SdfShape
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### `sdf.torus()` — Create an SDF torus centered at the origin, lying in the XY plane.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
sdf.torus(majorRadius: number, minorRadius: number): SdfShape
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### `sdf.capsule()` — Create an SDF capsule centered at the origin, axis along Z.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
sdf.capsule(height: number, radius: number): SdfShape
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### `sdf.cone()` — Create an SDF cone with base at z=0 and tip at z=height.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
sdf.cone(height: number, radius: number): SdfShape
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### `sdf.smoothUnion()` — Smooth union — blends shapes together with a smooth transition radius.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
sdf.smoothUnion(a: SdfShape, b: SdfShape, options: { radius: number; }): SdfShape
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### `sdf.smoothDifference()` — Smooth difference — smoothly subtracts b from a.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
sdf.smoothDifference(a: SdfShape, b: SdfShape, options: { radius: number; }): SdfShape
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### `sdf.smoothIntersection()` — Smooth intersection — smoothly intersects a and b.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
sdf.smoothIntersection(a: SdfShape, b: SdfShape, options: { radius: number; }): SdfShape
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### `sdf.morph()` — Morph between two SDF shapes. t=0 → a, t=1 → b.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
sdf.morph(a: SdfShape, b: SdfShape, t: number): SdfShape
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### `sdf.blend()` — Spatially blend between two SDF patterns. The blend function receives (x, y, z) and returns 0..1: 0 = fully pattern `a`, 1 = fully pattern `b`.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
sdf.blend(a: SdfShape, b: SdfShape, fn: (x: number, y: number, z: number) => number, options?: BlendOptions): SdfShape
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**`BlendOptions`**
|
|
97
|
+
- `constants?: Record<string, number>` — Optional named constants accessible in the blend function.
|
|
98
|
+
|
|
99
|
+
#### `sdf.gyroid()` — Gyroid TPMS lattice — the most common lattice for additive manufacturing.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
sdf.gyroid(options: TpmsOptions): SdfShape
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`TpmsOptions`: `{ cellSize: number, thickness: number }`
|
|
106
|
+
|
|
107
|
+
#### `sdf.schwarzP()` — Schwarz-P TPMS lattice — isotropic pore structure.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
sdf.schwarzP(options: TpmsOptions): SdfShape
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### `sdf.diamond()` — Diamond TPMS lattice — stiffest TPMS structure.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
sdf.diamond(options: TpmsOptions): SdfShape
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### `sdf.lidinoid()` — Lidinoid TPMS lattice — visually distinct from gyroid, popular in research and art.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
sdf.lidinoid(options: TpmsOptions): SdfShape
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### `sdf.noise()` — 3D Simplex noise field — produces organic, natural-looking displacements.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
sdf.noise(options?: NoiseOptions): SdfShape
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**`NoiseOptions`**
|
|
132
|
+
|
|
133
|
+
| Option | Type | Description |
|
|
134
|
+
|--------|------|-------------|
|
|
135
|
+
| `scale?` | `number` | Spatial frequency — smaller = larger features. Default: 0.1 |
|
|
136
|
+
| `amplitude?` | `number` | Peak displacement amplitude. Default: 1 |
|
|
137
|
+
| `octaves?` | `number` | fBm octaves (1 = plain simplex, higher = more detail). Default: 1 |
|
|
138
|
+
| `seed?` | `number` | Seed for deterministic variation. Default: 0 |
|
|
139
|
+
|
|
140
|
+
#### `sdf.voronoi()` — 3D Voronoi pattern — organic cellular structures like bone, coral, or soap bubbles.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
sdf.voronoi(options?: VoronoiOptions): SdfShape
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**`VoronoiOptions`**
|
|
147
|
+
|
|
148
|
+
| Option | Type | Description |
|
|
149
|
+
|--------|------|-------------|
|
|
150
|
+
| `cellSize?` | `number` | Size of each Voronoi cell in world units. Default: 10 |
|
|
151
|
+
| `wallThickness?` | `number` | Wall thickness between cells. Default: 1 |
|
|
152
|
+
| `seed?` | `number` | Seed for deterministic variation. Default: 0 |
|
|
153
|
+
| `suppressionThreshold?` | `number` | Projection weight for membrane suppression (0..1). Controls how much of the surface-normal distance component is removed from Voronoi cell distances. 0 = no projection (classic 3D voronoi with membranes). 1 = full tangent-plane projection (pure 2D pattern on surface). Default: 0.85. Only active when voronoi is intersected with another shape. |
|
|
154
|
+
|
|
155
|
+
#### `sdf.honeycomb()` — Honeycomb (hexagonal) lattice pattern. Intersect with your shape to apply.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
sdf.honeycomb(options?: HoneycombOptions): SdfShape
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**`HoneycombOptions`**
|
|
162
|
+
- `cellSize?: number` — Size of each hex cell. Default: 8
|
|
163
|
+
- `wallThickness?: number` — Wall thickness. Default: 1
|
|
164
|
+
|
|
165
|
+
#### `sdf.waves()` — Sinusoidal wave ridges — parallel ridges along an axis.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
sdf.waves(options?: WavesOptions): SdfShape
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**`WavesOptions`**
|
|
172
|
+
- `wavelength?: number` — Distance between wave peaks. Default: 10
|
|
173
|
+
- `amplitude?: number` — Height of waves. Default: 1
|
|
174
|
+
- `axis?: "x" | "y" | "z"` — Axis along which waves propagate: 'x', 'y', or 'z'. Default: 'x'
|
|
175
|
+
|
|
176
|
+
#### `sdf.knurl()` — Knurl pattern — crossed helical grooves for grips and handles.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
sdf.knurl(options?: KnurlOptions): SdfShape
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**`KnurlOptions`**
|
|
183
|
+
- `pitch?: number` — Distance between knurl ridges. Default: 3
|
|
184
|
+
- `depth?: number` — Depth of knurl grooves. Default: 0.5
|
|
185
|
+
- `angle?: number` — Helix angle in degrees. Default: 30
|
|
186
|
+
|
|
187
|
+
#### `sdf.perforated()` — Perforated plate pattern — regular array of cylindrical holes.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
sdf.perforated(options?: PerforatedOptions): SdfShape
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**`PerforatedOptions`**
|
|
194
|
+
- `radius?: number` — Hole radius. Default: 3
|
|
195
|
+
- `spacing?: number` — Center-to-center spacing. Default: 8
|
|
196
|
+
|
|
197
|
+
#### `sdf.scales()` — Fish/dragon scale pattern — overlapping circular scales in hex-packed rows.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
sdf.scales(options?: ScalesOptions): SdfShape
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**`ScalesOptions`**
|
|
204
|
+
- `size?: number` — Scale diameter. Default: 5
|
|
205
|
+
- `depth?: number` — How much scales protrude. Default: 0.8
|
|
206
|
+
|
|
207
|
+
#### `sdf.brick()` — Brick/stone wall pattern — running bond with mortar grooves.
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
sdf.brick(options?: BrickOptions): SdfShape
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**`BrickOptions`**
|
|
214
|
+
|
|
215
|
+
| Option | Type | Description |
|
|
216
|
+
|--------|------|-------------|
|
|
217
|
+
| `width?` | `number` | Brick width. Default: 10 |
|
|
218
|
+
| `height?` | `number` | Brick height. Default: 5 |
|
|
219
|
+
| `depth?` | `number` | Mortar groove depth. Default: 0.5 |
|
|
220
|
+
| `mortar?` | `number` | Mortar gap width. Default: 1 |
|
|
221
|
+
|
|
222
|
+
#### `sdf.weave()` — Grid lattice pattern — two families of infinite slabs crossing at 90°.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
sdf.weave(options?: WeaveOptions): SdfShape
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**`WeaveOptions`**
|
|
229
|
+
- `spacing?: number` — Thread center-to-center spacing (for intersection patterns). Default: 5
|
|
230
|
+
- `threadRadius?: number` — Thread half-width. Default: 1
|
|
231
|
+
|
|
232
|
+
#### `sdf.basketWeave()` — Basket weave surface pattern — threads with over-under crossings in UV space. Returns a SurfacePattern for use with `.surfaceDisplace()`.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
sdf.basketWeave(options?: BasketWeaveOptions): SurfacePattern
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**`BasketWeaveOptions`**
|
|
239
|
+
- `spacing?: number` — Spacing between threads in mm (both directions). Default: 3
|
|
240
|
+
- `threadWidth?: number` — Thread width in mm. Default: 1.5
|
|
241
|
+
- `depth?: number` — Thread protrusion depth in mm. Default: 0.8
|
|
242
|
+
|
|
243
|
+
#### `sdf.twist()` — Twist an SDF shape around the Z axis.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
sdf.twist(shape: SdfShape, degreesPerUnit: number): SdfShape
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### `sdf.bend()` — Bend an SDF shape around the Z axis.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
sdf.bend(shape: SdfShape, radius: number): SdfShape
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### `sdf.repeat()` — Repeat an SDF shape in space.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
sdf.repeat(shape: SdfShape, spacing: Vec3, count?: Vec3): SdfShape
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### `sdf.SurfacePattern()` — A 2D surface pattern — a heightmap function for use with `.surfaceDisplace()`.
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
sdf.SurfacePattern: typeof SurfacePattern
|
|
265
|
+
```
|
|
37
266
|
|
|
38
|
-
|
|
267
|
+
#### `sdf.fromFunction()` — Create an SDF shape from an arbitrary distance function. You must provide bounds since the function is opaque.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
sdf.fromFunction(fn: (x: number, y: number, z: number) => number, bounds: { min: Vec3; max: Vec3; }, constants?: Record<string, number>): SdfShape
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### `circle2d()` — Create a 2D circle centered at the origin.
|
|
274
|
+
|
|
275
|
+
Omit `segments` for a smooth (auto-tessellated) circle. Pass an integer to get a regular polygon approximation — e.g. `6` for a hexagon, `8` for an octagon.
|
|
39
276
|
|
|
40
277
|
```ts
|
|
41
278
|
circle2d(25).extrude(10); // smooth cylinder
|
|
42
279
|
circle2d(25, 6).extrude(10); // hexagonal prism
|
|
43
280
|
```
|
|
44
281
|
|
|
45
|
-
|
|
282
|
+
```ts
|
|
283
|
+
circle2d(radius: number, segments?: number): Sketch
|
|
284
|
+
```
|
|
46
285
|
|
|
47
286
|
#### `ellipse()` — Create a 2D ellipse centered at the origin.
|
|
48
287
|
|
|
49
|
-
**Example**
|
|
50
|
-
|
|
51
288
|
```ts
|
|
52
289
|
ellipse(30, 15).extrude(5);
|
|
53
290
|
ellipse(30, 15, 32).extrude(5); // lower-resolution approximation
|
|
54
291
|
```
|
|
55
292
|
|
|
56
|
-
|
|
293
|
+
```ts
|
|
294
|
+
ellipse(rx: number, ry: number, segments?: number): Sketch
|
|
295
|
+
```
|
|
57
296
|
|
|
58
297
|
#### `loadFont()` — Pre-load and cache a font for use with `text2d()`.
|
|
59
298
|
|
|
60
|
-
**Details**
|
|
61
|
-
|
|
62
299
|
Fonts are cached by their source string (or `cacheKey` for `ArrayBuffer` sources), so repeated calls with the same path are free. Pre-loading is useful when you call `text2d()` many times with the same font — it avoids repeated disk reads.
|
|
63
300
|
|
|
64
|
-
Built-in font names that work everywhere (browser + CLI):
|
|
301
|
+
Built-in font names that work everywhere (browser + CLI):
|
|
65
302
|
|
|
66
|
-
|
|
303
|
+
- `'sans-serif'` or `'inter'` — bundled Inter Regular
|
|
67
304
|
|
|
68
305
|
```ts
|
|
69
306
|
const font = loadFont('/path/to/Arial Bold.ttf');
|
|
@@ -71,32 +308,28 @@ text2d('Title', { size: 12, font }).extrude(1.5);
|
|
|
71
308
|
text2d('Subtitle', { size: 8, font }).extrude(1);
|
|
72
309
|
```
|
|
73
310
|
|
|
74
|
-
|
|
311
|
+
```ts
|
|
312
|
+
loadFont(source: string | ArrayBuffer, cacheKey?: string): opentype.Font
|
|
313
|
+
```
|
|
75
314
|
|
|
76
315
|
#### `ngon()` — Create a regular polygon inscribed in a circle of the given radius.
|
|
77
316
|
|
|
78
|
-
**Details**
|
|
79
|
-
|
|
80
317
|
`radius` is the center-to-vertex (circumradius) distance. Use `sides` of `3` for a triangle, `6` for a hexagon, etc. The first vertex is at the top (−90° from +X).
|
|
81
318
|
|
|
82
|
-
**Example**
|
|
83
|
-
|
|
84
319
|
```ts
|
|
85
320
|
ngon(6, 20).extrude(10); // hexagonal prism, circumradius 20
|
|
86
321
|
```
|
|
87
322
|
|
|
88
|
-
|
|
323
|
+
```ts
|
|
324
|
+
ngon(sides: number, radius: number): Sketch
|
|
325
|
+
```
|
|
89
326
|
|
|
90
327
|
#### `path()` — Create a new `PathBuilder` for tracing a 2D outline point by point.
|
|
91
328
|
|
|
92
|
-
**Details**
|
|
93
|
-
|
|
94
329
|
`PathBuilder` is a fluent API for constructing 2D profiles using a mix of line segments, arcs, bezier curves, and splines. Always start with `.moveTo(x, y)` to set the starting point. Call `.close()` to get a filled `Sketch`, or `.stroke(width)` to thicken an open polyline into a solid profile.
|
|
95
330
|
|
|
96
331
|
Edge labels can be assigned with `.label('name')` after any segment — they propagate through extrusion, revolve, loft, and sweep into named faces on the resulting `Shape`.
|
|
97
332
|
|
|
98
|
-
**Example**
|
|
99
|
-
|
|
100
333
|
```ts
|
|
101
334
|
// Closed triangle
|
|
102
335
|
const triangle = path().moveTo(0, 0).lineH(50).lineV(30).close();
|
|
@@ -113,21 +346,21 @@ const slot = path()
|
|
|
113
346
|
.close();
|
|
114
347
|
```
|
|
115
348
|
|
|
116
|
-
|
|
349
|
+
```ts
|
|
350
|
+
path(): PathBuilder
|
|
351
|
+
```
|
|
117
352
|
|
|
118
353
|
#### `polygon()` — Create a 2D polygon from an array of `[x, y]` points or `Point2D` objects.
|
|
119
354
|
|
|
120
|
-
**Details**
|
|
121
|
-
|
|
122
355
|
Winding order is normalized automatically — clockwise (CW) input is silently reversed to CCW before being passed to the geometry kernel.
|
|
123
356
|
|
|
124
|
-
**Example**
|
|
125
|
-
|
|
126
357
|
```ts
|
|
127
358
|
polygon([[0, 0], [50, 0], [25, 40]]).extrude(5); // triangle
|
|
128
359
|
```
|
|
129
360
|
|
|
130
|
-
|
|
361
|
+
```ts
|
|
362
|
+
polygon(points: ([ number, number ] | Point2D)[]): Sketch
|
|
363
|
+
```
|
|
131
364
|
|
|
132
365
|
#### `polygonVertices()` — Compute the vertex positions of a regular polygon.
|
|
133
366
|
|
|
@@ -145,7 +378,9 @@ const v3 = [center.x + r, center.y];
|
|
|
145
378
|
const [v1, v2, v3] = polygonVertices(3, r);
|
|
146
379
|
```
|
|
147
380
|
|
|
148
|
-
|
|
381
|
+
```ts
|
|
382
|
+
polygonVertices(sides: number, radius: number, options?: PolygonVerticesOptions): LayoutPoint[]
|
|
383
|
+
```
|
|
149
384
|
|
|
150
385
|
**`PolygonVerticesOptions`**
|
|
151
386
|
- `startDeg?: number` — Angle of the first vertex in degrees (default: 90 = top).
|
|
@@ -156,57 +391,55 @@ const [v1, v2, v3] = polygonVertices(3, r);
|
|
|
156
391
|
|
|
157
392
|
#### `rect()` — Create a 2D rectangle centered at the origin.
|
|
158
393
|
|
|
159
|
-
**Example**
|
|
160
|
-
|
|
161
394
|
```ts
|
|
162
395
|
rect(40, 20).extrude(5);
|
|
163
396
|
```
|
|
164
397
|
|
|
165
|
-
|
|
398
|
+
```ts
|
|
399
|
+
rect(width: number, height: number): Sketch
|
|
400
|
+
```
|
|
166
401
|
|
|
167
402
|
#### `arcSlot()` — Create an arc-shaped slot (banana / annular sector) centered at the origin.
|
|
168
403
|
|
|
169
|
-
**Details**
|
|
170
|
-
|
|
171
404
|
The slot is symmetric about the +X axis. The two ends are closed with semicircular caps. `pitchRadius` is the distance from the origin to the centerline of the slot, and `thickness` is the radial width of the slot.
|
|
172
405
|
|
|
173
|
-
**Example**
|
|
174
|
-
|
|
175
406
|
```ts
|
|
176
407
|
arcSlot(135, 74, 40).extrude(5); // pitch R135, 74° sweep, 40mm wide
|
|
177
408
|
```
|
|
178
409
|
|
|
179
|
-
|
|
410
|
+
```ts
|
|
411
|
+
arcSlot(pitchRadius: number, sweepDeg: number, thickness: number): Sketch
|
|
412
|
+
```
|
|
180
413
|
|
|
181
414
|
#### `roundedRect()` — Create a 2D rectangle with rounded corners, centered at the origin.
|
|
182
415
|
|
|
183
|
-
**Details**
|
|
184
|
-
|
|
185
416
|
The corner radius is automatically clamped to `min(width/2, height/2)` so it can never exceed the shape dimensions.
|
|
186
417
|
|
|
187
|
-
**Example**
|
|
188
|
-
|
|
189
418
|
```ts
|
|
190
419
|
roundedRect(60, 30, 5).extrude(3);
|
|
191
420
|
```
|
|
192
421
|
|
|
193
|
-
|
|
422
|
+
```ts
|
|
423
|
+
roundedRect(width: number, height: number, radius: number): Sketch
|
|
424
|
+
```
|
|
194
425
|
|
|
195
426
|
#### `slot()` — Create a slot (oblong / stadium shape) — a rectangle with semicircular ends, centered at the origin.
|
|
196
427
|
|
|
197
|
-
**Example**
|
|
198
|
-
|
|
199
428
|
```ts
|
|
200
429
|
slot(40, 10).extrude(3); // 40mm long, 10mm wide slot
|
|
201
430
|
```
|
|
202
431
|
|
|
203
|
-
|
|
432
|
+
```ts
|
|
433
|
+
slot(length: number, width: number): Sketch
|
|
434
|
+
```
|
|
204
435
|
|
|
205
436
|
#### `spline2d()` — Build a smooth Catmull-Rom spline sketch from 2D control points.
|
|
206
437
|
|
|
207
438
|
A closed spline (default) returns a filled profile. An open spline requires a strokeWidth option to produce a solid sketch. Use tension (0..1, default 0.5) to control curve tightness.
|
|
208
439
|
|
|
209
|
-
|
|
440
|
+
```ts
|
|
441
|
+
spline2d(points: Vec2[], options?: Spline2DOptions): Sketch
|
|
442
|
+
```
|
|
210
443
|
|
|
211
444
|
**`Spline2DOptions`**
|
|
212
445
|
|
|
@@ -220,30 +453,28 @@ A closed spline (default) returns a filled profile. An open spline requires a st
|
|
|
220
453
|
|
|
221
454
|
#### `star()` — Create a star shape with alternating outer and inner radii.
|
|
222
455
|
|
|
223
|
-
**Example**
|
|
224
|
-
|
|
225
456
|
```ts
|
|
226
457
|
star(5, 30, 12).extrude(4); // five-pointed star
|
|
227
458
|
```
|
|
228
459
|
|
|
229
|
-
|
|
460
|
+
```ts
|
|
461
|
+
star(points: number, outerR: number, innerR: number): Sketch
|
|
462
|
+
```
|
|
230
463
|
|
|
231
464
|
#### `stroke()` — Create a stroked polyline sketch from an array of 2D points.
|
|
232
465
|
|
|
233
|
-
|
|
466
|
+
```ts
|
|
467
|
+
stroke(points: [ number, number ][], width: number, join?: "Round" | "Square"): Sketch
|
|
468
|
+
```
|
|
234
469
|
|
|
235
470
|
#### `text2d()` — Build a filled 2D Sketch from a text string.
|
|
236
471
|
|
|
237
|
-
**Details**
|
|
238
|
-
|
|
239
472
|
The Sketch origin is at the left end of the text baseline by default. Use `align` and `baseline` options to adjust placement. Text is rendered using the bundled Inter font by default, or any TTF/OTF/WOFF font you provide.
|
|
240
473
|
|
|
241
474
|
Alignment reference table:
|
|
242
475
|
|
|
243
476
|
| `align` | `baseline` | Origin | |------------|--------------|-------------------------------------| | `'left'` | `'baseline'` | Bottom-left of first char (default) | | `'center'` | `'center'` | Dead center of text block | | `'right'` | `'top'` | Top-right corner |
|
|
244
477
|
|
|
245
|
-
**Example**
|
|
246
|
-
|
|
247
478
|
```ts
|
|
248
479
|
// Extruded nameplate
|
|
249
480
|
text2d('FORGE CAD', { size: 8 }).extrude(1.2);
|
|
@@ -263,7 +494,9 @@ const font = loadFont('/path/to/Arial Bold.ttf');
|
|
|
263
494
|
text2d('Title', { size: 12, font }).extrude(1.5);
|
|
264
495
|
```
|
|
265
496
|
|
|
266
|
-
|
|
497
|
+
```ts
|
|
498
|
+
text2d(content: string, options?: TextOptions): Sketch
|
|
499
|
+
```
|
|
267
500
|
|
|
268
501
|
**`TextOptions`**
|
|
269
502
|
|
|
@@ -273,43 +506,49 @@ text2d('Title', { size: 12, font }).extrude(1.5);
|
|
|
273
506
|
| `letterSpacing?` | `number` | Extra space between characters in model units. Negative values tighten the tracking. |
|
|
274
507
|
| `align?` | `"left" | "center" | "right"` | Horizontal alignment relative to x = 0. - `'left'` — left edge at x = 0 (default) - `'center'` — centred on x = 0 - `'right'` — right edge at x = 0 |
|
|
275
508
|
| `baseline?` | `"baseline" | "center" | "top"` | Vertical alignment relative to y = 0. - `'baseline'` — y = 0 is the text baseline (bottom of capital letters) - `'center'` — y = 0 is the vertical midpoint of the cap height - `'top'` — y = 0 is the top of capital letters |
|
|
276
|
-
| `font?` | `string | opentype
|
|
509
|
+
| `font?` | `string | opentype.Font` | Font to use for text rendering. - `'sans-serif'` or `'inter'` — bundled Inter font (works everywhere, including browser) - **file path** — path to a TTF, OTF, or WOFF font file (CLI/Node only) - **Font object** — a previously loaded opentype.js Font (from `loadFont()`) - **omitted** — uses the bundled Inter font (same as `'sans-serif'`) text2d('Hello World', { size: 10 }) // default Inter text2d('Custom Font', { size: 10, font: '/path/to/font.ttf' }) |
|
|
277
510
|
| `flattenTolerance?` | `number` | Bezier flattening tolerance in model units. Smaller = more polygon segments = smoother curves. |
|
|
278
511
|
|
|
279
512
|
#### `textWidth()` — Measure the rendered advance width of a string without creating any geometry.
|
|
280
513
|
|
|
281
|
-
**Details**
|
|
282
|
-
|
|
283
514
|
Uses the same font metrics as `text2d()`. Useful for computing layout dimensions before building the actual sketch — e.g. sizing a plate to fit a label.
|
|
284
515
|
|
|
285
|
-
**Example**
|
|
286
|
-
|
|
287
516
|
```ts
|
|
288
517
|
const w = textWidth('SERIAL: 001', { size: 6 });
|
|
289
518
|
const plate = box(w + 10, 12, 2);
|
|
290
519
|
```
|
|
291
520
|
|
|
292
|
-
|
|
521
|
+
```ts
|
|
522
|
+
textWidth(content: string, options?: Pick<TextOptions, "size" | "letterSpacing" | "font">): number
|
|
523
|
+
```
|
|
293
524
|
|
|
294
525
|
#### `box()` — Create a rectangular box. Centered on XY, base at Z=0.
|
|
295
526
|
|
|
296
527
|
For named faces, build from a labeled sketch: `rect(x, y).labelEdges('s', 'e', 'n', 'w').extrude(z, { labels: { start: 'bottom', end: 'top' } })`.
|
|
297
528
|
|
|
298
|
-
|
|
529
|
+
```ts
|
|
530
|
+
box(x: number, y: number, z: number): Shape
|
|
531
|
+
```
|
|
299
532
|
|
|
300
533
|
#### `cylinder()` — Create a cylinder or cone with named faces and edges. Centered on XY, base at Z=0.
|
|
301
534
|
|
|
302
535
|
When radiusTop differs from radius, creates a tapered cone. Use the segments parameter to create regular prisms (e.g. 6 for a hexagonal prism). Returns a Shape with faces: top, bottom, side; and edges: top-rim, bottom-rim.
|
|
303
536
|
|
|
304
|
-
|
|
537
|
+
```ts
|
|
538
|
+
cylinder(height: number, radius: number, radiusTop?: number, segments?: number): Shape
|
|
539
|
+
```
|
|
305
540
|
|
|
306
541
|
#### `sphere()` — Create a sphere centered at the origin. Use segments for lower-poly approximations.
|
|
307
542
|
|
|
308
|
-
|
|
543
|
+
```ts
|
|
544
|
+
sphere(radius: number, segments?: number): Shape
|
|
545
|
+
```
|
|
309
546
|
|
|
310
547
|
#### `torus()` — Create a torus (donut shape) lying in the XY plane. Centered on all axes (origin is the ring center).
|
|
311
548
|
|
|
312
|
-
|
|
549
|
+
```ts
|
|
550
|
+
torus(majorRadius: number, minorRadius: number, segments?: number): Shape
|
|
551
|
+
```
|
|
313
552
|
|
|
314
553
|
---
|
|
315
554
|
|
|
@@ -319,63 +558,63 @@ Combine same-dimension geometry using CSG set operations.
|
|
|
319
558
|
|
|
320
559
|
#### `difference2d()` — Subtract one or more 2D sketches from a base sketch.
|
|
321
560
|
|
|
322
|
-
**Details**
|
|
323
|
-
|
|
324
561
|
The first sketch is the base; all subsequent sketches are subtracted from it. Accepts individual sketches or arrays: `difference2d(base, c1, c2)` or `difference2d([base, c1, c2])`. Uses Manifold's batch operation — faster than chaining `.subtract()` one by one.
|
|
325
562
|
|
|
326
|
-
**Example**
|
|
327
|
-
|
|
328
563
|
```ts
|
|
329
564
|
const donut = difference2d(circle2d(50), circle2d(30));
|
|
330
565
|
```
|
|
331
566
|
|
|
332
|
-
|
|
567
|
+
```ts
|
|
568
|
+
difference2d(...inputs: SketchOperandInput[]): Sketch
|
|
569
|
+
```
|
|
333
570
|
|
|
334
571
|
#### `intersection2d()` — Keep only the area where all input sketches overlap (intersection boolean).
|
|
335
572
|
|
|
336
|
-
**Details**
|
|
337
|
-
|
|
338
573
|
Accepts individual sketches or arrays: `intersection2d(a, b)` or `intersection2d([a, b, c])`. Uses Manifold's batch operation — faster than chaining `.intersect()` one by one.
|
|
339
574
|
|
|
340
|
-
**Example**
|
|
341
|
-
|
|
342
575
|
```ts
|
|
343
576
|
const lens = intersection2d(circle2d(30).translate(-10, 0), circle2d(30).translate(10, 0));
|
|
344
577
|
```
|
|
345
578
|
|
|
346
|
-
|
|
579
|
+
```ts
|
|
580
|
+
intersection2d(...inputs: SketchOperandInput[]): Sketch
|
|
581
|
+
```
|
|
347
582
|
|
|
348
583
|
#### `union2d()` — Combine 2D sketches into a single profile using an additive boolean union.
|
|
349
584
|
|
|
350
|
-
**Details**
|
|
351
|
-
|
|
352
585
|
Accepts individual sketches or arrays: `union2d(a, b, c)` or `union2d([a, b, c])`. Uses Manifold's batch operation — faster than chaining `.add()` one by one when combining many sketches.
|
|
353
586
|
|
|
354
|
-
**Example**
|
|
355
|
-
|
|
356
587
|
```ts
|
|
357
588
|
const cross = union2d(rect(60, 10), rect(10, 60));
|
|
358
589
|
```
|
|
359
590
|
|
|
360
|
-
|
|
591
|
+
```ts
|
|
592
|
+
union2d(...inputs: SketchOperandInput[]): Sketch
|
|
593
|
+
```
|
|
361
594
|
|
|
362
595
|
#### `union()` — Combine shapes into a single solid (additive boolean).
|
|
363
596
|
|
|
364
597
|
Accepts individual shapes, or an array of shapes. The first operand's color is preserved in the result.
|
|
365
598
|
|
|
366
|
-
|
|
599
|
+
```ts
|
|
600
|
+
union(...inputs: ShapeOperandInput[]): Shape
|
|
601
|
+
```
|
|
367
602
|
|
|
368
603
|
#### `difference()` — Subtract shapes from a base shape (subtractive boolean).
|
|
369
604
|
|
|
370
605
|
The first shape is the base; all subsequent shapes are subtracted from it. Accepts individual shapes, or an array of shapes.
|
|
371
606
|
|
|
372
|
-
|
|
607
|
+
```ts
|
|
608
|
+
difference(...inputs: ShapeOperandInput[]): Shape
|
|
609
|
+
```
|
|
373
610
|
|
|
374
611
|
#### `intersection()` — Keep only the overlapping volume of the input shapes (intersection boolean).
|
|
375
612
|
|
|
376
613
|
Requires at least two shapes. Accepts individual shapes, or an array.
|
|
377
614
|
|
|
378
|
-
|
|
615
|
+
```ts
|
|
616
|
+
intersection(...inputs: ShapeOperandInput[]): Shape
|
|
617
|
+
```
|
|
379
618
|
|
|
380
619
|
---
|
|
381
620
|
|
|
@@ -387,17 +626,23 @@ Reposition or reorient geometry without changing its shape.
|
|
|
387
626
|
|
|
388
627
|
Use for clarity when the unit of an angle value would otherwise be ambiguous — e.g. `param("Angle", degrees(45))`.
|
|
389
628
|
|
|
390
|
-
|
|
629
|
+
```ts
|
|
630
|
+
degrees(deg: number): number
|
|
631
|
+
```
|
|
391
632
|
|
|
392
633
|
#### `radians()` — Convert radians to degrees.
|
|
393
634
|
|
|
394
635
|
ForgeCAD's public API uses degrees throughout. Use this when you have a radian value (e.g. from `Math.atan2`) that you want to express in degrees.
|
|
395
636
|
|
|
396
|
-
|
|
637
|
+
```ts
|
|
638
|
+
radians(rad: number): number
|
|
639
|
+
```
|
|
397
640
|
|
|
398
641
|
#### `composeChain()` — Compose transforms in chain order. Equivalent to Transform.identity().mul(a).mul(b).mul(c)...
|
|
399
642
|
|
|
400
|
-
|
|
643
|
+
```ts
|
|
644
|
+
composeChain(...steps: TransformInput[]): Transform
|
|
645
|
+
```
|
|
401
646
|
|
|
402
647
|
---
|
|
403
648
|
|
|
@@ -405,11 +650,77 @@ ForgeCAD's public API uses degrees throughout. Use this when you have a radian v
|
|
|
405
650
|
|
|
406
651
|
Convert a 2D profile into a 3D solid (extrude, revolve, loft, sweep).
|
|
407
652
|
|
|
653
|
+
#### `nurbs3d()` — Create a NURBS curve from control points.
|
|
654
|
+
|
|
655
|
+
With default options, creates a cubic non-rational B-spline with uniform clamped knots. Set `weights` for rational curves (exact circles, conics). Set `degree` for linear (1), quadratic (2), cubic (3), or higher-order curves.
|
|
656
|
+
|
|
657
|
+
```js
|
|
658
|
+
// Simple cubic B-spline through control points
|
|
659
|
+
const curve = nurbs3d([[0,0,0], [10,5,0], [20,-5,10], [30,0,5]]);
|
|
660
|
+
const tube = sweep(circle(2), curve);
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
```js
|
|
664
|
+
// Rational quadratic — exact circular arc
|
|
665
|
+
const arc = nurbs3d(
|
|
666
|
+
[[10,0,0], [10,10,0], [0,10,0]],
|
|
667
|
+
{ degree: 2, weights: [1, Math.SQRT1_2, 1] }
|
|
668
|
+
);
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
```ts
|
|
672
|
+
nurbs3d(points: Vec3[], options?: NurbsCurve3DOptions): NurbsCurve3D
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**`NurbsCurve3DOptions`**
|
|
676
|
+
|
|
677
|
+
| Option | Type | Description |
|
|
678
|
+
|--------|------|-------------|
|
|
679
|
+
| `degree?` | `number` | Polynomial degree (default 3 = cubic). Must be ≥ 1. |
|
|
680
|
+
| `weights?` | `number[]` | Rational weights, one per control point (default: all 1.0 = non-rational). |
|
|
681
|
+
| `knots?` | `number[]` | Knot vector (default: uniform clamped). Must have length = controlPoints.length + degree + 1. |
|
|
682
|
+
| `closed?` | `boolean` | Whether the curve is closed/periodic (default false). |
|
|
683
|
+
|
|
684
|
+
#### `nurbsSurface()` — Create a NURBS surface from a grid of control points.
|
|
685
|
+
|
|
686
|
+
The control grid is indexed as `controlGrid[u][v]` — each row is a curve in the V direction, and columns trace curves in the U direction.
|
|
687
|
+
|
|
688
|
+
With default options, creates a bicubic non-rational B-spline surface with uniform clamped knots.
|
|
689
|
+
|
|
690
|
+
```js
|
|
691
|
+
// Simple 4×4 control grid — a gently curved surface
|
|
692
|
+
const grid = [
|
|
693
|
+
[[0,0,0], [10,0,2], [20,0,2], [30,0,0]],
|
|
694
|
+
[[0,10,1], [10,10,5], [20,10,5], [30,10,1]],
|
|
695
|
+
[[0,20,1], [10,20,5], [20,20,5], [30,20,1]],
|
|
696
|
+
[[0,30,0], [10,30,2], [20,30,2], [30,30,0]],
|
|
697
|
+
];
|
|
698
|
+
const surface = nurbsSurface(grid, { thickness: 2 });
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
```ts
|
|
702
|
+
nurbsSurface(controlGrid: Vec3[][], options?: NurbsSurfaceOptions): Shape
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**`NurbsSurfaceOptions`**
|
|
706
|
+
|
|
707
|
+
| Option | Type | Description |
|
|
708
|
+
|--------|------|-------------|
|
|
709
|
+
| `degreeU?` | `number` | Degree in U direction (default 3). |
|
|
710
|
+
| `degreeV?` | `number` | Degree in V direction (default 3). |
|
|
711
|
+
| `weights?` | `number[][]` | Weights grid — same dimensions as controlGrid (default: all 1.0). |
|
|
712
|
+
| `knotsU?` | `number[]` | Knot vector in U direction (default: uniform clamped). |
|
|
713
|
+
| `knotsV?` | `number[]` | Knot vector in V direction (default: uniform clamped). |
|
|
714
|
+
| `thickness?` | `number` | Sheet thickness — if > 0, thickens the surface into a solid (default 0 = surface only). |
|
|
715
|
+
| `resolution?` | `number` | Tessellation resolution — points per direction (default 32). |
|
|
716
|
+
|
|
408
717
|
#### `connectEdges()` — Create a transition surface or solid bridge between two edge segments.
|
|
409
718
|
|
|
410
719
|
Tangents can be inferred from neighboring geometry or supplied explicitly through `options`. This is useful for loft-like blends where you want a direct connection between two edge spans.
|
|
411
720
|
|
|
412
|
-
|
|
721
|
+
```ts
|
|
722
|
+
connectEdges(edgeA: EdgeSegment, edgeB: EdgeSegment, options?: ConnectEdgesOptions): Shape
|
|
723
|
+
```
|
|
413
724
|
|
|
414
725
|
**`EdgeSegment`**
|
|
415
726
|
|
|
@@ -435,7 +746,7 @@ Tangents can be inferred from neighboring geometry or supplied explicitly throug
|
|
|
435
746
|
|--------|------|-------------|
|
|
436
747
|
| `profile?` | `Sketch` | Cross-section profile to sweep along the transition curve. If omitted, a circular profile with `radius` is used. |
|
|
437
748
|
| `radius?` | `number` | Radius of circular cross-section (used when `profile` is omitted). Default: 5% of chord length. |
|
|
438
|
-
| `up?` | `Vec3
|
|
749
|
+
| `up?` | `Vec3` | Preferred up vector for the sweep frame. Default: auto-detected. |
|
|
439
750
|
| `edgeLength?` | `number` | Edge length for level-set meshing. Smaller = finer. |
|
|
440
751
|
| `boundsPadding?` | `number` | Extra bounds padding for level-set meshing. |
|
|
441
752
|
| `width`, `height` | | — |
|
|
@@ -448,8 +759,8 @@ Tangents can be inferred from neighboring geometry or supplied explicitly throug
|
|
|
448
759
|
| `endB?` | `EdgeEnd` | Which end of edge B to connect. Default: 'start'. |
|
|
449
760
|
| `tangentModeA?` | `TangentMode` | Tangent mode for edge A. Default: 'along'. |
|
|
450
761
|
| `tangentModeB?` | `TangentMode` | Tangent mode for edge B. Default: 'along'. |
|
|
451
|
-
| `tangentA?` | `Vec3
|
|
452
|
-
| `tangentB?` | `Vec3
|
|
762
|
+
| `tangentA?` | `Vec3` | Explicit tangent for edge A. |
|
|
763
|
+
| `tangentB?` | `Vec3` | Explicit tangent for edge B. |
|
|
453
764
|
| `flipA?` | `boolean` | Flip tangent A. |
|
|
454
765
|
| `flipB?` | `boolean` | Flip tangent B. |
|
|
455
766
|
|
|
@@ -457,15 +768,17 @@ Tangents can be inferred from neighboring geometry or supplied explicitly throug
|
|
|
457
768
|
|
|
458
769
|
The curve starts at `a.point` tangent to `a.tangent` with curvature `a.curvature`, and ends at `b.point` tangent to `b.tangent` with curvature `b.curvature`, with smooth G2-continuous interpolation matching position, tangent, and curvature.
|
|
459
770
|
|
|
460
|
-
|
|
771
|
+
```ts
|
|
772
|
+
hermiteTransitionG2(a: QuinticHermiteCurveEndpoint, b: QuinticHermiteCurveEndpoint): QuinticHermiteCurve3D
|
|
773
|
+
```
|
|
461
774
|
|
|
462
775
|
**`QuinticHermiteCurveEndpoint`**
|
|
463
776
|
|
|
464
777
|
| Option | Type | Description |
|
|
465
778
|
|--------|------|-------------|
|
|
466
|
-
| `point` | `Vec3
|
|
467
|
-
| `tangent` | `Vec3
|
|
468
|
-
| `curvature?` | `Vec3
|
|
779
|
+
| `point` | `Vec3` | Position |
|
|
780
|
+
| `tangent` | `Vec3` | Tangent direction (will be normalized internally) |
|
|
781
|
+
| `curvature?` | `Vec3` | Second derivative / curvature vector. Default [0, 0, 0]. |
|
|
469
782
|
| `weight?` | `number` | Weight: scales tangent magnitude relative to chord length. Default 1.0. |
|
|
470
783
|
|
|
471
784
|
#### `loft()` — Loft between multiple sketches along Z stations.
|
|
@@ -474,7 +787,9 @@ Profiles can differ in topology and vertex count: interpolation is done on signe
|
|
|
474
787
|
|
|
475
788
|
Performance note: loft is significantly heavier than primitive/extrude/revolve. If the part is axis-symmetric (bottles, vases, knobs), prefer revolve().
|
|
476
789
|
|
|
477
|
-
|
|
790
|
+
```ts
|
|
791
|
+
loft(profiles: Sketch[], heights: number[], options?: LoftOptions): Shape
|
|
792
|
+
```
|
|
478
793
|
|
|
479
794
|
**`LoftOptions`**
|
|
480
795
|
- `edgeLength?: number` — Marching-grid edge length for level-set meshing. Smaller = finer.
|
|
@@ -490,7 +805,9 @@ Internally uses variableSweep infrastructure with SDF interpolation.
|
|
|
490
805
|
|
|
491
806
|
Performance note: uses level-set meshing, heavier than simple loft().
|
|
492
807
|
|
|
493
|
-
|
|
808
|
+
```ts
|
|
809
|
+
loftAlongSpine(profiles: Sketch[], spine: Curve3D | Vec3[], tValues: number[], options?: LoftAlongSpineOptions): Shape
|
|
810
|
+
```
|
|
494
811
|
|
|
495
812
|
**`LoftAlongSpineOptions`**
|
|
496
813
|
|
|
@@ -499,13 +816,15 @@ Performance note: uses level-set meshing, heavier than simple loft().
|
|
|
499
816
|
| `samples?` | `number` | Number of samples when spine is a Curve3D. Default 48. |
|
|
500
817
|
| `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
|
|
501
818
|
| `boundsPadding?` | `number` | Optional extra bounds padding. |
|
|
502
|
-
| `up?` | `Vec3
|
|
819
|
+
| `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
|
|
503
820
|
|
|
504
821
|
#### `spline3d()` — Create a reusable 3D spline curve object (Catmull-Rom).
|
|
505
822
|
|
|
506
823
|
The returned Curve3D provides sample(), pointAt(t), tangentAt(t), and length() for downstream use in sweep() or manual path operations.
|
|
507
824
|
|
|
508
|
-
|
|
825
|
+
```ts
|
|
826
|
+
spline3d(points: Vec3[], options?: Spline3DOptions): Curve3D
|
|
827
|
+
```
|
|
509
828
|
|
|
510
829
|
**`Spline3DOptions`**
|
|
511
830
|
- `closed?: boolean` — Closed loop (default false).
|
|
@@ -513,7 +832,12 @@ The returned Curve3D provides sample(), pointAt(t), tangentAt(t), and length() f
|
|
|
513
832
|
|
|
514
833
|
#### `surfacePatch()` — Create a smooth surface patch from 4 boundary curves (Coons patch).
|
|
515
834
|
|
|
516
|
-
The four curves form the boundary of a quadrilateral patch:
|
|
835
|
+
The four curves form the boundary of a quadrilateral patch:
|
|
836
|
+
|
|
837
|
+
- bottom: u=0..1 at v=0 (from corner00 to corner10)
|
|
838
|
+
- top: u=0..1 at v=1 (from corner01 to corner11)
|
|
839
|
+
- left: v=0..1 at u=0 (from corner00 to corner01)
|
|
840
|
+
- right: v=0..1 at u=1 (from corner10 to corner11)
|
|
517
841
|
|
|
518
842
|
The interior is filled using bilinear Coons patch interpolation: P(u,v) = Lc(u,v) + Ld(u,v) - B(u,v)
|
|
519
843
|
|
|
@@ -521,19 +845,19 @@ The result is a thin solid created by offsetting the surface mesh along its norm
|
|
|
521
845
|
|
|
522
846
|
Note: curves should meet at corners. Small gaps are tolerated.
|
|
523
847
|
|
|
524
|
-
|
|
848
|
+
```ts
|
|
849
|
+
surfacePatch(curves: { ... }, options?: SurfacePatchOptions): Shape
|
|
850
|
+
```
|
|
525
851
|
|
|
526
852
|
**`SurfacePatchOptions`**
|
|
527
853
|
- `resolution?: number` — Number of samples along each direction. Default 24.
|
|
528
854
|
- `thickness?: number` — Thickness of the generated solid. Default 0.5.
|
|
529
855
|
|
|
530
|
-
#### `sweep()`
|
|
531
|
-
|
|
532
|
-
Path can be a Curve3D from spline3d() or an array of [x,y,z] points (polyline). The profile is interpreted in the local frame normal plane. Compatible sweeps can export through the OCCT exact route using the canonical path representation.
|
|
856
|
+
#### `sweep()`
|
|
533
857
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
858
|
+
```ts
|
|
859
|
+
sweep(profile: Sketch, path: SweepPathInput, options?: SweepOptions): Shape
|
|
860
|
+
```
|
|
537
861
|
|
|
538
862
|
**`SweepOptions`**
|
|
539
863
|
|
|
@@ -542,7 +866,7 @@ Performance note: sweep uses level-set meshing internally. Prefer direct primiti
|
|
|
542
866
|
| `samples?` | `number` | Number of samples when path is a Curve3D. Default 48. |
|
|
543
867
|
| `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
|
|
544
868
|
| `boundsPadding?` | `number` | Optional extra bounds padding. |
|
|
545
|
-
| `up?` | `Vec3
|
|
869
|
+
| `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
|
|
546
870
|
|
|
547
871
|
#### `variableSweep()` — Sweep a variable cross-section along a 3D spine curve.
|
|
548
872
|
|
|
@@ -552,7 +876,9 @@ Each section specifies a t parameter (0 = start, 1 = end of spine) and a 2D prof
|
|
|
552
876
|
|
|
553
877
|
Performance note: like sweep(), this uses level-set meshing internally.
|
|
554
878
|
|
|
555
|
-
|
|
879
|
+
```ts
|
|
880
|
+
variableSweep(spine: SweepPathInput, sections: VariableSweepSection[], options?: VariableSweepOptions): Shape
|
|
881
|
+
```
|
|
556
882
|
|
|
557
883
|
**`VariableSweepSection`**
|
|
558
884
|
- `t: number` — Parameter along the spine (0 = start, 1 = end).
|
|
@@ -565,7 +891,7 @@ Performance note: like sweep(), this uses level-set meshing internally.
|
|
|
565
891
|
| `samples?` | `number` | Number of samples when spine is a Curve3D. Default 48. |
|
|
566
892
|
| `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
|
|
567
893
|
| `boundsPadding?` | `number` | Optional extra bounds padding. |
|
|
568
|
-
| `up?` | `Vec3
|
|
894
|
+
| `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
|
|
569
895
|
|
|
570
896
|
#### `transitionCurve()` — Create a smooth transition curve between two edges.
|
|
571
897
|
|
|
@@ -574,11 +900,11 @@ Returns a `HermiteCurve3D` that starts at `edgeA.point` tangent to `edgeA.tangen
|
|
|
574
900
|
The curve maintains G1 continuity (matching tangent direction) at both endpoints. Weight parameters control the shape of the transition.
|
|
575
901
|
|
|
576
902
|
```js
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
903
|
+
```js
|
|
904
|
+
|
|
905
|
+
// Connect two edges with a balanced transition const curve = transitionCurve( { point: [0, 0, 0], tangent: [1, 0, 0] }, { point: [10, 5, 0], tangent: [1, 0, 0] }, );
|
|
906
|
+
|
|
907
|
+
```
|
|
582
908
|
|
|
583
909
|
// Weighted: curve hugs edge A longer
|
|
584
910
|
const weighted = transitionCurve(
|
|
@@ -588,24 +914,25 @@ const weighted = transitionCurve(
|
|
|
588
914
|
);
|
|
589
915
|
```
|
|
590
916
|
|
|
591
|
-
|
|
917
|
+
```ts
|
|
918
|
+
transitionCurve(edgeA: TransitionEdge, edgeB: TransitionEdge, options?: TransitionCurveOptions): HermiteCurve3D
|
|
919
|
+
```
|
|
592
920
|
|
|
593
921
|
**`TransitionEdge`**
|
|
594
|
-
- `point: Vec3
|
|
595
|
-
- `tangent: Vec3
|
|
596
|
-
- `normal?: Vec3
|
|
922
|
+
- `point: Vec3` — Connection point on the edge. Can be any point along the edge where the transition should connect.
|
|
923
|
+
- `tangent: Vec3` — Tangent direction at the connection point. This is the direction the curve should initially follow when leaving this edge. For a straight edge, this is typically the edge direction pointing "outward" (away from the body of the edge, toward the other edge).
|
|
924
|
+
- `normal?: Vec3` — Surface normal at the connection point (optional). Used as a hint for the sweep frame's up vector.
|
|
597
925
|
|
|
598
926
|
#### `transitionSurface()` — Create a solid transition surface between two edges by sweeping a profile along a Hermite transition curve.
|
|
599
927
|
|
|
600
928
|
This produces a watertight solid that smoothly connects the two edges. Works with both Manifold and OCCT backends.
|
|
601
929
|
|
|
602
930
|
```js
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
);
|
|
931
|
+
```js
|
|
932
|
+
|
|
933
|
+
// Circular tube connecting two edges const tube = transitionSurface( { point: [0, 0, 0], tangent: [1, 0, 0] }, { point: [10, 5, 3], tangent: [0, 1, 0] }, { radius: 0.5 }, );
|
|
934
|
+
|
|
935
|
+
```
|
|
609
936
|
|
|
610
937
|
// Custom profile with weights
|
|
611
938
|
const custom = transitionSurface(
|
|
@@ -615,7 +942,9 @@ const custom = transitionSurface(
|
|
|
615
942
|
);
|
|
616
943
|
```
|
|
617
944
|
|
|
618
|
-
|
|
945
|
+
```ts
|
|
946
|
+
transitionSurface(edgeA: TransitionEdge, edgeB: TransitionEdge, options?: TransitionSurfaceOptions): Shape
|
|
947
|
+
```
|
|
619
948
|
|
|
620
949
|
---
|
|
621
950
|
|
|
@@ -625,14 +954,10 @@ Select or inspect named faces and edges on a shape.
|
|
|
625
954
|
|
|
626
955
|
#### `coalesceEdges()` — Merge collinear edge segments into longer logical edges.
|
|
627
956
|
|
|
628
|
-
**Details**
|
|
629
|
-
|
|
630
957
|
Tessellation often splits one geometric edge into multiple short segments. `coalesceEdges` groups adjacent collinear segments and merges each group into a single `EdgeSegment` spanning the full extent. This is usually needed before passing edges to `fillet()` or `chamfer()` on non-primitive shapes.
|
|
631
958
|
|
|
632
959
|
The `tolerance` controls the maximum perpendicular distance from collinearity before two segments are considered non-collinear. Default: `0.01`.
|
|
633
960
|
|
|
634
|
-
**Example**
|
|
635
|
-
|
|
636
961
|
```ts
|
|
637
962
|
const topEdges = selectEdges(part, { atZ: 20 });
|
|
638
963
|
for (const edge of coalesceEdges(topEdges)) {
|
|
@@ -640,7 +965,9 @@ for (const edge of coalesceEdges(topEdges)) {
|
|
|
640
965
|
}
|
|
641
966
|
```
|
|
642
967
|
|
|
643
|
-
|
|
968
|
+
```ts
|
|
969
|
+
coalesceEdges(segments: EdgeSegment[], tolerance?: number): EdgeSegment[]
|
|
970
|
+
```
|
|
644
971
|
|
|
645
972
|
**`EdgeSegment`**
|
|
646
973
|
|
|
@@ -657,19 +984,17 @@ for (const edge of coalesceEdges(topEdges)) {
|
|
|
657
984
|
|
|
658
985
|
#### `selectEdge()` — Select the single best-matching edge from a shape.
|
|
659
986
|
|
|
660
|
-
**Details**
|
|
661
|
-
|
|
662
987
|
When `near` is specified, returns the edge whose midpoint is closest to that point. Otherwise returns the first matching edge in mesh order. Throws if no edges match the query — useful as a guard when you expect exactly one result.
|
|
663
988
|
|
|
664
|
-
**Example**
|
|
665
|
-
|
|
666
989
|
```ts
|
|
667
990
|
// Chamfer one specific edge near a known point
|
|
668
991
|
const bottomEdge = selectEdge(part, { near: [25, 0, 0], atZ: 0 });
|
|
669
992
|
result = chamfer(result, 1.5, bottomEdge);
|
|
670
993
|
```
|
|
671
994
|
|
|
672
|
-
|
|
995
|
+
```ts
|
|
996
|
+
selectEdge(shape: Shape, query?: EdgeQuery): EdgeSegment
|
|
997
|
+
```
|
|
673
998
|
|
|
674
999
|
**`EdgeQuery`**
|
|
675
1000
|
|
|
@@ -693,14 +1018,10 @@ result = chamfer(result, 1.5, bottomEdge);
|
|
|
693
1018
|
|
|
694
1019
|
#### `selectEdges()` — Select all edges from a shape that match the given query.
|
|
695
1020
|
|
|
696
|
-
**Details**
|
|
697
|
-
|
|
698
1021
|
Extracts sharp edges from the mesh (dihedral angle > 1°), applies all filters in the query, and returns the matching `EdgeSegment[]`. When `near` is specified the results are sorted closest-first.
|
|
699
1022
|
|
|
700
1023
|
Works on any shape — primitives, booleans, shells, and imported meshes. Use this when tracked topology is unavailable (e.g. after a difference or on imported geometry). For simpler cases, pass an `EdgeQuery` directly to `fillet()` or `chamfer()` instead of calling `selectEdges` separately.
|
|
701
1024
|
|
|
702
|
-
**Example**
|
|
703
|
-
|
|
704
1025
|
```ts
|
|
705
1026
|
// Fillet all top edges of a box
|
|
706
1027
|
const topEdges = selectEdges(part, { atZ: 20, perpendicular: [0, 0, 1] });
|
|
@@ -710,7 +1031,9 @@ for (const edge of coalesceEdges(topEdges)) {
|
|
|
710
1031
|
}
|
|
711
1032
|
```
|
|
712
1033
|
|
|
713
|
-
|
|
1034
|
+
```ts
|
|
1035
|
+
selectEdges(shape: Shape, query?: EdgeQuery): EdgeSegment[]
|
|
1036
|
+
```
|
|
714
1037
|
|
|
715
1038
|
---
|
|
716
1039
|
|
|
@@ -720,14 +1043,10 @@ Modify edges of a solid — fillets, chamfers, draft, offset.
|
|
|
720
1043
|
|
|
721
1044
|
#### `chamfer()` — Apply chamfers (beveled edges) to one or more edges of a shape.
|
|
722
1045
|
|
|
723
|
-
**Details**
|
|
724
|
-
|
|
725
1046
|
Produces a 45° bevel at the specified `size` (distance from edge). Works on both straight and curved edges. Supports OCCT and Manifold backends.
|
|
726
1047
|
|
|
727
1048
|
The `edges` parameter accepts the same options as `fillet()`: inline `EdgeQuery`, pre-selected `EdgeSegment`/`EdgeSegment[]`, or `undefined` (all sharp edges).
|
|
728
1049
|
|
|
729
|
-
**Example**
|
|
730
|
-
|
|
731
1050
|
```ts
|
|
732
1051
|
// Chamfer all edges
|
|
733
1052
|
chamfer(myShape, 1)
|
|
@@ -736,18 +1055,16 @@ chamfer(myShape, 1)
|
|
|
736
1055
|
chamfer(myShape, 2, { parallel: [0, 0, 1] })
|
|
737
1056
|
```
|
|
738
1057
|
|
|
739
|
-
|
|
1058
|
+
```ts
|
|
1059
|
+
chamfer(shape: Shape, size: number, edges?: EdgeSelector): Shape
|
|
1060
|
+
```
|
|
740
1061
|
|
|
741
1062
|
#### `draft()` — Apply a draft angle (taper) to vertical faces for mold extraction.
|
|
742
1063
|
|
|
743
|
-
**Details**
|
|
744
|
-
|
|
745
1064
|
Adds a taper angle to the vertical faces of a solid so that it can be extracted from a mold. The neutral plane is the Z position where the draft angle is zero — faces above and below are tapered symmetrically. Typical values for injection molding are 1–5°.
|
|
746
1065
|
|
|
747
1066
|
Requires the OCCT backend. Throws on Manifold.
|
|
748
1067
|
|
|
749
|
-
**Example**
|
|
750
|
-
|
|
751
1068
|
```ts
|
|
752
1069
|
// Add 3° draft to a box for injection molding
|
|
753
1070
|
draft(myBox, 3)
|
|
@@ -756,19 +1073,21 @@ draft(myBox, 3)
|
|
|
756
1073
|
draft(myShape, 2, [0, 0, 1], 10)
|
|
757
1074
|
```
|
|
758
1075
|
|
|
759
|
-
|
|
1076
|
+
```ts
|
|
1077
|
+
draft(shape: Shape, angleDeg: number, pullDirection?: [ number, number, number ], neutralPlaneOffset?: number): Shape
|
|
1078
|
+
```
|
|
760
1079
|
|
|
761
1080
|
#### `fillet()` — Apply fillets (rounded edges) to one or more edges of a shape.
|
|
762
1081
|
|
|
763
|
-
**Details**
|
|
764
|
-
|
|
765
1082
|
Works on both straight and curved edges. Supports OCCT and Manifold backends. When using OCCT, all edges are filleted in a single kernel operation for best quality. When using Manifold, edges are filleted sequentially.
|
|
766
1083
|
|
|
767
|
-
The `edges` parameter is flexible:
|
|
1084
|
+
The `edges` parameter is flexible:
|
|
768
1085
|
|
|
769
|
-
|
|
1086
|
+
- Omit to fillet **all** sharp edges
|
|
1087
|
+
- Pass an `EdgeQuery` for an inline filter (most common)
|
|
1088
|
+
- Pass an `EdgeSegment` or `EdgeSegment[]` from `selectEdges()` for pre-selected edges
|
|
770
1089
|
|
|
771
|
-
|
|
1090
|
+
Throws if no edges match the selection, or if `radius` is not a positive finite number.
|
|
772
1091
|
|
|
773
1092
|
```ts
|
|
774
1093
|
// Fillet all edges
|
|
@@ -782,18 +1101,16 @@ const edges = selectEdges(myShape, { parallel: [0, 0, 1] })
|
|
|
782
1101
|
fillet(myShape, 3, edges)
|
|
783
1102
|
```
|
|
784
1103
|
|
|
785
|
-
|
|
1104
|
+
```ts
|
|
1105
|
+
fillet(shape: Shape, radius: number, edges?: EdgeSelector, segments?: number): Shape
|
|
1106
|
+
```
|
|
786
1107
|
|
|
787
1108
|
#### `offsetSolid()` — Uniformly offset all surfaces of a solid inward or outward.
|
|
788
1109
|
|
|
789
|
-
**Details**
|
|
790
|
-
|
|
791
1110
|
Unlike `shell()`, which hollows a solid by removing one face, `offsetSolid()` produces a new solid whose every surface is shifted by `thickness`. Positive values grow the shape outward; negative values shrink it inward.
|
|
792
1111
|
|
|
793
1112
|
Requires the OCCT backend. Throws on Manifold.
|
|
794
1113
|
|
|
795
|
-
**Example**
|
|
796
|
-
|
|
797
1114
|
```ts
|
|
798
1115
|
// Grow a box outward by 1mm on all sides
|
|
799
1116
|
offsetSolid(myBox, 1)
|
|
@@ -802,22 +1119,22 @@ offsetSolid(myBox, 1)
|
|
|
802
1119
|
offsetSolid(myShape, -0.5)
|
|
803
1120
|
```
|
|
804
1121
|
|
|
805
|
-
|
|
1122
|
+
```ts
|
|
1123
|
+
offsetSolid(shape: Shape, thickness: number): Shape
|
|
1124
|
+
```
|
|
806
1125
|
|
|
807
1126
|
#### `chamfer2d()` — Bevel a named vertical edge of a shape with a 45° chamfer.
|
|
808
1127
|
|
|
809
|
-
**Details**
|
|
810
|
-
|
|
811
1128
|
Compiler-owned chamfer for tracked vertical edges. Requires a compile-plan-covered target. Supported subset and quadrant semantics are the same as `fillet2d()` — see that function for details.
|
|
812
1129
|
|
|
813
|
-
**Example**
|
|
814
|
-
|
|
815
1130
|
```ts
|
|
816
1131
|
const b = rectangle(0, 0, 50, 50).extrude(20);
|
|
817
1132
|
const chamfered = chamfer2d(b.toShape(), b.edge('vert-br'), 3, [-1, -1]);
|
|
818
1133
|
```
|
|
819
1134
|
|
|
820
|
-
|
|
1135
|
+
```ts
|
|
1136
|
+
chamfer2d(shape: Shape, edge: EdgeRef, size: number, quadrant?: [ number, number ]): Shape
|
|
1137
|
+
```
|
|
821
1138
|
|
|
822
1139
|
**`EdgeRef`**
|
|
823
1140
|
- `query?: EdgeQueryRef` — Compiler-owned edge query when available.
|
|
@@ -825,36 +1142,38 @@ const chamfered = chamfer2d(b.toShape(), b.edge('vert-br'), 3, [-1, -1]);
|
|
|
825
1142
|
|
|
826
1143
|
#### `fillet2d()` — Round a named vertical edge of a shape with a circular fillet.
|
|
827
1144
|
|
|
828
|
-
**Details**
|
|
829
|
-
|
|
830
1145
|
Compiler-owned fillet for tracked vertical edges. Requires a compile-plan-covered target (shapes from `box()`, `rectangle().extrude()`, or rigid transforms of those).
|
|
831
1146
|
|
|
832
|
-
**Supported edges:**
|
|
1147
|
+
**Supported edges:**
|
|
1148
|
+
|
|
1149
|
+
- Tracked vertical edges from `box()` or `rectangle().extrude()`
|
|
1150
|
+
- Rigid transforms between tracked source and target
|
|
1151
|
+
- Untouched sibling tracked vertical edges after earlier `fillet2d`/`chamfer2d`
|
|
833
1152
|
|
|
834
1153
|
**Not supported:** edges after shell, hole, cut, trim, difference, intersection, generic sketch extrudes, or tapered extrudes. Use `fillet()` with an `EdgeQuery` for those cases.
|
|
835
1154
|
|
|
836
1155
|
Canonical quadrants: `vert-bl → [1,-1]`, `vert-br → [-1,-1]`, `vert-tr → [-1,1]`, `vert-tl → [1,1]`
|
|
837
1156
|
|
|
838
|
-
**Example**
|
|
839
|
-
|
|
840
1157
|
```ts
|
|
841
1158
|
const b = rectangle(0, 0, 50, 50).extrude(20);
|
|
842
1159
|
const filleted = fillet2d(b.toShape(), b.edge('vert-br'), 5, [-1, -1]);
|
|
843
1160
|
```
|
|
844
1161
|
|
|
845
|
-
|
|
1162
|
+
```ts
|
|
1163
|
+
fillet2d(shape: Shape, edge: EdgeRef, radius: number, quadrant?: [ number, number ], segments?: number): Shape
|
|
1164
|
+
```
|
|
846
1165
|
|
|
847
1166
|
#### `filletCorners()` — Create a polygon from points with specific corners rounded to arc fillets.
|
|
848
1167
|
|
|
849
|
-
**Details**
|
|
850
|
-
|
|
851
1168
|
Each corner spec identifies a vertex by its index in the `points` array and the desired fillet `radius`. Both convex and concave corners are supported.
|
|
852
1169
|
|
|
853
|
-
Constraints:
|
|
1170
|
+
Constraints:
|
|
854
1171
|
|
|
855
|
-
|
|
1172
|
+
- Collinear corners cannot be filleted (throws an error)
|
|
1173
|
+
- Two neighboring fillets whose tangent lengths overlap the same edge will throw
|
|
1174
|
+
- Radius must be positive and small enough to fit within the adjacent edge lengths
|
|
856
1175
|
|
|
857
|
-
**
|
|
1176
|
+
Use `offset(-r).offset(+r)` instead if you want to round **all** convex corners uniformly. Use `filletCorners` when you need selective or mixed sharp/rounded profiles.
|
|
858
1177
|
|
|
859
1178
|
```ts
|
|
860
1179
|
const roof = filletCorners(roofPoints, [
|
|
@@ -864,7 +1183,9 @@ const roof = filletCorners(roofPoints, [
|
|
|
864
1183
|
]);
|
|
865
1184
|
```
|
|
866
1185
|
|
|
867
|
-
|
|
1186
|
+
```ts
|
|
1187
|
+
filletCorners(points: PointInput[], corners: FilletCornerSpec[]): Sketch
|
|
1188
|
+
```
|
|
868
1189
|
|
|
869
1190
|
`FilletCornerSpec`: `{ index: number, radius: number, segments?: number }`
|
|
870
1191
|
|
|
@@ -891,7 +1212,9 @@ for (const {x, y} of circularLayout(12, r)) {
|
|
|
891
1212
|
}
|
|
892
1213
|
```
|
|
893
1214
|
|
|
894
|
-
|
|
1215
|
+
```ts
|
|
1216
|
+
circularLayout(count: number, radius: number, options?: CircularLayoutOptions): LayoutPoint[]
|
|
1217
|
+
```
|
|
895
1218
|
|
|
896
1219
|
**`CircularLayoutOptions`**
|
|
897
1220
|
- `startDeg?: number` — Angle of the first element in degrees (default: 0 = +X axis).
|
|
@@ -902,13 +1225,12 @@ for (const {x, y} of circularLayout(12, r)) {
|
|
|
902
1225
|
|
|
903
1226
|
#### `circularPattern()` — Repeat a shape in a circular pattern around an axis and union the copies.
|
|
904
1227
|
|
|
905
|
-
**Details**
|
|
906
|
-
|
|
907
1228
|
Distributes `count` copies evenly around the rotation axis (360° / count per step). All copies are unioned into a single `Shape`. Distinct compiler ownership is assigned to each copy — post-merge face identity via owner-scoped canonical queries still works for pattern descendants.
|
|
908
1229
|
|
|
909
|
-
Two calling conventions:
|
|
1230
|
+
Two calling conventions:
|
|
910
1231
|
|
|
911
|
-
**
|
|
1232
|
+
- **Simple** (Z axis): `circularPattern(shape, 6)` or `circularPattern(shape, 6, centerX, centerY)`
|
|
1233
|
+
- **Advanced** (arbitrary axis): `circularPattern(shape, 6, { axis, origin })`
|
|
912
1234
|
|
|
913
1235
|
```ts
|
|
914
1236
|
// 8 holes evenly spaced around origin
|
|
@@ -918,7 +1240,9 @@ circularPattern(cylinder(12, 4).translate(30, 0, -1), 8)
|
|
|
918
1240
|
circularPattern(myFeature, 4, { axis: [1, 0, 0], origin: [0, 0, 50] })
|
|
919
1241
|
```
|
|
920
1242
|
|
|
921
|
-
|
|
1243
|
+
```ts
|
|
1244
|
+
circularPattern(shape: Shape, count: number, centerXOrOpts?: number | CircularPatternOptions, centerY?: number): Shape
|
|
1245
|
+
```
|
|
922
1246
|
|
|
923
1247
|
**`CircularPatternOptions`**
|
|
924
1248
|
- `centerX?: number` — Center X of the rotation (default: 0). Used when axis is Z (legacy mode).
|
|
@@ -926,41 +1250,41 @@ circularPattern(myFeature, 4, { axis: [1, 0, 0], origin: [0, 0, 50] })
|
|
|
926
1250
|
|
|
927
1251
|
#### `circularPattern2d()` — Repeat a 2D sketch in a circular pattern around a center point and union the copies.
|
|
928
1252
|
|
|
929
|
-
|
|
1253
|
+
```ts
|
|
1254
|
+
circularPattern2d(sketch: Sketch, count: number, centerXOrOpts?: number | { centerX?: number; centerY?: number; startDeg?: number; }, centerY?: number): Sketch
|
|
1255
|
+
```
|
|
930
1256
|
|
|
931
1257
|
#### `linearPattern()` — Repeat a shape in a linear pattern along a direction vector and union the copies.
|
|
932
1258
|
|
|
933
|
-
**Details**
|
|
934
|
-
|
|
935
1259
|
Creates `count` copies of `shape`, each offset by `(dx*i, dy*i, dz*i)` from the original. All copies are unioned into a single `Shape`. Distinct compiler ownership is assigned to each copy so face identity via owner-scoped canonical queries still works post-merge.
|
|
936
1260
|
|
|
937
|
-
**Example**
|
|
938
|
-
|
|
939
1261
|
```ts
|
|
940
1262
|
// 5 cylinders, 20mm apart along X
|
|
941
1263
|
linearPattern(cylinder(10, 3), 5, 20, 0)
|
|
942
1264
|
```
|
|
943
1265
|
|
|
944
|
-
|
|
1266
|
+
```ts
|
|
1267
|
+
linearPattern(shape: Shape, count: number, dx: number, dy: number, dz?: number): Shape
|
|
1268
|
+
```
|
|
945
1269
|
|
|
946
1270
|
#### `linearPattern2d()` — Repeat a 2D sketch in a linear pattern and union the copies.
|
|
947
1271
|
|
|
948
|
-
|
|
1272
|
+
```ts
|
|
1273
|
+
linearPattern2d(sketch: Sketch, count: number, dx: number, dy?: number): Sketch
|
|
1274
|
+
```
|
|
949
1275
|
|
|
950
1276
|
#### `mirrorCopy()` — Mirror a shape across a plane and union the mirror with the original.
|
|
951
1277
|
|
|
952
|
-
**Details**
|
|
953
|
-
|
|
954
1278
|
The mirror plane passes through the origin and is defined by its normal vector. The mirrored copy is unioned with the original to produce a single symmetric Shape.
|
|
955
1279
|
|
|
956
|
-
**Example**
|
|
957
|
-
|
|
958
1280
|
```ts
|
|
959
1281
|
// Mirror across the YZ plane (X=0)
|
|
960
1282
|
mirrorCopy(box(50, 30, 10), [1, 0, 0])
|
|
961
1283
|
```
|
|
962
1284
|
|
|
963
|
-
|
|
1285
|
+
```ts
|
|
1286
|
+
mirrorCopy(shape: Shape, normal: [ number, number, number ]): Shape
|
|
1287
|
+
```
|
|
964
1288
|
|
|
965
1289
|
---
|
|
966
1290
|
|
|
@@ -968,14 +1292,72 @@ mirrorCopy(box(50, 30, 10), [1, 0, 0])
|
|
|
968
1292
|
|
|
969
1293
|
Define geometry by relationships and let a solver find positions.
|
|
970
1294
|
|
|
1295
|
+
#### `Constraint.makeParallel()` — Constrain two lines to be parallel.
|
|
1296
|
+
|
|
1297
|
+
```ts
|
|
1298
|
+
Constraint.makeParallel(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): ConstrainedSketchBuilder
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
#### `Constraint.enforceAngle()` — Constrain the signed angle from line `a` to line `b`.
|
|
1302
|
+
|
|
1303
|
+
```ts
|
|
1304
|
+
Constraint.enforceAngle(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg, angleDeg: number): ConstrainedSketchBuilder
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
#### `Constraint.horizontal()` — Constrain a line to be horizontal.
|
|
1308
|
+
|
|
1309
|
+
```ts
|
|
1310
|
+
Constraint.horizontal(builder: ConstrainedSketchBuilder, line: LineArg): ConstrainedSketchBuilder
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
#### `Constraint.vertical()` — Constrain a line to be vertical.
|
|
1314
|
+
|
|
1315
|
+
```ts
|
|
1316
|
+
Constraint.vertical(builder: ConstrainedSketchBuilder, line: LineArg): ConstrainedSketchBuilder
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
#### `Constraint.equalLength()` — Constrain two lines to have equal length.
|
|
1320
|
+
|
|
1321
|
+
```ts
|
|
1322
|
+
Constraint.equalLength(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): ConstrainedSketchBuilder
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
#### `Constraint.distance()` — Constrain the distance between two points.
|
|
1326
|
+
|
|
1327
|
+
```ts
|
|
1328
|
+
Constraint.distance(builder: ConstrainedSketchBuilder, a: PointArg, b: PointArg, value: number): ConstrainedSketchBuilder
|
|
1329
|
+
```
|
|
1330
|
+
|
|
1331
|
+
#### `Constraint.fix()` — Fix a point at a specific coordinate.
|
|
1332
|
+
|
|
1333
|
+
```ts
|
|
1334
|
+
Constraint.fix(builder: ConstrainedSketchBuilder, pt: PointArg, x: number, y: number): ConstrainedSketchBuilder
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
#### `Constraint.coincident()` — Constrain two points to occupy the same location.
|
|
1338
|
+
|
|
1339
|
+
```ts
|
|
1340
|
+
Constraint.coincident(builder: ConstrainedSketchBuilder, a: PointArg, b: PointArg): ConstrainedSketchBuilder
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
#### `Constraint.perpendicular()` — Constrain two lines to be perpendicular.
|
|
1344
|
+
|
|
1345
|
+
```ts
|
|
1346
|
+
Constraint.perpendicular(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): ConstrainedSketchBuilder
|
|
1347
|
+
```
|
|
1348
|
+
|
|
1349
|
+
#### `Constraint.length()` — Constrain the length of a line.
|
|
1350
|
+
|
|
1351
|
+
```ts
|
|
1352
|
+
Constraint.length(builder: ConstrainedSketchBuilder, line: LineArg, value: number): ConstrainedSketchBuilder
|
|
1353
|
+
```
|
|
1354
|
+
|
|
971
1355
|
#### `addPolygon()` — Add a general polygon concept to the builder.
|
|
972
1356
|
|
|
973
1357
|
Creates n vertices and n sides (CCW: `sides[i]` from `vertices[i]` → `vertices[(i+1) % n]`). Applies a `ccw` constraint to enforce winding. All dimensional constraints (lengths, angles, position) are left to the caller.
|
|
974
1358
|
|
|
975
1359
|
Use `sk.addPolygon()` as the shorthand builder method.
|
|
976
1360
|
|
|
977
|
-
**Example**
|
|
978
|
-
|
|
979
1361
|
```ts
|
|
980
1362
|
const sk = constrainedSketch();
|
|
981
1363
|
const tri = sk.addPolygon({ points: [[0,0],[100,0],[50,80]] });
|
|
@@ -984,7 +1366,9 @@ sk.length(tri.side(0), 100);
|
|
|
984
1366
|
return sk.solve().extrude(5);
|
|
985
1367
|
```
|
|
986
1368
|
|
|
987
|
-
|
|
1369
|
+
```ts
|
|
1370
|
+
addPolygon(sk: ConstrainedSketchBuilder, options: PolygonOptions): ConstrainedPolygon
|
|
1371
|
+
```
|
|
988
1372
|
|
|
989
1373
|
**`PolygonOptions`**
|
|
990
1374
|
- `addLoop?: boolean` — Whether to register a closed loop for sketch generation. Default: true.
|
|
@@ -1001,8 +1385,6 @@ Creates 4 vertices (CCW: bl→br→tr→tl), 4 sides, 4 structural constraints (
|
|
|
1001
1385
|
|
|
1002
1386
|
Use `sk.rect()` as the shorthand builder method.
|
|
1003
1387
|
|
|
1004
|
-
**Example**
|
|
1005
|
-
|
|
1006
1388
|
```ts
|
|
1007
1389
|
const sk = constrainedSketch();
|
|
1008
1390
|
const r = sk.rect({ x: 0, y: 0, width: 100, height: 50 });
|
|
@@ -1011,7 +1393,9 @@ sk.length(r.bottom, 120); // override initial width
|
|
|
1011
1393
|
return sk.solve().extrude(10);
|
|
1012
1394
|
```
|
|
1013
1395
|
|
|
1014
|
-
|
|
1396
|
+
```ts
|
|
1397
|
+
addRect(sk: ConstrainedSketchBuilder, options?: RectOptions): ConstrainedRect
|
|
1398
|
+
```
|
|
1015
1399
|
|
|
1016
1400
|
**`RectOptions`**
|
|
1017
1401
|
|
|
@@ -1041,8 +1425,6 @@ Vertices are placed at `(cx + r·cos(startAngle + i·2π/n), cy + r·sin(...))`.
|
|
|
1041
1425
|
|
|
1042
1426
|
Use `sk.regularPolygon()` as the shorthand builder method.
|
|
1043
1427
|
|
|
1044
|
-
**Example**
|
|
1045
|
-
|
|
1046
1428
|
```ts
|
|
1047
1429
|
const sk = constrainedSketch();
|
|
1048
1430
|
const hex = sk.regularPolygon({ sides: 6, radius: 25 });
|
|
@@ -1051,7 +1433,9 @@ sk.length(hex.side(0), 30); // all sides change (equal constraint)
|
|
|
1051
1433
|
return sk.solve().extrude(5);
|
|
1052
1434
|
```
|
|
1053
1435
|
|
|
1054
|
-
|
|
1436
|
+
```ts
|
|
1437
|
+
addRegularPolygon(sk: ConstrainedSketchBuilder, options: RegularPolygonOptions): ConstrainedRegularPolygon
|
|
1438
|
+
```
|
|
1055
1439
|
|
|
1056
1440
|
**`RegularPolygonOptions`**
|
|
1057
1441
|
|
|
@@ -1070,8 +1454,6 @@ return sk.solve().extrude(5);
|
|
|
1070
1454
|
|
|
1071
1455
|
#### `circle()` — Create an analytic 2D circle for measurement, construction, and extrusion.
|
|
1072
1456
|
|
|
1073
|
-
**Example**
|
|
1074
|
-
|
|
1075
1457
|
```ts
|
|
1076
1458
|
const c = circle(0, 0, 25);
|
|
1077
1459
|
c.diameter; c.circumference; c.area;
|
|
@@ -1085,15 +1467,18 @@ cyl.face('side'); // FaceRef (curved)
|
|
|
1085
1467
|
Circle2D.fromDiameter(point(0, 0), 50);
|
|
1086
1468
|
```
|
|
1087
1469
|
|
|
1088
|
-
|
|
1470
|
+
```ts
|
|
1471
|
+
circle(cx: number, cy: number, radius: number): Circle2D
|
|
1472
|
+
```
|
|
1089
1473
|
|
|
1090
1474
|
#### `constrainedSketch()` — Create a parametric 2D sketch driven by geometric constraints and a nonlinear solver.
|
|
1091
1475
|
|
|
1092
1476
|
**Workflow**
|
|
1093
1477
|
|
|
1094
|
-
1. Create a builder with `constrainedSketch()`.
|
|
1095
|
-
|
|
1096
|
-
|
|
1478
|
+
1. Create a builder with `constrainedSketch()`.
|
|
1479
|
+
2. Add geometry — points, lines, circles, arcs — using the builder methods.
|
|
1480
|
+
3. Add constraints (`horizontal`, `length`, `fix`, etc.) to drive the geometry.
|
|
1481
|
+
4. Call `.solve()` to run the solver and get a `ConstraintSketch` (which extends `Sketch`).
|
|
1097
1482
|
|
|
1098
1483
|
```ts
|
|
1099
1484
|
const sk = constrainedSketch();
|
|
@@ -1117,15 +1502,15 @@ result.inspect(); // human-readable summary
|
|
|
1117
1502
|
result.withUpdatedConstraint('cst-5', 120); // update a dimension without rebuilding
|
|
1118
1503
|
```
|
|
1119
1504
|
|
|
1120
|
-
|
|
1505
|
+
```ts
|
|
1506
|
+
constrainedSketch(options?: ConstrainedSketchOptions): ConstrainedSketchBuilder
|
|
1507
|
+
```
|
|
1121
1508
|
|
|
1122
1509
|
**`ConstrainedSketchOptions`**
|
|
1123
1510
|
- `strict?: boolean` — When true, adding a constraint that cannot be satisfied throws instead of silently discarding it.
|
|
1124
1511
|
|
|
1125
1512
|
#### `line()` — Create an analytic 2D line segment between two points.
|
|
1126
1513
|
|
|
1127
|
-
**Example**
|
|
1128
|
-
|
|
1129
1514
|
```ts
|
|
1130
1515
|
const l = line(0, 0, 50, 0);
|
|
1131
1516
|
l.length; l.midpoint; l.angle; l.direction;
|
|
@@ -1137,12 +1522,12 @@ Line2D.fromPointAndAngle(point(0, 0), 45, 100);
|
|
|
1137
1522
|
Line2D.fromPointAndDirection(point(0, 0), [1, 1], 50);
|
|
1138
1523
|
```
|
|
1139
1524
|
|
|
1140
|
-
|
|
1525
|
+
```ts
|
|
1526
|
+
line(x1: number, y1: number, x2: number, y2: number): Line2D
|
|
1527
|
+
```
|
|
1141
1528
|
|
|
1142
1529
|
#### `point()` — Create an analytic 2D point for measurement and construction geometry.
|
|
1143
1530
|
|
|
1144
|
-
**Example**
|
|
1145
|
-
|
|
1146
1531
|
```ts
|
|
1147
1532
|
const p = point(10, 20);
|
|
1148
1533
|
p.distanceTo(point(30, 40)); // Euclidean distance
|
|
@@ -1151,15 +1536,52 @@ p.translate(5, 5); // new shifted point
|
|
|
1151
1536
|
p.toTuple(); // [10, 20]
|
|
1152
1537
|
```
|
|
1153
1538
|
|
|
1154
|
-
|
|
1539
|
+
```ts
|
|
1540
|
+
point(x: number, y: number): Point2D
|
|
1541
|
+
```
|
|
1155
1542
|
|
|
1156
1543
|
---
|
|
1157
1544
|
|
|
1158
|
-
## C9: Spatial Placement
|
|
1545
|
+
## C9: Spatial Placement
|
|
1546
|
+
|
|
1547
|
+
Position geometry relative to other geometry using semantic anchors.
|
|
1548
|
+
|
|
1549
|
+
|
|
1550
|
+
#### `Points.distance()` — Euclidean distance between two 3D points.
|
|
1551
|
+
|
|
1552
|
+
```ts
|
|
1553
|
+
Points.readonly distance: typeof distance
|
|
1554
|
+
```
|
|
1555
|
+
|
|
1556
|
+
#### `Points.midpoint()` — Center point between two 3D points.
|
|
1557
|
+
|
|
1558
|
+
```ts
|
|
1559
|
+
Points.readonly midpoint: typeof midpoint
|
|
1560
|
+
```
|
|
1561
|
+
|
|
1562
|
+
#### `Points.lerp()` — Linearly interpolate between two 3D points. t=0 returns a, t=1 returns b.
|
|
1563
|
+
|
|
1564
|
+
```ts
|
|
1565
|
+
Points.readonly lerp: typeof lerp
|
|
1566
|
+
```
|
|
1567
|
+
|
|
1568
|
+
#### `Points.direction()` — Unit direction vector from a to b. Throws if a and b are the same point.
|
|
1569
|
+
|
|
1570
|
+
```ts
|
|
1571
|
+
Points.readonly direction: typeof direction
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
#### `Points.offset()` — Move a point along a direction vector by a given amount.
|
|
1575
|
+
|
|
1576
|
+
```ts
|
|
1577
|
+
Points.readonly offset: typeof offset
|
|
1578
|
+
```
|
|
1159
1579
|
|
|
1160
|
-
|
|
1580
|
+
#### `Points.polar()` — Compute a 2D point at distance and angle (degrees) from an optional origin.
|
|
1161
1581
|
|
|
1162
|
-
|
|
1582
|
+
```ts
|
|
1583
|
+
Points.readonly polar: typeof polar
|
|
1584
|
+
```
|
|
1163
1585
|
|
|
1164
1586
|
---
|
|
1165
1587
|
|
|
@@ -1169,7 +1591,7 @@ Compose parts with joints for kinematic simulation.
|
|
|
1169
1591
|
|
|
1170
1592
|
#### `assembly()` — Create an assembly container with named parts and joints for kinematic mechanisms.
|
|
1171
1593
|
|
|
1172
|
-
**
|
|
1594
|
+
**Use this from iteration 1 for any model with moving parts.** Hinges, sliders, gears, articulated fingers, doors — all start with `assembly()`, not with manual rotation math. Don't build a static "extended pose" first and refactor to an assembly later: joint sliders, animations, sweeps, collision detection, and robot export all flow from the kinematic graph.
|
|
1173
1595
|
|
|
1174
1596
|
An assembly models a mechanism as a directed graph of parts connected by joints. Parts are the nodes; joints are directed edges from parent to child. The graph must be a forest (no cycles). Root parts (those with no incoming joint) are anchored to world space.
|
|
1175
1597
|
|
|
@@ -1179,8 +1601,6 @@ The higher-level `connect()` API uses declared **connectors** to compute joint f
|
|
|
1179
1601
|
|
|
1180
1602
|
For multi-file assemblies, a file that returns an `Assembly` is importable via `require()` and yields an `ImportedAssembly`. Use `mergeInto()` to flatten a sub-assembly into a parent assembly.
|
|
1181
1603
|
|
|
1182
|
-
**Example**
|
|
1183
|
-
|
|
1184
1604
|
```ts
|
|
1185
1605
|
const mech = assembly("Arm")
|
|
1186
1606
|
.addPart("base", box(80, 80, 20, true), {
|
|
@@ -1196,15 +1616,17 @@ const mech = assembly("Arm")
|
|
|
1196
1616
|
return mech; // auto-solved at defaults, renders all parts
|
|
1197
1617
|
```
|
|
1198
1618
|
|
|
1199
|
-
|
|
1619
|
+
```ts
|
|
1620
|
+
assembly(name?: string): Assembly
|
|
1621
|
+
```
|
|
1200
1622
|
|
|
1201
1623
|
#### `bomToCsv()` — Convert an array of BOM rows into a CSV string.
|
|
1202
1624
|
|
|
1203
|
-
**Details**
|
|
1204
|
-
|
|
1205
1625
|
Produces a CSV with columns: `part`, `qty`, `material`, `process`, `tolerance`, `notes`. String values are quoted and internal double-quotes are escaped. Prefer calling `solvedAssembly.bomCsv()` directly — this function is exposed for custom BOM processing.
|
|
1206
1626
|
|
|
1207
|
-
|
|
1627
|
+
```ts
|
|
1628
|
+
bomToCsv(rows: BomRow[]): string
|
|
1629
|
+
```
|
|
1208
1630
|
|
|
1209
1631
|
**`BomRow`**: `part: string`, `qty: number`, `material?: string`, `process?: string`, `tolerance?: string`, `notes?: string`, `metadata?: PartMetadata`
|
|
1210
1632
|
|
|
@@ -1212,12 +1634,8 @@ Produces a CSV with columns: `part`, `qty`, `material`, `process`, `tolerance`,
|
|
|
1212
1634
|
|
|
1213
1635
|
#### `joint()` — Create a revolute joint that auto-generates a parameter slider and rotates the shape.
|
|
1214
1636
|
|
|
1215
|
-
**Details**
|
|
1216
|
-
|
|
1217
1637
|
This is a convenience wrapper for single-shape, single-joint use cases. It calls `param()` to create a named angle slider, then applies `rotateAroundAxis()` to the shape. Use the full `Assembly` API for mechanisms with multiple parts and joints.
|
|
1218
1638
|
|
|
1219
|
-
**Example**
|
|
1220
|
-
|
|
1221
1639
|
```ts
|
|
1222
1640
|
const arm = joint("Shoulder", armShape, [0, 0, 20], {
|
|
1223
1641
|
axis: [0, 1, 0],
|
|
@@ -1226,14 +1644,14 @@ const arm = joint("Shoulder", armShape, [0, 0, 20], {
|
|
|
1226
1644
|
return arm;
|
|
1227
1645
|
```
|
|
1228
1646
|
|
|
1229
|
-
|
|
1647
|
+
```ts
|
|
1648
|
+
joint(name: string, shape: Shape, pivot: [ number, number, number ], opts?: RevoluteJointOpts): Shape
|
|
1649
|
+
```
|
|
1230
1650
|
|
|
1231
1651
|
`RevoluteJointOpts`: `{ min?: number, max?: number, default?: number, unit?: string, reverse?: boolean }`
|
|
1232
1652
|
|
|
1233
1653
|
#### `jointsView()` — Register viewport-only mechanism controls that animate returned objects without re-running the script.
|
|
1234
1654
|
|
|
1235
|
-
**Details**
|
|
1236
|
-
|
|
1237
1655
|
Defines joints (revolute or prismatic), optional gear/rack couplings, and named animations. The viewport resolves transforms through the joint chain at display time — the script geometry is computed only once at rest pose.
|
|
1238
1656
|
|
|
1239
1657
|
**Critical:** Solve the assembly at **rest pose** (all animated joints = 0). The viewport applies `jointsView` transforms on top of the returned scene. If geometry is already solved at non-zero angles, animation will double-rotate everything.
|
|
@@ -1280,8 +1698,6 @@ keyframes: [
|
|
|
1280
1698
|
|
|
1281
1699
|
Mixing explicit `at` and omitted `at` in the same animation is not allowed.
|
|
1282
1700
|
|
|
1283
|
-
**Example**
|
|
1284
|
-
|
|
1285
1701
|
```js
|
|
1286
1702
|
jointsView({
|
|
1287
1703
|
joints: [{
|
|
@@ -1300,7 +1716,9 @@ jointsView({
|
|
|
1300
1716
|
});
|
|
1301
1717
|
```
|
|
1302
1718
|
|
|
1303
|
-
|
|
1719
|
+
```ts
|
|
1720
|
+
jointsView(options?: JointsViewOptions): void
|
|
1721
|
+
```
|
|
1304
1722
|
|
|
1305
1723
|
**`JointsViewOptions`**: `enabled?: boolean`, `joints?: JointViewInput[]`, `couplings?: JointViewCouplingInput[]`, `animations?: JointViewAnimationInput[]`, `defaultAnimation?: string`
|
|
1306
1724
|
|
|
@@ -1323,112 +1741,140 @@ jointsView({
|
|
|
1323
1741
|
|
|
1324
1742
|
Declare user-facing controls that drive model geometry.
|
|
1325
1743
|
|
|
1326
|
-
#### `
|
|
1744
|
+
#### `Param.number()` — Declare a numeric parameter that renders as a slider in the UI.
|
|
1327
1745
|
|
|
1328
|
-
|
|
1746
|
+
Each call registers a slider control. When the user moves the slider the entire script re-executes with the new value. Parameter values are also overridable from `require()` imports or the CLI `--param` flag — the `name` string is the key used in both cases.
|
|
1329
1747
|
|
|
1330
|
-
|
|
1748
|
+
Default range rules when options are omitted:
|
|
1749
|
+
|
|
1750
|
+
- `min` defaults to `0`
|
|
1751
|
+
- `max` defaults to `defaultValue * 4`
|
|
1752
|
+
- `step` is auto-calculated: `1` for integer params, `0.1` for ranges ≤ 100, `1` for larger ranges
|
|
1331
1753
|
|
|
1332
|
-
|
|
1754
|
+
The `unit` option is cosmetic only — no conversion is performed. Use `integer: true` for counts, sides, quantities (rounds to whole numbers; step defaults to `1`).
|
|
1333
1755
|
|
|
1334
1756
|
```ts
|
|
1335
|
-
const
|
|
1336
|
-
|
|
1337
|
-
|
|
1757
|
+
const width = Param.number("Width", 50);
|
|
1758
|
+
const angle = Param.number("Angle", 45, { min: 0, max: 180, unit: "°" });
|
|
1759
|
+
const sides = Param.number("Sides", 6, { min: 3, max: 12, integer: true });
|
|
1338
1760
|
```
|
|
1339
1761
|
|
|
1340
|
-
|
|
1762
|
+
**Parameter overrides** — key must match `name` exactly:
|
|
1341
1763
|
|
|
1342
1764
|
```ts
|
|
1343
|
-
|
|
1765
|
+
// Via require()
|
|
1766
|
+
const bracket = require("./bracket.forge.js", { Width: 80 });
|
|
1767
|
+
|
|
1768
|
+
// Via CLI
|
|
1769
|
+
// forgecad run model.forge.js --param "Wall Thickness=3"
|
|
1344
1770
|
```
|
|
1345
1771
|
|
|
1346
|
-
|
|
1772
|
+
Also available as the shorthand alias `param()`.
|
|
1347
1773
|
|
|
1348
|
-
|
|
1774
|
+
```ts
|
|
1775
|
+
Param.number(name: string, defaultValue: number, opts?: { min?: number; max?: number; step?: number; unit?: string; integer?: boolean; reverse?: boolean; }): number
|
|
1776
|
+
```
|
|
1349
1777
|
|
|
1350
|
-
|
|
1778
|
+
#### `Param.string()` — Declare a string parameter that renders as a text input in the UI.
|
|
1351
1779
|
|
|
1352
|
-
|
|
1780
|
+
String parameters let users type free-form text — labels, names, inscriptions, file paths, etc. The `name` string is the override key.
|
|
1353
1781
|
|
|
1354
|
-
|
|
1782
|
+
```ts
|
|
1783
|
+
const label = Param.string("Label", "Hello World");
|
|
1784
|
+
const name = Param.string("Name", "Part-001", { maxLength: 20 });
|
|
1785
|
+
```
|
|
1355
1786
|
|
|
1356
|
-
|
|
1787
|
+
Override via import:
|
|
1357
1788
|
|
|
1358
1789
|
```ts
|
|
1359
|
-
const
|
|
1360
|
-
if (panStyle === "wok") return buildWok();
|
|
1790
|
+
const tag = require("./tag.forge.js", { Label: "Custom Text" });
|
|
1361
1791
|
```
|
|
1362
1792
|
|
|
1363
|
-
|
|
1793
|
+
Only available as `Param.string()` — no standalone alias.
|
|
1364
1794
|
|
|
1365
1795
|
```ts
|
|
1366
|
-
|
|
1796
|
+
Param.string(name: string, defaultValue: string, opts?: { maxLength?: number; }): string
|
|
1367
1797
|
```
|
|
1368
1798
|
|
|
1369
|
-
|
|
1799
|
+
#### `Param.bool()` — Declare a boolean parameter that renders as a checkbox in the UI.
|
|
1370
1800
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1801
|
+
Internally stored as `0`/`1`. When overriding from CLI or `require()`, pass `1` for true and `0` for false. The `name` string is the override key.
|
|
1802
|
+
|
|
1803
|
+
```ts
|
|
1804
|
+
const showHoles = Param.bool("Show Holes", true);
|
|
1805
|
+
if (showHoles) return difference(plate, cylinder(10, 5).translate(50, 30, 0));
|
|
1806
|
+
return plate;
|
|
1373
1807
|
```
|
|
1374
1808
|
|
|
1375
|
-
|
|
1809
|
+
Override via import:
|
|
1376
1810
|
|
|
1377
|
-
|
|
1811
|
+
```ts
|
|
1812
|
+
const pan = require("./pan.forge.js", { "Show Lid": 0 });
|
|
1813
|
+
```
|
|
1378
1814
|
|
|
1379
|
-
|
|
1815
|
+
Also available as the shorthand alias `boolParam()`.
|
|
1380
1816
|
|
|
1381
|
-
|
|
1817
|
+
```ts
|
|
1818
|
+
Param.bool(name: string, defaultValue: boolean): boolean
|
|
1819
|
+
```
|
|
1382
1820
|
|
|
1383
|
-
|
|
1821
|
+
#### `Param.choice()` — Declare a choice parameter that renders as a dropdown in the UI.
|
|
1384
1822
|
|
|
1385
|
-
`
|
|
1823
|
+
`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.
|
|
1386
1824
|
|
|
1387
|
-
|
|
1825
|
+
Overrides may be passed as the choice label string (preferred) or as a numeric index. The `name` string is the override key.
|
|
1388
1826
|
|
|
1389
|
-
|
|
1827
|
+
```ts
|
|
1828
|
+
const panStyle = Param.choice("Pan Style", "frying-pan", ["frying-pan", "saute-pan", "wok"]);
|
|
1829
|
+
if (panStyle === "wok") return buildWok();
|
|
1830
|
+
```
|
|
1390
1831
|
|
|
1391
|
-
|
|
1832
|
+
Override via import:
|
|
1392
1833
|
|
|
1393
|
-
|
|
1834
|
+
```ts
|
|
1835
|
+
const pan = require("./pan.forge.js", { "Pan Style": "wok" });
|
|
1836
|
+
```
|
|
1394
1837
|
|
|
1395
|
-
|
|
1838
|
+
Override via CLI:
|
|
1396
1839
|
|
|
1397
|
-
|
|
1840
|
+
```bash
|
|
1841
|
+
forgecad run model.forge.js --param "Pan Style=wok"
|
|
1842
|
+
```
|
|
1398
1843
|
|
|
1399
|
-
|
|
1844
|
+
Also available as the shorthand alias `choiceParam()`.
|
|
1400
1845
|
|
|
1401
1846
|
```ts
|
|
1402
|
-
|
|
1403
|
-
const angle = param("Angle", 45, { min: 0, max: 180, unit: "°" });
|
|
1404
|
-
const sides = param("Sides", 6, { min: 3, max: 12, integer: true });
|
|
1847
|
+
Param.choice(name: string, defaultValue: string, choices: string[]): string
|
|
1405
1848
|
```
|
|
1406
1849
|
|
|
1407
|
-
|
|
1850
|
+
#### `Param.list()` — Declare a list parameter — an array of struct items with per-field UI controls.
|
|
1408
1851
|
|
|
1409
|
-
|
|
1410
|
-
// Via require()
|
|
1411
|
-
const bracket = require("./bracket.forge.js", { Width: 80 });
|
|
1852
|
+
Each item in the list is a struct whose fields each render as their own control (slider, checkbox, or dropdown). The user can add/remove rows up to `minItems`/`maxItems` bounds.
|
|
1412
1853
|
|
|
1413
|
-
|
|
1414
|
-
|
|
1854
|
+
Field types:
|
|
1855
|
+
|
|
1856
|
+
- Boolean fields (`boolean: true` in field defs) return as `boolean`
|
|
1857
|
+
- Choice fields (`choices: [...]` in field defs) return as `string`
|
|
1858
|
+
- All other fields return as `number`
|
|
1859
|
+
|
|
1860
|
+
```ts
|
|
1861
|
+
Param.list<T extends Record<string, number | boolean | string>>(name: string, defaultItems: T[], opts: { ... }): T[]
|
|
1415
1862
|
```
|
|
1416
1863
|
|
|
1417
|
-
`
|
|
1864
|
+
`ListParamFieldDef`: `{ min?: number, max?: number, step?: number, unit?: string, integer?: boolean, boolean?: boolean, choices?: string[] }`
|
|
1418
1865
|
|
|
1419
1866
|
#### `dim()` — Add a dimension annotation between two points.
|
|
1420
1867
|
|
|
1421
|
-
**Details**
|
|
1422
|
-
|
|
1423
1868
|
Dimension annotations are purely visual callouts rendered in the viewport and report export. They do not affect geometry or constrain the model.
|
|
1424
1869
|
|
|
1425
1870
|
Point arguments accept 2D tuples `[x, y]`, 3D tuples `[x, y, z]`, or `Point2D` objects (Z is treated as 0 for 2D inputs).
|
|
1426
1871
|
|
|
1427
1872
|
**Ownership Rules (Report Pages)**
|
|
1428
1873
|
|
|
1429
|
-
- `currentComponent: true` — deterministic ownership by the calling import instance. Use when authoring reusable imported parts.
|
|
1430
|
-
|
|
1431
|
-
|
|
1874
|
+
- `currentComponent: true` — deterministic ownership by the calling import instance. Use when authoring reusable imported parts.
|
|
1875
|
+
- `component: "Part Name"` — route dimension to another named returned object.
|
|
1876
|
+
- Multiple owners: dimension is shared and appears on the assembly overview page.
|
|
1877
|
+
- No ownership set: report export infers ownership via endpoint-in-bbox.
|
|
1432
1878
|
|
|
1433
1879
|
```ts
|
|
1434
1880
|
dim([-w / 2, 0, 0], [w / 2, 0, 0], { label: "Width" });
|
|
@@ -1438,25 +1884,25 @@ dim([0, 0, 0], [100, 0, 0], { component: "Base", color: "#00AAFF" });
|
|
|
1438
1884
|
|
|
1439
1885
|
`component` (string or string[] — report ownership), `currentComponent` (boolean)
|
|
1440
1886
|
|
|
1441
|
-
|
|
1887
|
+
```ts
|
|
1888
|
+
dim(from: PointArg, to: PointArg, opts?: DimOpts): void
|
|
1889
|
+
```
|
|
1442
1890
|
|
|
1443
1891
|
`DimOpts`: `{ offset?: number, label?: string, color?: string, component?: string | string[], currentComponent?: boolean }`
|
|
1444
1892
|
|
|
1445
1893
|
#### `dimLine()` — Add a dimension annotation along a `Line2D`.
|
|
1446
1894
|
|
|
1447
|
-
**Details**
|
|
1448
|
-
|
|
1449
1895
|
Convenience wrapper around { points from a constrained-sketch `Line2D` entity. All `opts` are forwarded unchanged.
|
|
1450
1896
|
|
|
1451
|
-
**Example**
|
|
1452
|
-
|
|
1453
1897
|
```ts
|
|
1454
1898
|
const a = point(0, 0);
|
|
1455
1899
|
const b = point(100, 0);
|
|
1456
1900
|
dimLine(line(a, b), { label: "Span", offset: -8 });
|
|
1457
1901
|
```
|
|
1458
1902
|
|
|
1459
|
-
|
|
1903
|
+
```ts
|
|
1904
|
+
dimLine(l: Line2D, opts?: DimOpts): void
|
|
1905
|
+
```
|
|
1460
1906
|
|
|
1461
1907
|
---
|
|
1462
1908
|
|
|
@@ -1468,15 +1914,21 @@ Extract 2D geometry from a 3D solid (section, projection).
|
|
|
1468
1914
|
|
|
1469
1915
|
The result is returned in the face's local 2D coordinate system, making it convenient for offsets, pocket profiles, or follow-up sketch operations driven by an existing face.
|
|
1470
1916
|
|
|
1471
|
-
|
|
1917
|
+
```ts
|
|
1918
|
+
faceProfile(shape: Shape, face: FaceSelector): Sketch
|
|
1919
|
+
```
|
|
1472
1920
|
|
|
1473
1921
|
#### `intersectWithPlane()` — Cross-section: slice a 3D shape with a plane and return the intersection as a 2D Sketch.
|
|
1474
1922
|
|
|
1475
|
-
|
|
1923
|
+
```ts
|
|
1924
|
+
intersectWithPlane(shape: Shape, plane: PlaneSpec): Sketch
|
|
1925
|
+
```
|
|
1476
1926
|
|
|
1477
1927
|
#### `projectToPlane()` — Orthographically project a 3D shape onto a plane and return the silhouette as a 2D Sketch.
|
|
1478
1928
|
|
|
1479
|
-
|
|
1929
|
+
```ts
|
|
1930
|
+
projectToPlane(shape: Shape, plane: PlaneSpec): Sketch
|
|
1931
|
+
```
|
|
1480
1932
|
|
|
1481
1933
|
---
|
|
1482
1934
|
|
|
@@ -1486,13 +1938,11 @@ Convert geometry to external formats (STL, 3MF, SVG, DXF, G-code, PDF).
|
|
|
1486
1938
|
|
|
1487
1939
|
#### `bom()` — Register a Bill of Materials entry for report export.
|
|
1488
1940
|
|
|
1489
|
-
**Details**
|
|
1490
|
-
|
|
1491
1941
|
BOM entries are accumulated during script execution and exported alongside the model in report views. Rows are grouped by normalized `description + unit`. Pass an explicit `key` to force multiple descriptions to collapse into a single line item.
|
|
1492
1942
|
|
|
1493
|
-
- `quantity` must be a finite number `>= 0`. A quantity of `0` is silently ignored (useful for conditional scripting with `param()`-driven counts).
|
|
1494
|
-
|
|
1495
|
-
|
|
1943
|
+
- `quantity` must be a finite number `>= 0`. A quantity of `0` is silently ignored (useful for conditional scripting with `param()`-driven counts).
|
|
1944
|
+
- `unit` defaults to `"pieces"` when omitted or empty.
|
|
1945
|
+
- The assembly `solved.bom()` / `solved.bomCsv()` API is separate and covers per-part assembly metadata; this function is for free-form purchased-item annotation.
|
|
1496
1946
|
|
|
1497
1947
|
```ts
|
|
1498
1948
|
const tubeLen = param("Tube Length", 1200, { min: 300, max: 4000, unit: "mm" });
|
|
@@ -1501,27 +1951,54 @@ const boltCount = param("Bolt Count", 16, { min: 0, max: 200, integer: true });
|
|
|
1501
1951
|
bom(tubeLen, "iron tube 30 x 20", { unit: "mm" });
|
|
1502
1952
|
bom(boltCount, "M4 bolt, 16 mm length");
|
|
1503
1953
|
bom(4, "rubber foot", { key: "foot-rubber" }); // explicit aggregation key
|
|
1954
|
+
|
|
1955
|
+
// Structured metadata for richer reports:
|
|
1956
|
+
bom(tubeLen, "rectangular steel tube", {
|
|
1957
|
+
unit: "mm",
|
|
1958
|
+
material: "steel",
|
|
1959
|
+
section: [30, 20],
|
|
1960
|
+
wall: 3,
|
|
1961
|
+
});
|
|
1504
1962
|
```
|
|
1505
1963
|
|
|
1506
|
-
|
|
1964
|
+
```ts
|
|
1965
|
+
bom(quantity: number, description: string, opts?: BomOpts): void
|
|
1966
|
+
```
|
|
1507
1967
|
|
|
1508
1968
|
**`BomOpts`**
|
|
1509
|
-
|
|
1510
|
-
|
|
1969
|
+
|
|
1970
|
+
| Option | Type | Description |
|
|
1971
|
+
|--------|------|-------------|
|
|
1972
|
+
| `unit?` | `string` | Quantity unit label, e.g. "mm", "pieces", "kg". Default: "pieces" |
|
|
1973
|
+
| `key?` | `string` | Optional explicit grouping key used during report aggregation. |
|
|
1974
|
+
| `material?` | `string` | Material name, e.g. "steel", "birch plywood", "nylon" |
|
|
1975
|
+
| `dimensions?` | `number[]` | Overall dimensions `[width, height]` or `[width, height, thickness]` in the entry's unit |
|
|
1976
|
+
| `section?` | `number[]` | Cross-section dimensions `[w, h]` for tubes and profiles |
|
|
1977
|
+
| `wall?` | `number` | Wall thickness for hollow sections (mm) |
|
|
1978
|
+
| `diameter?` | `number` | Diameter for round stock, bolts, dowels (mm) |
|
|
1979
|
+
| `length?` | `number` | Length for fasteners (mm) |
|
|
1980
|
+
| `process?` | `string` | Manufacturing process, e.g. "laser cut", "CNC", "welded" |
|
|
1981
|
+
| `notes?` | `string` | Free-form notes |
|
|
1982
|
+
| `grain?` | `string` | Wood grain direction, e.g. "long", "cross" |
|
|
1511
1983
|
|
|
1512
1984
|
#### `robotExport()` — Declare that this script should export the assembly as a SDF/URDF robot package.
|
|
1513
1985
|
|
|
1514
|
-
|
|
1986
|
+
Call `robotExport()` alongside your assembly definition. The CLI commands `forgecad export sdf` and `forgecad export urdf` pick up the declaration and produce a robot package with:
|
|
1515
1987
|
|
|
1516
|
-
|
|
1988
|
+
- Mesh-based inertia tensors (full 6-component, not bounding-box approximations)
|
|
1989
|
+
- Separate collision meshes (convex hull by default — ~50–80% smaller)
|
|
1990
|
+
- Joint mimic elements derived from `addJointCoupling` / `addGearCoupling`
|
|
1517
1991
|
|
|
1518
1992
|
**Collision mesh modes** (set per-link via `links["PartName"].collision`):
|
|
1519
1993
|
|
|
1520
1994
|
| Mode | Description | Default | |------|-------------|---------| | `'convex'` | Convex hull (separate `_collision.stl`) | Yes | | `'box'` | AABB primitive — fastest physics | | | `'visual'` | Same mesh as visual — exact but slow | | | `'none'` | No collision geometry | |
|
|
1521
1995
|
|
|
1522
|
-
**Unit conventions:**
|
|
1996
|
+
**Unit conventions:**
|
|
1523
1997
|
|
|
1524
|
-
|
|
1998
|
+
- Revolute `velocity` is in degrees/second in Forge; exporters convert to rad/s.
|
|
1999
|
+
- Prismatic distances are in mm in Forge; exported in meters.
|
|
2000
|
+
- `massKg` is preferred; `densityKgM3` is used when mass is unknown.
|
|
2001
|
+
- Couplings with multiple terms: only the primary term (largest ratio) maps to `<mimic>` — SDF/URDF support single-leader mimic only. Dropped terms emit a warning.
|
|
1525
2002
|
|
|
1526
2003
|
```ts
|
|
1527
2004
|
const rover = assembly("Scout")
|
|
@@ -1557,7 +2034,9 @@ forgecad export sdf model.forge.js # SDF package (Gazebo/Ignition)
|
|
|
1557
2034
|
forgecad export urdf model.forge.js # URDF package (ROS/PyBullet/MuJoCo)
|
|
1558
2035
|
```
|
|
1559
2036
|
|
|
1560
|
-
|
|
2037
|
+
```ts
|
|
2038
|
+
robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
2039
|
+
```
|
|
1561
2040
|
|
|
1562
2041
|
**`RobotExportOptions`**: `assembly: Assembly`, `modelName?: string`, `state?: JointState`, `static?: boolean`, `selfCollide?: boolean`, `allowAutoDisable?: boolean`, `links?: Record<string, RobotLinkExportOptions>`, `joints?: Record<string, RobotJointExportOptions>`, `diffDrive?: RobotDiffDrivePluginOptions`, `jointStatePublisher?: RobotJointStatePublisherOptions`, `world?: RobotWorldOptions`
|
|
1563
2042
|
|
|
@@ -1589,15 +2068,16 @@ forgecad export urdf model.forge.js # URDF package (ROS/PyBullet/MuJoCo)
|
|
|
1589
2068
|
|
|
1590
2069
|
#### `sheetMetal()` — Create a parametric sheet metal part with flanges, bend allowances, and flat-pattern unfolding.
|
|
1591
2070
|
|
|
1592
|
-
**Details**
|
|
1593
|
-
|
|
1594
2071
|
`sheetMetal()` keeps one semantic model and derives both a folded 3D solid and an accurate flat pattern from it. The K-factor bend allowance is applied during unfolding. This is a strict v1 subset — it does not infer sheet metal from arbitrary solids.
|
|
1595
2072
|
|
|
1596
|
-
**Recommended authoring order:**
|
|
2073
|
+
**Recommended authoring order:**
|
|
1597
2074
|
|
|
1598
|
-
|
|
2075
|
+
1. Define the base panel + thickness + bend parameters.
|
|
2076
|
+
2. Chain `.flange()` calls for each edge. Validate with `.folded()` and `.flatPattern()` before adding cutouts.
|
|
2077
|
+
3. Add panel cutouts, then flange cutouts one region at a time.
|
|
2078
|
+
4. Validate after each new cutout region.
|
|
1599
2079
|
|
|
1600
|
-
**
|
|
2080
|
+
**v1 limitations:** one base panel, up to four 90° edge flanges, constant thickness, explicit K-factor, rectangular corner reliefs, planar cutouts only. No hems, jogs, lofted bends, non-90° flanges, or bend-region cutouts.
|
|
1601
2081
|
|
|
1602
2082
|
```ts
|
|
1603
2083
|
const cover = sheetMetal({
|
|
@@ -1618,7 +2098,9 @@ const folded = cover.folded();
|
|
|
1618
2098
|
const flat = cover.flatPattern();
|
|
1619
2099
|
```
|
|
1620
2100
|
|
|
1621
|
-
|
|
2101
|
+
```ts
|
|
2102
|
+
sheetMetal(options: SheetMetalOptions): SheetMetalPart
|
|
2103
|
+
```
|
|
1622
2104
|
|
|
1623
2105
|
**`SheetMetalOptions`**
|
|
1624
2106
|
|
|
@@ -1634,20 +2116,18 @@ const flat = cover.flatPattern();
|
|
|
1634
2116
|
|
|
1635
2117
|
#### `sketchToDxf()` — Export a 2D sketch as a DXF string (R12/AC1009 — maximally compatible).
|
|
1636
2118
|
|
|
1637
|
-
**Details**
|
|
1638
|
-
|
|
1639
2119
|
For regular sketches, each polygon loop becomes a closed `LWPOLYLINE`. For constrained sketches, exports raw `LINE`, `CIRCLE`, and `ARC` entities from the constraint edge geometry, which preserves internal/shared edges that `toPolygons()` would merge away.
|
|
1640
2120
|
|
|
1641
2121
|
The R12 format is chosen for maximum compatibility with CAM tools, laser-cutter software, and older CAD readers.
|
|
1642
2122
|
|
|
1643
|
-
**Example**
|
|
1644
|
-
|
|
1645
2123
|
```ts
|
|
1646
2124
|
const s = rect(100, 60);
|
|
1647
2125
|
const dxf = sketchToDxf(s, { layer: 'cut' });
|
|
1648
2126
|
```
|
|
1649
2127
|
|
|
1650
|
-
|
|
2128
|
+
```ts
|
|
2129
|
+
sketchToDxf(sketch: Sketch, options?: SketchDxfOptions): string
|
|
2130
|
+
```
|
|
1651
2131
|
|
|
1652
2132
|
**`SketchDxfOptions`**
|
|
1653
2133
|
- `layer?: string` — DXF layer name. Default: "0"
|
|
@@ -1655,20 +2135,18 @@ const dxf = sketchToDxf(s, { layer: 'cut' });
|
|
|
1655
2135
|
|
|
1656
2136
|
#### `sketchToSvg()` — Export a 2D sketch as an SVG string.
|
|
1657
2137
|
|
|
1658
|
-
**Details**
|
|
1659
|
-
|
|
1660
2138
|
For regular sketches, exports filled polygon regions. For constrained sketches, exports raw edge geometry (LINE, ARC, CIRCLE) which preserves internal/shared edges that `toPolygons()` would merge away.
|
|
1661
2139
|
|
|
1662
2140
|
The SVG uses the sketch's native coordinate system (Y-up) with a CSS transform that flips Y so the output renders correctly in SVG's Y-down space. Coordinates are in sketch units (typically mm).
|
|
1663
2141
|
|
|
1664
|
-
**Example**
|
|
1665
|
-
|
|
1666
2142
|
```ts
|
|
1667
2143
|
const s = rect(100, 60);
|
|
1668
2144
|
const svg = sketchToSvg(s, { stroke: '#333', strokeWidth: 0.8 });
|
|
1669
2145
|
```
|
|
1670
2146
|
|
|
1671
|
-
|
|
2147
|
+
```ts
|
|
2148
|
+
sketchToSvg(sketch: Sketch, options?: SketchSvgOptions): string
|
|
2149
|
+
```
|
|
1672
2150
|
|
|
1673
2151
|
**`SketchSvgOptions`**
|
|
1674
2152
|
|
|
@@ -1686,9 +2164,121 @@ const svg = sketchToSvg(s, { stroke: '#333', strokeWidth: 0.8 });
|
|
|
1686
2164
|
|
|
1687
2165
|
Control viewport appearance and debugging aids.
|
|
1688
2166
|
|
|
1689
|
-
#### `
|
|
2167
|
+
#### `verify.that()` — Custom predicate check.
|
|
2168
|
+
|
|
2169
|
+
```ts
|
|
2170
|
+
verify.that(label: string, check: () => boolean, message?: string): void
|
|
2171
|
+
```
|
|
2172
|
+
|
|
2173
|
+
#### `verify.equal()` — Check that two numbers are approximately equal (within tolerance).
|
|
2174
|
+
|
|
2175
|
+
```ts
|
|
2176
|
+
verify.equal(label: string, actual: number, expected: number, tolerance?: number, message?: string): void
|
|
2177
|
+
```
|
|
1690
2178
|
|
|
1691
|
-
|
|
2179
|
+
#### `verify.notEqual()` — Check that two numbers are NOT equal (differ by more than tolerance).
|
|
2180
|
+
|
|
2181
|
+
```ts
|
|
2182
|
+
verify.notEqual(label: string, actual: number, unexpected: number, tolerance?: number, message?: string): void
|
|
2183
|
+
```
|
|
2184
|
+
|
|
2185
|
+
#### `verify.greaterThan()` — Check that actual > min.
|
|
2186
|
+
|
|
2187
|
+
```ts
|
|
2188
|
+
verify.greaterThan(label: string, actual: number, min: number, message?: string): void
|
|
2189
|
+
```
|
|
2190
|
+
|
|
2191
|
+
#### `verify.lessThan()` — Check that actual < max.
|
|
2192
|
+
|
|
2193
|
+
```ts
|
|
2194
|
+
verify.lessThan(label: string, actual: number, max: number, message?: string): void
|
|
2195
|
+
```
|
|
2196
|
+
|
|
2197
|
+
#### `verify.inRange()` — Check that min <= actual <= max.
|
|
2198
|
+
|
|
2199
|
+
```ts
|
|
2200
|
+
verify.inRange(label: string, actual: number, min: number, max: number, message?: string): void
|
|
2201
|
+
```
|
|
2202
|
+
|
|
2203
|
+
#### `verify.centersCoincide()` — Check that the bounding-box centers of two shapes coincide within tolerance (mm).
|
|
2204
|
+
|
|
2205
|
+
```ts
|
|
2206
|
+
verify.centersCoincide(label: string, a: ShapeLike, b: ShapeLike, tolerance?: number): void
|
|
2207
|
+
```
|
|
2208
|
+
|
|
2209
|
+
#### `verify.notColliding()` — Check that two shapes do not collide (minGap > 0).
|
|
2210
|
+
|
|
2211
|
+
```ts
|
|
2212
|
+
verify.notColliding(label: string, a: ShapeLike, b: ShapeLike, searchLength?: number): void
|
|
2213
|
+
```
|
|
2214
|
+
|
|
2215
|
+
#### `verify.minClearance()` — Check that a minimum clearance gap exists between two shapes.
|
|
2216
|
+
|
|
2217
|
+
```ts
|
|
2218
|
+
verify.minClearance(label: string, a: ShapeLike, b: ShapeLike, minGap: number, searchLength?: number): void
|
|
2219
|
+
```
|
|
2220
|
+
|
|
2221
|
+
#### `verify.parallel()` — Check that two face normals are parallel (within toleranceDeg degrees).
|
|
2222
|
+
|
|
2223
|
+
```ts
|
|
2224
|
+
verify.parallel(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number): void
|
|
2225
|
+
```
|
|
2226
|
+
|
|
2227
|
+
#### `verify.perpendicular()` — Check that two face normals are perpendicular (within toleranceDeg degrees).
|
|
2228
|
+
|
|
2229
|
+
```ts
|
|
2230
|
+
verify.perpendicular(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number): void
|
|
2231
|
+
```
|
|
2232
|
+
|
|
2233
|
+
#### `verify.coplanar()` — Check that a face is coplanar with (same plane as) another face, meaning they are parallel AND their centers lie on the same plane.
|
|
2234
|
+
|
|
2235
|
+
```ts
|
|
2236
|
+
verify.coplanar(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number, toleranceMm?: number): void
|
|
2237
|
+
```
|
|
2238
|
+
|
|
2239
|
+
#### `verify.faceAt()` — Check that a face center lies at a specific position (within toleranceMm).
|
|
2240
|
+
|
|
2241
|
+
```ts
|
|
2242
|
+
verify.faceAt(label: string, face: FaceRefLike, expectedPos: [ number
|
|
2243
|
+
```
|
|
2244
|
+
|
|
2245
|
+
#### `verify.sameDirection()` — Check that two face normals point in the same direction (not antiparallel). Stricter than parallel — both |angle| AND sign must match.
|
|
2246
|
+
|
|
2247
|
+
```ts
|
|
2248
|
+
verify.sameDirection(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number): void
|
|
2249
|
+
```
|
|
2250
|
+
|
|
2251
|
+
#### `verify.isEmpty()` — Check that a shape is empty.
|
|
2252
|
+
|
|
2253
|
+
```ts
|
|
2254
|
+
verify.isEmpty(label: string, shape: ShapeLike, message?: string): void
|
|
2255
|
+
```
|
|
2256
|
+
|
|
2257
|
+
#### `verify.notEmpty()` — Check that a shape is NOT empty.
|
|
2258
|
+
|
|
2259
|
+
```ts
|
|
2260
|
+
verify.notEmpty(label: string, shape: ShapeLike, message?: string): void
|
|
2261
|
+
```
|
|
2262
|
+
|
|
2263
|
+
#### `verify.volumeApprox()` — Check that a shape's volume is approximately equal to expected (mm³).
|
|
2264
|
+
|
|
2265
|
+
```ts
|
|
2266
|
+
verify.volumeApprox(label: string, shape: ShapeLike, expected: number, tolerance?: number): void
|
|
2267
|
+
```
|
|
2268
|
+
|
|
2269
|
+
#### `verify.areaApprox()` — Check that a shape's surface area is approximately equal to expected (mm²).
|
|
2270
|
+
|
|
2271
|
+
```ts
|
|
2272
|
+
verify.areaApprox(label: string, shape: ShapeLike, expected: number, tolerance?: number): void
|
|
2273
|
+
```
|
|
2274
|
+
|
|
2275
|
+
#### `verify.boundingBoxSize()` — Check that a shape's bounding box has approximately the given size.
|
|
2276
|
+
|
|
2277
|
+
```ts
|
|
2278
|
+
verify.boundingBoxSize(label: string, shape: ShapeLike, expectedSize: [ number
|
|
2279
|
+
```
|
|
2280
|
+
|
|
2281
|
+
#### `explodeView()` — Configure how the viewport explode slider offsets returned objects.
|
|
1692
2282
|
|
|
1693
2283
|
Offsets are resolved from the returned object tree, not a flat list. In `radial` mode each node follows its parent branch direction, then fans locally from the immediate parent center — nested assemblies peel apart level by level. In fixed-axis or fixed-vector modes, the branch follows that axis/vector but nested descendants fan out perpendicular by default.
|
|
1694
2284
|
|
|
@@ -1696,8 +2286,6 @@ Multiple calls merge — later values override earlier ones on a per-key basis.
|
|
|
1696
2286
|
|
|
1697
2287
|
For programmatic explode applied before returning (without the slider), use `lib.explode()` instead.
|
|
1698
2288
|
|
|
1699
|
-
**Example**
|
|
1700
|
-
|
|
1701
2289
|
```js
|
|
1702
2290
|
explodeView({
|
|
1703
2291
|
amountScale: 1.2,
|
|
@@ -1707,7 +2295,9 @@ explodeView({
|
|
|
1707
2295
|
});
|
|
1708
2296
|
```
|
|
1709
2297
|
|
|
1710
|
-
|
|
2298
|
+
```ts
|
|
2299
|
+
explodeView(options?: ExplodeViewOptions): void
|
|
2300
|
+
```
|
|
1711
2301
|
|
|
1712
2302
|
**`ExplodeViewOptions`**
|
|
1713
2303
|
|
|
@@ -1728,15 +2318,42 @@ explodeView({
|
|
|
1728
2318
|
|
|
1729
2319
|
#### `cutPlane()`
|
|
1730
2320
|
|
|
1731
|
-
|
|
2321
|
+
```ts
|
|
2322
|
+
cutPlane(name: string, normal: [ number, number, number ], options?: CutPlaneOptions): void
|
|
2323
|
+
```
|
|
1732
2324
|
|
|
1733
2325
|
**`CutPlaneOptions`**
|
|
1734
2326
|
- `offset?: number` — Optional offset along the plane normal (primarily for object-form overload).
|
|
1735
2327
|
- `exclude?: CutPlaneExcludeInput` — Object names to keep uncut for this plane.
|
|
1736
2328
|
|
|
1737
|
-
#### `
|
|
2329
|
+
#### `mock()` — Register a mock (context) object for visualization and collision checking.
|
|
2330
|
+
|
|
2331
|
+
Mock objects appear in the viewport and spatial analysis when you run a file directly, but are excluded when the file is imported via `require()`. This lets you model the surrounding context — walls, bolts, mating parts — without polluting the module's exports.
|
|
2332
|
+
|
|
2333
|
+
The shape is returned unchanged, so you can reference it for alignment, dimensioning, and `verify` checks.
|
|
2334
|
+
|
|
2335
|
+
Mock objects participate in `forgecad run` collision detection and spatial analysis. Their names appear with a `(mock)` suffix in reports.
|
|
2336
|
+
|
|
2337
|
+
In the viewport, mock objects render at reduced opacity so they are visually distinct from real geometry.
|
|
2338
|
+
|
|
2339
|
+
```ts
|
|
2340
|
+
// bracket.forge.js
|
|
2341
|
+
const wall = mock(box(100, 200, 10).translate(0, 0, -5), "wall");
|
|
2342
|
+
const bolt = mock(cylinder(3, 15).translate(10, 15, 0), "bolt");
|
|
2343
|
+
|
|
2344
|
+
const bracket = box(20, 30, 5);
|
|
2345
|
+
verify.notColliding("bracket vs wall", bracket, wall);
|
|
2346
|
+
|
|
2347
|
+
return bracket;
|
|
2348
|
+
// When imported: only bracket is exported
|
|
2349
|
+
// When run directly: bracket + wall + bolt all visible
|
|
2350
|
+
```
|
|
1738
2351
|
|
|
1739
|
-
|
|
2352
|
+
```ts
|
|
2353
|
+
mock<T extends Shape>(shape: T, name?: string): T
|
|
2354
|
+
```
|
|
2355
|
+
|
|
2356
|
+
#### `scene()` — Configure the scene environment for the current script execution.
|
|
1740
2357
|
|
|
1741
2358
|
Controls camera position, lighting rig, background color or gradient, atmospheric fog, environment maps, post-processing effects, and capture parameters for the `forgecad capture` command. Multiple calls merge — later values override earlier ones on a per-key basis, so you can split configuration across multiple `scene()` calls.
|
|
1742
2359
|
|
|
@@ -1748,8 +2365,6 @@ Post-processing effects (`bloom`, `vignette`, `grain`) work in the browser viewp
|
|
|
1748
2365
|
|
|
1749
2366
|
All numeric values accept `param()` expressions.
|
|
1750
2367
|
|
|
1751
|
-
**Example**
|
|
1752
|
-
|
|
1753
2368
|
```js
|
|
1754
2369
|
scene({
|
|
1755
2370
|
background: { top: '#000814', bottom: '#001d3d' },
|
|
@@ -1771,7 +2386,9 @@ scene({
|
|
|
1771
2386
|
});
|
|
1772
2387
|
```
|
|
1773
2388
|
|
|
1774
|
-
|
|
2389
|
+
```ts
|
|
2390
|
+
scene(options: SceneOptions): void
|
|
2391
|
+
```
|
|
1775
2392
|
|
|
1776
2393
|
**`SceneOptions`**
|
|
1777
2394
|
|
|
@@ -1840,18 +2457,16 @@ scene({
|
|
|
1840
2457
|
|
|
1841
2458
|
Shows each user-authored label name in the viewport for visual debugging. Returns the shape unchanged for chaining: `return showLabels(myShape)`.
|
|
1842
2459
|
|
|
1843
|
-
|
|
2460
|
+
```ts
|
|
2461
|
+
showLabels(shape: Shape): Shape
|
|
2462
|
+
```
|
|
1844
2463
|
|
|
1845
2464
|
#### `viewConfig()` — Configure viewport helper visuals for the current script execution.
|
|
1846
2465
|
|
|
1847
|
-
**Details**
|
|
1848
|
-
|
|
1849
2466
|
Controls renderer-only overlays that appear in the viewport but are not part of the geometry. Currently supports the joint overlay that renders axis arrows and arc indicators when `jointsView` is active. Multiple calls merge — later values override earlier ones per key.
|
|
1850
2467
|
|
|
1851
2468
|
This does **not** trigger a geometry recompute; it only affects the visual helpers drawn on top of the 3D scene.
|
|
1852
2469
|
|
|
1853
|
-
**Example**
|
|
1854
|
-
|
|
1855
2470
|
```js
|
|
1856
2471
|
viewConfig({
|
|
1857
2472
|
jointOverlay: {
|
|
@@ -1863,7 +2478,9 @@ viewConfig({
|
|
|
1863
2478
|
});
|
|
1864
2479
|
```
|
|
1865
2480
|
|
|
1866
|
-
|
|
2481
|
+
```ts
|
|
2482
|
+
viewConfig(options?: ViewConfigOptions): void
|
|
2483
|
+
```
|
|
1867
2484
|
|
|
1868
2485
|
`ViewConfigOptions`: `{ jointOverlay?: JointOverlayViewConfigOptions }`
|
|
1869
2486
|
|
|
@@ -1871,16 +2488,12 @@ viewConfig({
|
|
|
1871
2488
|
|
|
1872
2489
|
#### `spec()` — Create a named, reusable bundle of verification checks.
|
|
1873
2490
|
|
|
1874
|
-
**Details**
|
|
1875
|
-
|
|
1876
2491
|
A spec groups related `verify.*` calls under a collapsible header in the Checks panel. This makes large check suites scannable. Specs can be applied to multiple shapes and can check relationships between parts.
|
|
1877
2492
|
|
|
1878
2493
|
Specs can be defined in separate `.forge.js` files and imported via `require()` to share them across models.
|
|
1879
2494
|
|
|
1880
2495
|
`spec.check()` returns a `SpecResult` — you can inspect it programmatically or ignore the return value and let the Checks panel show results.
|
|
1881
2496
|
|
|
1882
|
-
**Example**
|
|
1883
|
-
|
|
1884
2497
|
```ts
|
|
1885
2498
|
const printable = spec("Fits printer bed", (shape) => {
|
|
1886
2499
|
verify.notEmpty("Has geometry", shape);
|
|
@@ -1903,7 +2516,9 @@ fitSpec.check(bracket, standoff);
|
|
|
1903
2516
|
|
|
1904
2517
|
**Spec-first workflow:** Write specs before building geometry. Checks go from red to green as you build — effectively TDD for CAD.
|
|
1905
2518
|
|
|
1906
|
-
|
|
2519
|
+
```ts
|
|
2520
|
+
spec(name: string, checkFn: (...args: any[]) => void): Spec
|
|
2521
|
+
```
|
|
1907
2522
|
|
|
1908
2523
|
**`Spec`**
|
|
1909
2524
|
- `name: string` — The display name of this spec
|
|
@@ -1920,11 +2535,19 @@ Unlike union(), colors and individual identities are preserved. Children can be
|
|
|
1920
2535
|
|
|
1921
2536
|
**Local coordinate pattern:** Build child parts at the origin (local coordinates), then group and translate once to place the whole assembly. This eliminates the error-prone pattern of manually adding parent offsets to every sub-part.
|
|
1922
2537
|
|
|
1923
|
-
|
|
2538
|
+
```js
|
|
2539
|
+
// BAD — every sub-part repeats the parent's global offset
|
|
2540
|
+
const unitX = 0, unitY = -18, unitZ = 70;
|
|
2541
|
+
const body = roundedBox(100, 20, 32, 4).translate(unitX, unitY, unitZ);
|
|
2542
|
+
const panel = box(98, 2, 18).translate(unitX, unitY - 12, unitZ + 4);
|
|
2543
|
+
const louver = box(88, 2, 6).translate(unitX, unitY - 14, unitZ - 11);
|
|
2544
|
+
```
|
|
1924
2545
|
|
|
1925
2546
|
// GOOD — build at origin, group, translate once const body = roundedBox(100, 20, 32, 4); const panel = box(98, 2, 18).translate(0, -12, 4); const louver = box(88, 2, 6).translate(0, -14, -11); const indoorUnit = group( { name: 'Body', shape: body }, { name: 'Panel', shape: panel }, { name: 'Louver', shape: louver }, ).translate(0, -18, 70);
|
|
1926
2547
|
|
|
1927
|
-
|
|
2548
|
+
```ts
|
|
2549
|
+
group(...items: GroupInput[]): ShapeGroup
|
|
2550
|
+
```
|
|
1928
2551
|
|
|
1929
2552
|
---
|
|
1930
2553
|
|
|
@@ -1932,6 +2555,46 @@ Unlike union(), colors and individual identities are preserved. Children can be
|
|
|
1932
2555
|
|
|
1933
2556
|
Pre-built parametric parts accessible via `lib.*`.
|
|
1934
2557
|
|
|
1935
|
-
|
|
2558
|
+
#### `Wood.board()` — Create a wood board with metadata for manufacturing.
|
|
2559
|
+
|
|
2560
|
+
The board is a box(width, height, thickness) centered on XY, base at Z=0. Width along X, height along Y, thickness along Z (0 to thickness).
|
|
2561
|
+
|
|
2562
|
+
```ts
|
|
2563
|
+
Wood.readonly board: (width: number, height: number, thickness: number, opts?: WoodBoardOptions) => WoodBoard
|
|
2564
|
+
```
|
|
2565
|
+
|
|
2566
|
+
**`WoodBoardOptions`**
|
|
2567
|
+
|
|
2568
|
+
| Option | Type | Description |
|
|
2569
|
+
|--------|------|-------------|
|
|
2570
|
+
| `species?` | `string` | Wood species, e.g. "birch", "oak", "plywood". Default: "wood" |
|
|
2571
|
+
| `material?` | `string` | Material description for BOM, e.g. "birch plywood". Default: species value |
|
|
2572
|
+
| `grain?` | `string` | Grain direction: "long" (along width) or "cross" (along height). Default: "long" |
|
|
2573
|
+
| `color?` | `string` | Color hex string for visualization. Default: "#d2b48c" (tan/wood) |
|
|
2574
|
+
| `autoBom?` | `boolean` | If false, skip automatic BOM registration. Default: true |
|
|
2575
|
+
|
|
2576
|
+
#### `Wood.dado()` — Cut a dado (channel) across the face of a host board for a guest board to sit in.
|
|
2577
|
+
|
|
2578
|
+
Mutates `host.shape` by subtracting a rectangular channel.
|
|
2579
|
+
|
|
2580
|
+
```ts
|
|
2581
|
+
Wood.readonly dado: typeof dado
|
|
2582
|
+
```
|
|
2583
|
+
|
|
2584
|
+
#### `Wood.rabbet()` — Cut a rabbet (L-shaped step) along an edge of a board.
|
|
2585
|
+
|
|
2586
|
+
Mutates `board.shape` by subtracting a step from the specified edge.
|
|
2587
|
+
|
|
2588
|
+
```ts
|
|
2589
|
+
Wood.readonly rabbet: typeof rabbet
|
|
2590
|
+
```
|
|
2591
|
+
|
|
2592
|
+
#### `Wood.mortiseAndTenon()` — Cut a mortise in one board and shape a tenon on another.
|
|
2593
|
+
|
|
2594
|
+
Mutates both boards — subtracts the mortise pocket and removes shoulder material to form the tenon.
|
|
2595
|
+
|
|
2596
|
+
```ts
|
|
2597
|
+
Wood.readonly mortiseAndTenon: typeof mortiseAndTenon
|
|
2598
|
+
```
|
|
1936
2599
|
|
|
1937
2600
|
---
|