forgecad 0.6.3 → 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 +3 -12
- package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-D4bocK4E.js} +250 -151
- package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
- package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-D3A_g8V3.js} +329 -163
- package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-BWYUSpUN.css} +590 -136
- package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
- package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-kWjKaC_t.js} +2 -4
- package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
- package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
- package/dist/assets/PricingPage-BsU5vzEx.js +232 -0
- package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-PqvpAKIs.js} +129 -5
- package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-C-hzNUMy.js} +8949 -3161
- package/dist/assets/{Viewport-CoB46f5R.js → index-Pz321YAt.js} +38382 -7501
- package/dist/assets/{index-2hfs_ub0.css → index-ay13WNfa.css} +726 -53
- package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
- package/dist/assets/{manifold-CqNMHHKO.js → manifold-BcbjWLIo.js} +4 -3
- package/dist/assets/{manifold-Cce9wRFz.js → manifold-DBckbFgx.js} +1 -1
- package/dist/assets/{manifold-D6BeHIOo.js → manifold-O2AAGXyj.js} +1 -1
- package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-Dxr-5A7w.js} +8760 -3559
- package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +341 -718
- package/dist/docs-raw/generated/assembly.md +699 -112
- package/dist/docs-raw/generated/concepts.md +1834 -1346
- package/dist/docs-raw/generated/core.md +1012 -1059
- package/dist/docs-raw/generated/curves.md +759 -116
- package/dist/docs-raw/generated/lib.md +43 -748
- package/dist/docs-raw/generated/output.md +139 -245
- package/dist/docs-raw/generated/sdf.md +208 -0
- package/dist/docs-raw/generated/sheet-metal.md +473 -21
- package/dist/docs-raw/generated/sketch.md +1518 -362
- package/dist/docs-raw/generated/viewport.md +368 -299
- package/dist/docs-raw/generated/wood.md +104 -0
- 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 +12321 -5700
- package/dist-cli/forgecad.js.map +1 -0
- package/dist-cli/solver-46FFSK2U.js +363 -0
- package/dist-cli/solver-46FFSK2U.js.map +1 -0
- package/dist-skill/CONTEXT.md +4890 -6302
- package/dist-skill/SKILL-dev.md +22 -66
- package/dist-skill/SKILL.md +20 -59
- package/dist-skill/docs/API/core/concepts.md +37 -92
- package/dist-skill/docs/CLI.md +341 -718
- package/dist-skill/docs/generated/assembly.md +699 -112
- package/dist-skill/docs/generated/core.md +1012 -1059
- package/dist-skill/docs/generated/curves.md +759 -116
- package/dist-skill/docs/generated/lib.md +43 -748
- package/dist-skill/docs/generated/output.md +139 -245
- package/dist-skill/docs/generated/sdf.md +208 -0
- package/dist-skill/docs/generated/sheet-metal.md +473 -21
- package/dist-skill/docs/generated/sketch.md +1518 -362
- package/dist-skill/docs/generated/viewport.md +368 -299
- package/dist-skill/docs/generated/wood.md +104 -0
- package/dist-skill/docs/guides/coordinate-system.md +11 -17
- package/dist-skill/docs/guides/geometry-conventions.md +13 -70
- package/dist-skill/docs/guides/joint-design.md +78 -0
- package/dist-skill/docs/guides/modeling-recipes.md +22 -195
- package/dist-skill/docs/guides/positioning.md +88 -147
- package/dist-skill/docs-dev/API/core/concepts.md +78 -0
- package/dist-skill/docs-dev/CLI.md +488 -0
- package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
- package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
- package/dist-skill/{docs → docs-dev}/coding.md +2 -4
- package/dist-skill/docs-dev/component-model.md +164 -0
- package/dist-skill/docs-dev/generated/assembly.md +779 -0
- package/dist-skill/docs-dev/generated/core.md +1676 -0
- package/dist-skill/docs-dev/generated/curves.md +855 -0
- package/dist-skill/docs-dev/generated/lib.md +55 -0
- package/dist-skill/docs-dev/generated/output.md +234 -0
- package/dist-skill/docs-dev/generated/sdf.md +208 -0
- package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
- package/dist-skill/docs-dev/generated/sketch.md +1753 -0
- package/dist-skill/docs-dev/generated/viewport.md +513 -0
- package/dist-skill/docs-dev/generated/wood.md +104 -0
- package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
- package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
- package/dist-skill/docs-dev/guides/joint-design.md +78 -0
- package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
- package/dist-skill/docs-dev/guides/positioning.md +151 -0
- package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
- package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
- package/examples/api/attachTo-basics.forge.js +8 -8
- 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 +5 -5
- package/examples/api/bounding-box-visualizer.forge.js +3 -3
- package/examples/api/clone-duplicate.forge.js +2 -2
- package/examples/api/colors-union-vs-array.forge.js +6 -6
- package/examples/api/connector-assembly.forge.js +8 -6
- package/examples/api/connector-basics.forge.js +7 -7
- 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 +8 -14
- package/examples/api/feature-created-faces.forge.js +6 -10
- package/examples/api/fillet-showcase.forge.js +2 -2
- package/examples/api/folded-service-panel-cover.forge.js +2 -2
- package/examples/api/gears-tier1.forge.js +5 -5
- package/examples/api/group-test.forge.js +3 -3
- package/examples/api/group-vs-union.forge.js +1 -1
- package/examples/api/highlight-debug.forge.js +4 -0
- package/examples/api/js-module-pillars.js +1 -1
- package/examples/api/js-module-scene.js +2 -2
- package/examples/api/mesh-import-slats.forge.js +4 -4
- package/examples/api/patterns.forge.js +3 -3
- package/examples/api/pointAlong-orientation.forge.js +3 -3
- package/examples/api/profile-2020-b-slot6.forge.js +4 -5
- package/examples/api/route-perimeter-flange.forge.js +1 -1
- package/examples/api/sdf-rover-demo.forge.js +10 -10
- package/examples/api/sketch-on-face-demo.forge.js +2 -2
- package/examples/api/sketch-regions.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 +4 -4
- package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
- package/examples/api/variable-sweep-test.forge.js +2 -2
- package/examples/api/wood-joinery.forge.js +60 -0
- package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
- package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
- 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/experiments/drone-arm.forge.js +53 -0
- package/examples/furniture/adjustable-table.forge.js +15 -15
- package/examples/furniture/bathroom.forge.js +26 -26
- package/examples/furniture/chair.forge.js +13 -13
- 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 +9 -9
- package/examples/generative/frost-spires.forge.js +9 -9
- package/examples/generative/golden-spiral-tower.forge.js +11 -11
- 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 +37 -37
- package/examples/mechanical/5-finger-robot-hand.forge.js +19 -19
- package/examples/mechanical/airplane-propeller.forge.js +9 -9
- 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 +15 -11
- package/examples/mechanical/headphone-hanger-v2.forge.js +11 -11
- package/examples/mechanical/robot_hand.forge.js +24 -24
- package/examples/mechanical/robot_hand_2.forge.js +26 -26
- package/examples/nurbs-surface.forge.js +8 -0
- package/examples/nurbs-tube.forge.js +7 -0
- package/examples/products/bottle.forge.js +8 -8
- package/examples/products/chess-set.forge.js +25 -25
- package/examples/products/classical-piano.forge.js +20 -20
- package/examples/products/clock.forge.js +33 -33
- package/examples/products/cup.forge.js +5 -5
- package/examples/products/iphone.forge.js +20 -20
- package/examples/products/laptop.forge.js +24 -24
- 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 +23 -23
- package/examples/products/origami-fish.forge.js +14 -12
- package/examples/products/spiderman-cake.forge.js +6 -6
- package/examples/shelf/container.forge.js +5 -5
- package/examples/shelf/shelf-unit.forge.js +6 -6
- package/examples/toolbox/bolted-joint.forge.js +7 -7
- package/package.json +9 -4
- package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
- package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
- package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
- package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
- package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
- package/dist/assets/index-1CYp3zUp.js +0 -1455
- package/dist-skill/docs/API/API.md +0 -1666
- package/dist-skill/docs/API/README.md +0 -37
- package/dist-skill/docs/API/assembly/assembly.md +0 -617
- package/dist-skill/docs/API/core/edge-queries.md +0 -130
- package/dist-skill/docs/API/core/parameters.md +0 -122
- package/dist-skill/docs/API/core/reserved-terms.md +0 -137
- package/dist-skill/docs/API/core/sdf.md +0 -326
- package/dist-skill/docs/API/core/skill-cli.md +0 -194
- package/dist-skill/docs/API/core/skill-guide.md +0 -205
- package/dist-skill/docs/API/core/specs.md +0 -186
- package/dist-skill/docs/API/core/topology.md +0 -372
- package/dist-skill/docs/API/entities.md +0 -268
- package/dist-skill/docs/API/output/bom.md +0 -58
- package/dist-skill/docs/API/output/brep-export.md +0 -87
- package/dist-skill/docs/API/output/dimensions.md +0 -67
- package/dist-skill/docs/API/output/export.md +0 -110
- package/dist-skill/docs/API/output/gcode.md +0 -195
- package/dist-skill/docs/API/runtime/viewport.md +0 -420
- package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
- package/dist-skill/docs/API/sketch/anchor.md +0 -37
- package/dist-skill/docs/API/sketch/booleans.md +0 -91
- package/dist-skill/docs/API/sketch/core.md +0 -73
- package/dist-skill/docs/API/sketch/extrude.md +0 -62
- package/dist-skill/docs/API/sketch/on-face.md +0 -104
- package/dist-skill/docs/API/sketch/operations.md +0 -78
- package/dist-skill/docs/API/sketch/path.md +0 -75
- package/dist-skill/docs/API/sketch/primitives.md +0 -146
- package/dist-skill/docs/API/sketch/regions.md +0 -80
- package/dist-skill/docs/API/sketch/text.md +0 -108
- package/dist-skill/docs/API/sketch/transforms.md +0 -65
- package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
- package/dist-skill/docs/INDEX.md +0 -94
- package/dist-skill/docs/RELEASING.md +0 -55
- package/dist-skill/docs/cli-monetization.md +0 -111
- package/dist-skill/docs/deployment.md +0 -281
- package/dist-skill/docs/generated/concepts.md +0 -2112
- package/dist-skill/docs/internals/shape-from-slices.md +0 -152
- package/dist-skill/docs/platform/admin.md +0 -45
- package/dist-skill/docs/platform/architecture.md +0 -79
- package/dist-skill/docs/platform/auth.md +0 -110
- package/dist-skill/docs/platform/email.md +0 -67
- package/dist-skill/docs/platform/projects.md +0 -111
- package/dist-skill/docs/platform/sharing.md +0 -90
- package/dist-skill/docs/runbook.md +0 -345
|
@@ -5,1667 +5,1621 @@ skill-order: 100
|
|
|
5
5
|
|
|
6
6
|
# Core API
|
|
7
7
|
|
|
8
|
-
> **Auto-generated** from `src/forge/forge-public-api.ts`. Do not edit by hand — run `npm run gen:docs` to regenerate.
|
|
9
|
-
|
|
10
8
|
3D primitives, boolean operations, transforms, patterns, imports, and parameters.
|
|
11
9
|
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [Boolean Operations](#boolean-operations) — `union`, `difference`, `intersection`
|
|
13
|
+
- [Edge Features](#edge-features) — `fillet`, `chamfer`, `draft`, `offsetSolid`
|
|
14
|
+
- [Patterns & Layout](#patterns-layout) — `selectEdges`, `selectEdge`, `coalesceEdges`, `filletCorners`, `circularLayout`, `polygonVertices`, `linearPattern`, `circularPattern`, `linearPattern2d`, `circularPattern2d`, `mirrorCopy`
|
|
15
|
+
- [Imports & Composition](#imports-composition) — `require`, `importSvgSketch`, `importMesh`, `importStep`
|
|
16
|
+
- [Parameters](#parameters) — `Param.number`, `Param.string`, `Param.bool`, `Param.choice`, `Param.list`
|
|
17
|
+
- [Grouping & Local Coordinates](#grouping-local-coordinates) — `group`
|
|
18
|
+
- [Section & Projection](#section-projection) — `intersectWithPlane`, `faceProfile`, `projectToPlane`
|
|
19
|
+
- [Transforms](#transforms) — `composeChain`
|
|
20
|
+
- [Verification](#verification) — `spec`
|
|
21
|
+
- [Shape](#shape) — Appearance, Face Topology, Edge Topology, Transforms, Booleans & Cutting, Features, Placement, Connectors, References, Measurement
|
|
22
|
+
- [Transform](#transform)
|
|
23
|
+
- [ShapeGroup](#shapegroup) — Children, Transforms, Placement, Connectors, References
|
|
24
|
+
- [SurfacePattern](#surfacepattern)
|
|
25
|
+
- [ANCHOR3D_NAMES](#anchor3d-names)
|
|
26
|
+
- [verify](#verify)
|
|
27
|
+
- [Constraint](#constraint)
|
|
28
|
+
- [Points](#points)
|
|
29
|
+
- [connector](#connector)
|
|
30
|
+
|
|
12
31
|
## Functions
|
|
13
32
|
|
|
14
|
-
###
|
|
33
|
+
### Boolean Operations
|
|
15
34
|
|
|
16
|
-
|
|
35
|
+
#### `union()` — Combine shapes into a single solid (additive boolean).
|
|
17
36
|
|
|
18
|
-
|
|
37
|
+
Accepts individual shapes, or an array of shapes. The first operand's color is preserved in the result.
|
|
19
38
|
|
|
20
39
|
```ts
|
|
21
|
-
|
|
40
|
+
union(...inputs: ShapeOperandInput[]): Shape
|
|
22
41
|
```
|
|
23
42
|
|
|
24
|
-
|
|
43
|
+
#### `difference()` — Subtract shapes from a base shape (subtractive boolean).
|
|
25
44
|
|
|
26
|
-
|
|
45
|
+
The first shape is the base; all subsequent shapes are subtracted from it. Accepts individual shapes, or an array of shapes.
|
|
27
46
|
|
|
28
47
|
```ts
|
|
29
|
-
|
|
48
|
+
difference(...inputs: ShapeOperandInput[]): Shape
|
|
30
49
|
```
|
|
31
50
|
|
|
32
|
-
|
|
51
|
+
#### `intersection()` — Keep only the overlapping volume of the input shapes (intersection boolean).
|
|
33
52
|
|
|
34
|
-
|
|
53
|
+
Requires at least two shapes. Accepts individual shapes, or an array.
|
|
35
54
|
|
|
36
55
|
```ts
|
|
37
|
-
|
|
56
|
+
intersection(...inputs: ShapeOperandInput[]): Shape
|
|
38
57
|
```
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
### Edge Features
|
|
41
60
|
|
|
42
|
-
|
|
61
|
+
#### `fillet()` — Apply fillets (rounded edges) to one or more edges of a shape.
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
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.
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
union(...shapes: (_ShapeOperand | _ShapeOperand[])[]): Shape
|
|
50
|
-
```
|
|
65
|
+
The `edges` parameter is flexible:
|
|
51
66
|
|
|
52
|
-
|
|
67
|
+
- Omit to fillet **all** sharp edges
|
|
68
|
+
- Pass an `EdgeQuery` for an inline filter (most common)
|
|
69
|
+
- Pass an `EdgeSegment` or `EdgeSegment[]` from `selectEdges()` for pre-selected edges
|
|
53
70
|
|
|
54
|
-
|
|
71
|
+
Throws if no edges match the selection, or if `radius` is not a positive finite number.
|
|
55
72
|
|
|
56
73
|
```ts
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
// Fillet all edges
|
|
75
|
+
fillet(myShape, 2)
|
|
59
76
|
|
|
60
|
-
|
|
77
|
+
// Fillet only top convex edges
|
|
78
|
+
fillet(myShape, 1.5, { atZ: 20, convex: true })
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
// Fillet vertical edges selected beforehand
|
|
81
|
+
const edges = selectEdges(myShape, { parallel: [0, 0, 1] })
|
|
82
|
+
fillet(myShape, 3, edges)
|
|
83
|
+
```
|
|
63
84
|
|
|
64
85
|
```ts
|
|
65
|
-
|
|
86
|
+
fillet(shape: Shape, radius: number, edges?: EdgeSelector, segments?: number): Shape
|
|
66
87
|
```
|
|
67
88
|
|
|
68
|
-
|
|
89
|
+
#### `chamfer()` — Apply chamfers (beveled edges) to one or more edges of a shape.
|
|
69
90
|
|
|
70
|
-
|
|
91
|
+
Produces a 45° bevel at the specified `size` (distance from edge). Works on both straight and curved edges. Supports OCCT and Manifold backends.
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
The `edges` parameter accepts the same options as `fillet()`: inline `EdgeQuery`, pre-selected `EdgeSegment`/`EdgeSegment[]`, or `undefined` (all sharp edges).
|
|
73
94
|
|
|
74
|
-
|
|
95
|
+
```ts
|
|
96
|
+
// Chamfer all edges
|
|
97
|
+
chamfer(myShape, 1)
|
|
98
|
+
|
|
99
|
+
// Chamfer only vertical edges
|
|
100
|
+
chamfer(myShape, 2, { parallel: [0, 0, 1] })
|
|
101
|
+
```
|
|
75
102
|
|
|
76
103
|
```ts
|
|
77
|
-
|
|
104
|
+
chamfer(shape: Shape, size: number, edges?: EdgeSelector): Shape
|
|
78
105
|
```
|
|
79
106
|
|
|
80
|
-
|
|
107
|
+
#### `draft()` — Apply a draft angle (taper) to vertical faces for mold extraction.
|
|
81
108
|
|
|
82
|
-
|
|
109
|
+
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°.
|
|
83
110
|
|
|
84
|
-
|
|
85
|
-
interface EdgeSegment {
|
|
86
|
-
/** Stable index within the extraction (deterministic for a given mesh). */
|
|
87
|
-
index: number;
|
|
88
|
-
start: Vec3;
|
|
89
|
-
end: Vec3;
|
|
90
|
-
midpoint: Vec3;
|
|
91
|
-
/** Normalized direction from start → end. */
|
|
92
|
-
direction: Vec3;
|
|
93
|
-
length: number;
|
|
94
|
-
/** Dihedral angle in degrees (0 = coplanar, 180 = knife edge). */
|
|
95
|
-
dihedralAngle: number;
|
|
96
|
-
/** true = outside corner (convex), false = inside corner (concave). */
|
|
97
|
-
convex: boolean;
|
|
98
|
-
/** Normal of first adjacent face. */
|
|
99
|
-
normalA: Vec3;
|
|
100
|
-
/** Normal of second adjacent face (same as normalA for boundary edges). */
|
|
101
|
-
normalB: Vec3;
|
|
102
|
-
/** true if this is a boundary (unmatched) edge — unusual for closed solids. */
|
|
103
|
-
boundary: boolean;
|
|
104
|
-
}
|
|
105
|
-
```
|
|
111
|
+
Requires the OCCT backend. Throws on Manifold.
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
```ts
|
|
114
|
+
// Add 3° draft to a box for injection molding
|
|
115
|
+
draft(myBox, 3)
|
|
108
116
|
|
|
109
|
-
|
|
117
|
+
// Draft with custom pull direction and neutral plane
|
|
118
|
+
draft(myShape, 2, [0, 0, 1], 10)
|
|
119
|
+
```
|
|
110
120
|
|
|
111
121
|
```ts
|
|
112
|
-
|
|
122
|
+
draft(shape: Shape, angleDeg: number, pullDirection?: [ number, number, number ], neutralPlaneOffset?: number): Shape
|
|
113
123
|
```
|
|
114
124
|
|
|
115
|
-
|
|
125
|
+
#### `offsetSolid()` — Uniformly offset all surfaces of a solid inward or outward.
|
|
126
|
+
|
|
127
|
+
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.
|
|
116
128
|
|
|
117
|
-
|
|
129
|
+
Requires the OCCT backend. Throws on Manifold.
|
|
118
130
|
|
|
119
131
|
```ts
|
|
120
|
-
|
|
132
|
+
// Grow a box outward by 1mm on all sides
|
|
133
|
+
offsetSolid(myBox, 1)
|
|
134
|
+
|
|
135
|
+
// Shrink a shape inward by 0.5mm
|
|
136
|
+
offsetSolid(myShape, -0.5)
|
|
121
137
|
```
|
|
122
138
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
<details><summary><code>EdgeQuery</code></summary>
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
interface EdgeQuery {
|
|
129
|
-
/** Sort by proximity to this point (closest first). */
|
|
130
|
-
near?: Vec3;
|
|
131
|
-
/** Filter: edge direction approximately parallel to this vector. */
|
|
132
|
-
parallel?: Vec3;
|
|
133
|
-
/** Filter: edge direction approximately perpendicular to this vector. */
|
|
134
|
-
perpendicular?: Vec3;
|
|
135
|
-
/** Filter: only convex (outside corner) edges. */
|
|
136
|
-
convex?: boolean;
|
|
137
|
-
/** Filter: only concave (inside corner) edges. */
|
|
138
|
-
concave?: boolean;
|
|
139
|
-
/** Filter: minimum dihedral angle in degrees. */
|
|
140
|
-
minAngle?: number;
|
|
141
|
-
/** Filter: maximum dihedral angle in degrees. */
|
|
142
|
-
maxAngle?: number;
|
|
143
|
-
/** Filter: minimum edge length. */
|
|
144
|
-
minLength?: number;
|
|
145
|
-
/** Filter: maximum edge length. */
|
|
146
|
-
maxLength?: number;
|
|
147
|
-
/** Filter: edge midpoint must be within this bounding region. */
|
|
148
|
-
within?: BoundingRegion;
|
|
149
|
-
/** Shorthand: edge midpoint Z ≈ this value (within tolerance). */
|
|
150
|
-
atZ?: number;
|
|
151
|
-
/** Tolerance for approximate matches (default: 1.0). */
|
|
152
|
-
tolerance?: number;
|
|
153
|
-
/** Angular tolerance in degrees for parallel/perpendicular (default: 10). */
|
|
154
|
-
angleTolerance?: number;
|
|
155
|
-
}
|
|
139
|
+
```ts
|
|
140
|
+
offsetSolid(shape: Shape, thickness: number): Shape
|
|
156
141
|
```
|
|
157
142
|
|
|
158
|
-
|
|
143
|
+
### Patterns & Layout
|
|
144
|
+
|
|
145
|
+
#### `selectEdges()` — Select all edges from a shape that match the given query.
|
|
146
|
+
|
|
147
|
+
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.
|
|
159
148
|
|
|
160
|
-
|
|
149
|
+
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.
|
|
161
150
|
|
|
162
151
|
```ts
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
zMin?: number;
|
|
169
|
-
zMax?: number;
|
|
152
|
+
// Fillet all top edges of a box
|
|
153
|
+
const topEdges = selectEdges(part, { atZ: 20, perpendicular: [0, 0, 1] });
|
|
154
|
+
let result = part;
|
|
155
|
+
for (const edge of coalesceEdges(topEdges)) {
|
|
156
|
+
result = fillet(result, 2, edge);
|
|
170
157
|
}
|
|
171
158
|
```
|
|
172
159
|
|
|
173
|
-
|
|
160
|
+
```ts
|
|
161
|
+
selectEdges(shape: Shape, query?: EdgeQuery): EdgeSegment[]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**`EdgeQuery`**
|
|
165
|
+
|
|
166
|
+
| Option | Type | Description |
|
|
167
|
+
|--------|------|-------------|
|
|
168
|
+
| `near?` | `Vec3` | Sort by proximity to this point (closest first). When used with `selectEdge`, picks the closest match. |
|
|
169
|
+
| `parallel?` | `Vec3` | Filter: edge direction approximately parallel to this vector. |
|
|
170
|
+
| `perpendicular?` | `Vec3` | Filter: edge direction approximately perpendicular to this vector. |
|
|
171
|
+
| `convex?` | `boolean` | Filter: only convex (outside corner) edges. |
|
|
172
|
+
| `concave?` | `boolean` | Filter: only concave (inside corner) edges. |
|
|
173
|
+
| `minAngle?` | `number` | Filter: minimum dihedral angle in degrees. |
|
|
174
|
+
| `maxAngle?` | `number` | Filter: maximum dihedral angle in degrees. |
|
|
175
|
+
| `minLength?` | `number` | Filter: minimum edge length. |
|
|
176
|
+
| `maxLength?` | `number` | Filter: maximum edge length. |
|
|
177
|
+
| `within?` | `BoundingRegion` | Filter: edge midpoint must be within this bounding region. |
|
|
178
|
+
| `atZ?` | `number` | Shorthand: edge midpoint Z ≈ this value (within `tolerance`). Equivalent to `within: { zMin: atZ - tol, zMax: atZ + tol }`. |
|
|
179
|
+
| `tolerance?` | `number` | Position tolerance for approximate matches (default: `1.0`). Used by `atZ` and `near`. |
|
|
180
|
+
| `angleTolerance?` | `number` | Angular tolerance in degrees for `parallel`/`perpendicular` filters (default: `10`). |
|
|
181
|
+
|
|
182
|
+
`BoundingRegion`: `{ xMin?: number, xMax?: number, yMin?: number, yMax?: number, zMin?: number, zMax?: number }`
|
|
183
|
+
|
|
184
|
+
**`EdgeSegment`**
|
|
185
|
+
|
|
186
|
+
| Option | Type | Description |
|
|
187
|
+
|--------|------|-------------|
|
|
188
|
+
| `index` | `number` | Stable index within the extraction (deterministic for a given mesh). |
|
|
189
|
+
| `direction` | `Vec3` | Normalized direction from start → end. |
|
|
190
|
+
| `dihedralAngle` | `number` | Dihedral angle in degrees (0 = coplanar, 180 = knife edge). |
|
|
191
|
+
| `convex` | `boolean` | true = outside corner (convex), false = inside corner (concave). |
|
|
192
|
+
| `normalA` | `Vec3` | Normal of first adjacent face. |
|
|
193
|
+
| `normalB` | `Vec3` | Normal of second adjacent face (same as normalA for boundary edges). |
|
|
194
|
+
| `boundary` | `boolean` | true if this is a boundary (unmatched) edge — unusual for closed solids. |
|
|
195
|
+
| `start`, `end`, `midpoint`, `length` | | — |
|
|
196
|
+
|
|
197
|
+
#### `selectEdge()` — Select the single best-matching edge from a shape.
|
|
174
198
|
|
|
175
|
-
|
|
199
|
+
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.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
// Chamfer one specific edge near a known point
|
|
203
|
+
const bottomEdge = selectEdge(part, { near: [25, 0, 0], atZ: 0 });
|
|
204
|
+
result = chamfer(result, 1.5, bottomEdge);
|
|
205
|
+
```
|
|
176
206
|
|
|
177
207
|
```ts
|
|
178
208
|
selectEdge(shape: Shape, query?: EdgeQuery): EdgeSegment
|
|
179
209
|
```
|
|
180
210
|
|
|
181
|
-
|
|
211
|
+
#### `coalesceEdges()` — Merge collinear edge segments into longer logical edges.
|
|
182
212
|
|
|
183
|
-
|
|
213
|
+
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.
|
|
214
|
+
|
|
215
|
+
The `tolerance` controls the maximum perpendicular distance from collinearity before two segments are considered non-collinear. Default: `0.01`.
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const topEdges = selectEdges(part, { atZ: 20 });
|
|
219
|
+
for (const edge of coalesceEdges(topEdges)) {
|
|
220
|
+
result = fillet(result, 2, edge);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
184
223
|
|
|
185
224
|
```ts
|
|
186
225
|
coalesceEdges(segments: EdgeSegment[], tolerance?: number): EdgeSegment[]
|
|
187
226
|
```
|
|
188
227
|
|
|
189
|
-
|
|
228
|
+
#### `filletCorners()` — Create a polygon from points with specific corners rounded to arc fillets.
|
|
190
229
|
|
|
191
|
-
|
|
230
|
+
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.
|
|
192
231
|
|
|
193
|
-
|
|
194
|
-
arcBridgeBetweenRects(rectA: RectAreaArg, rectB: RectAreaArg, segments?: number): Shape
|
|
195
|
-
```
|
|
232
|
+
Constraints:
|
|
196
233
|
|
|
197
|
-
|
|
234
|
+
- Collinear corners cannot be filleted (throws an error)
|
|
235
|
+
- Two neighboring fillets whose tangent lengths overlap the same edge will throw
|
|
236
|
+
- Radius must be positive and small enough to fit within the adjacent edge lengths
|
|
198
237
|
|
|
199
|
-
|
|
238
|
+
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.
|
|
200
239
|
|
|
201
240
|
```ts
|
|
202
|
-
|
|
241
|
+
const roof = filletCorners(roofPoints, [
|
|
242
|
+
{ index: 3, radius: 19 },
|
|
243
|
+
{ index: 4, radius: 19 },
|
|
244
|
+
{ index: 5, radius: 19 },
|
|
245
|
+
]);
|
|
203
246
|
```
|
|
204
247
|
|
|
205
|
-
Round a named edge of a shape with a circular fillet of the given radius. Requires a compile-covered target.
|
|
206
|
-
|
|
207
|
-
<details><summary><code>EdgeRef</code></summary>
|
|
208
|
-
|
|
209
248
|
```ts
|
|
210
|
-
|
|
211
|
-
name: EdgeName;
|
|
212
|
-
/** Compiler-owned edge query when available. */
|
|
213
|
-
query?: EdgeQueryRef;
|
|
214
|
-
}
|
|
249
|
+
filletCorners(points: PointInput[], corners: FilletCornerSpec[]): Sketch
|
|
215
250
|
```
|
|
216
251
|
|
|
217
|
-
|
|
252
|
+
`FilletCornerSpec`: `{ index: number, radius: number, segments?: number }`
|
|
218
253
|
|
|
219
|
-
#### `
|
|
254
|
+
#### `circularLayout()` — Compute evenly-spaced positions around a circle.
|
|
220
255
|
|
|
221
|
-
|
|
222
|
-
chamferEdge(shape: Shape, edge: EdgeRef, size: number, quadrant?: [ number, number ]): Shape
|
|
223
|
-
```
|
|
256
|
+
Eliminates the most common trig pattern in CAD scripts:
|
|
224
257
|
|
|
225
|
-
|
|
258
|
+
```js
|
|
259
|
+
// Before — manual trig
|
|
260
|
+
for (let i = 0; i < 12; i++) {
|
|
261
|
+
const angle = i * 30 * Math.PI / 180;
|
|
262
|
+
markers.push(marker.translate(r * Math.cos(angle), r * Math.sin(angle), 0));
|
|
263
|
+
}
|
|
226
264
|
|
|
227
|
-
|
|
265
|
+
// After — declarative
|
|
266
|
+
for (const {x, y} of circularLayout(12, r)) {
|
|
267
|
+
markers.push(marker.translate(x, y, 0));
|
|
268
|
+
}
|
|
269
|
+
```
|
|
228
270
|
|
|
229
271
|
```ts
|
|
230
|
-
|
|
272
|
+
circularLayout(count: number, radius: number, options?: CircularLayoutOptions): LayoutPoint[]
|
|
231
273
|
```
|
|
232
274
|
|
|
233
|
-
|
|
275
|
+
**`CircularLayoutOptions`**
|
|
276
|
+
- `startDeg?: number` — Angle of the first element in degrees (default: 0 = +X axis).
|
|
277
|
+
- `centerX?: number` — Center X coordinate (default: 0).
|
|
278
|
+
- `centerY?: number` — Center Y coordinate (default: 0).
|
|
279
|
+
|
|
280
|
+
`LayoutPoint`: `{ x: number, y: number }`
|
|
281
|
+
|
|
282
|
+
#### `polygonVertices()` — Compute the vertex positions of a regular polygon.
|
|
283
|
+
|
|
284
|
+
Default orientation places the first vertex at the top (90 degrees), matching the convention used by [`ngon()`](/docs/sketch#ngon).
|
|
285
|
+
|
|
286
|
+
Eliminates manual Math.sqrt(3) for triangles, pentagon vertex math, etc:
|
|
234
287
|
|
|
235
|
-
|
|
288
|
+
```js
|
|
289
|
+
// Before — manual equilateral triangle
|
|
290
|
+
const v1 = [center.x - r/2, center.y + r * Math.sqrt(3)/2];
|
|
291
|
+
const v2 = [center.x - r/2, center.y - r * Math.sqrt(3)/2];
|
|
292
|
+
const v3 = [center.x + r, center.y];
|
|
293
|
+
|
|
294
|
+
// After — declarative
|
|
295
|
+
const [v1, v2, v3] = polygonVertices(3, r);
|
|
296
|
+
```
|
|
236
297
|
|
|
237
298
|
```ts
|
|
238
|
-
|
|
239
|
-
index: number;
|
|
240
|
-
radius: number;
|
|
241
|
-
segments?: number;
|
|
242
|
-
}
|
|
299
|
+
polygonVertices(sides: number, radius: number, options?: PolygonVerticesOptions): LayoutPoint[]
|
|
243
300
|
```
|
|
244
301
|
|
|
245
|
-
|
|
302
|
+
**`PolygonVerticesOptions`**
|
|
303
|
+
- `startDeg?: number` — Angle of the first vertex in degrees (default: 90 = top).
|
|
304
|
+
- `centerX?: number` — Center X coordinate (default: 0).
|
|
305
|
+
- `centerY?: number` — Center Y coordinate (default: 0).
|
|
306
|
+
|
|
307
|
+
#### `linearPattern()` — Repeat a shape in a linear pattern along a direction vector and union the copies.
|
|
308
|
+
|
|
309
|
+
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.
|
|
246
310
|
|
|
247
|
-
|
|
311
|
+
```ts
|
|
312
|
+
// 5 cylinders, 20mm apart along X
|
|
313
|
+
linearPattern(cylinder(10, 3), 5, 20, 0)
|
|
314
|
+
```
|
|
248
315
|
|
|
249
316
|
```ts
|
|
250
317
|
linearPattern(shape: Shape, count: number, dx: number, dy: number, dz?: number): Shape
|
|
251
318
|
```
|
|
252
319
|
|
|
253
|
-
Repeat a shape in a
|
|
320
|
+
#### `circularPattern()` — Repeat a shape in a circular pattern around an axis and union the copies.
|
|
321
|
+
|
|
322
|
+
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.
|
|
254
323
|
|
|
255
|
-
|
|
324
|
+
Two calling conventions:
|
|
325
|
+
|
|
326
|
+
- **Simple** (Z axis): `circularPattern(shape, 6)` or `circularPattern(shape, 6, centerX, centerY)`
|
|
327
|
+
- **Advanced** (arbitrary axis): `circularPattern(shape, 6, { axis, origin })`
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
// 8 holes evenly spaced around origin
|
|
331
|
+
circularPattern(cylinder(12, 4).translate(30, 0, -1), 8)
|
|
332
|
+
|
|
333
|
+
// Circular pattern around X axis
|
|
334
|
+
circularPattern(myFeature, 4, { axis: [1, 0, 0], origin: [0, 0, 50] })
|
|
335
|
+
```
|
|
256
336
|
|
|
257
337
|
```ts
|
|
258
338
|
circularPattern(shape: Shape, count: number, centerXOrOpts?: number | CircularPatternOptions, centerY?: number): Shape
|
|
259
339
|
```
|
|
260
340
|
|
|
261
|
-
|
|
341
|
+
**`CircularPatternOptions`**
|
|
342
|
+
- `centerX?: number` — Center X of the rotation (default: 0). Used when axis is Z (legacy mode).
|
|
343
|
+
- `centerY?: number` — Center Y of the rotation (default: 0). Used when axis is Z (legacy mode).
|
|
262
344
|
|
|
263
|
-
|
|
345
|
+
#### `linearPattern2d()` — Repeat a 2D sketch in a linear pattern and union the copies.
|
|
264
346
|
|
|
265
347
|
```ts
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
348
|
+
linearPattern2d(sketch: Sketch, count: number, dx: number, dy?: number): Sketch
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
#### `circularPattern2d()` — Repeat a 2D sketch in a circular pattern around a center point and union the copies.
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
circularPattern2d(sketch: Sketch, count: number, centerXOrOpts?: number | { centerX?: number; centerY?: number; startDeg?: number; }, centerY?: number): Sketch
|
|
272
355
|
```
|
|
273
356
|
|
|
274
|
-
|
|
357
|
+
#### `mirrorCopy()` — Mirror a shape across a plane and union the mirror with the original.
|
|
275
358
|
|
|
276
|
-
|
|
359
|
+
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.
|
|
277
360
|
|
|
278
361
|
```ts
|
|
279
|
-
|
|
362
|
+
// Mirror across the YZ plane (X=0)
|
|
363
|
+
mirrorCopy(box(50, 30, 10), [1, 0, 0])
|
|
280
364
|
```
|
|
281
365
|
|
|
282
|
-
|
|
366
|
+
```ts
|
|
367
|
+
mirrorCopy(shape: Shape, normal: [ number, number, number ]): Shape
|
|
368
|
+
```
|
|
283
369
|
|
|
284
370
|
### Imports & Composition
|
|
285
371
|
|
|
286
|
-
Import
|
|
372
|
+
#### `require()` — Import a module with optional ForgeCAD parameter overrides. Returns the module's exports.
|
|
287
373
|
|
|
288
|
-
|
|
374
|
+
When importing a `.forge.js` file, the return value is what the script returns. If the script returns a metadata object (e.g. `{ shape: myShape, bolts: {...} }`), the caller receives the full object — renderable values and metadata together.
|
|
289
375
|
|
|
290
|
-
|
|
291
|
-
|
|
376
|
+
**Parameter scoping:** Parameters declared in required files are automatically namespaced with a `"filename#N / "` prefix (e.g. `"bracket.forge.js#1 / Width"`). This prevents collisions when multiple files declare same-named params. Each file's params appear as separate sliders.
|
|
377
|
+
|
|
378
|
+
**Parameter overrides:** When passing overrides, use the bare param name (not the scoped name). Overrides are type-checked — unrecognized keys throw an error with typo suggestions.
|
|
379
|
+
|
|
380
|
+
**Multi-file assembly pattern** — pass cross-cutting design values from the assembly to parts:
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
// assembly.forge.js — owns cross-cutting params, passes to parts
|
|
384
|
+
const wall = param("Wall", 3);
|
|
385
|
+
const baseH = param("Base Height", 20);
|
|
386
|
+
|
|
387
|
+
const mount = require('./motor-mount.forge.js', { Wall: wall });
|
|
388
|
+
const base = require('./base-body.forge.js', { Wall: wall, Height: baseH });
|
|
292
389
|
```
|
|
293
390
|
|
|
294
|
-
|
|
391
|
+
**Metadata pattern** — parts publish interface data alongside geometry:
|
|
295
392
|
|
|
296
|
-
|
|
393
|
+
```js
|
|
394
|
+
// motor-mount.forge.js
|
|
395
|
+
return { shape: mount, bolts: { dia: 5.3, pos: holePositions } };
|
|
396
|
+
|
|
397
|
+
// base-body.forge.js
|
|
398
|
+
const mount = require('./motor-mount.forge.js');
|
|
399
|
+
mount.bolts.pos // access the metadata
|
|
400
|
+
mount.shape // access the geometry
|
|
401
|
+
```
|
|
297
402
|
|
|
298
403
|
```ts
|
|
299
|
-
|
|
404
|
+
require(path: string, paramOverrides?: Record<string, number | string>): any
|
|
300
405
|
```
|
|
301
406
|
|
|
302
|
-
Parse an SVG file and return it as a Sketch with options for region filtering, scaling, and simplification.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
```ts
|
|
307
|
-
interface SvgImportOptions {
|
|
308
|
-
/** Which geometry channels to include: - `auto`: prefer fills; if no fill geometry exists, fall back to strokes - `fill`: import only filled regions - `stroke`: import only stroke geometry - `fill-and-stroke`: include both */
|
|
309
|
-
include?: "auto" | "fill" | "stroke" | "fill-and-stroke";
|
|
310
|
-
/** Keep all disconnected regions, or only the largest. */
|
|
311
|
-
regionSelection?: "all" | "largest";
|
|
312
|
-
/** Keep at most this many regions (largest-first). */
|
|
313
|
-
maxRegions?: number;
|
|
314
|
-
/** Drop regions below this absolute area threshold. */
|
|
315
|
-
minRegionArea?: number;
|
|
316
|
-
/** Drop regions below this ratio of largest-region area. */
|
|
317
|
-
minRegionAreaRatio?: number;
|
|
318
|
-
/** Curve flattening tolerance in SVG user units. Smaller = more segments, higher fidelity. */
|
|
319
|
-
flattenTolerance?: number;
|
|
320
|
-
/** Minimum segment count for arc discretization. */
|
|
321
|
-
arcSegments?: number;
|
|
322
|
-
/** Global scale applied after SVG parsing. */
|
|
323
|
-
scale?: number;
|
|
324
|
-
/** Maximum imported sketch width. If exceeded, geometry is uniformly downscaled to fit. */
|
|
325
|
-
maxWidth?: number;
|
|
326
|
-
/** Maximum imported sketch height. If exceeded, geometry is uniformly downscaled to fit. */
|
|
327
|
-
maxHeight?: number;
|
|
328
|
-
/** Recenter imported geometry so its 2D bounds center is at CAD origin. */
|
|
329
|
-
centerOnOrigin?: boolean;
|
|
330
|
-
/** Simplification tolerance for final sketch cleanup. */
|
|
331
|
-
simplify?: number;
|
|
332
|
-
/** Flip SVG Y-down coordinates to CAD Y-up. Enabled by default. */
|
|
333
|
-
invertY?: boolean;
|
|
334
|
-
}
|
|
407
|
+
#### `importSvgSketch()` — Parse an SVG file and return it as a Sketch with options for region filtering, scaling, and simplification.
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
importSvgSketch(fileName: string, options?: SvgImportOptions): Sketch
|
|
335
411
|
```
|
|
336
412
|
|
|
337
|
-
|
|
413
|
+
**`SvgImportOptions`**
|
|
338
414
|
|
|
339
|
-
|
|
415
|
+
| Option | Type | Description |
|
|
416
|
+
|--------|------|-------------|
|
|
417
|
+
| `include?` | `"auto" | "fill" | "stroke" | "fill-and-stroke"` | Which geometry channels to include: - `auto`: prefer fills; if no fill geometry exists, fall back to strokes - `fill`: import only filled regions - `stroke`: import only stroke geometry - `fill-and-stroke`: include both |
|
|
418
|
+
| `regionSelection?` | `"all" | "largest"` | Keep all disconnected regions, or only the largest. |
|
|
419
|
+
| `maxRegions?` | `number` | Keep at most this many regions (largest-first). |
|
|
420
|
+
| `minRegionArea?` | `number` | Drop regions below this absolute area threshold. |
|
|
421
|
+
| `minRegionAreaRatio?` | `number` | Drop regions below this ratio of largest-region area. |
|
|
422
|
+
| `flattenTolerance?` | `number` | Curve flattening tolerance in SVG user units. Smaller = more segments, higher fidelity. |
|
|
423
|
+
| `arcSegments?` | `number` | Minimum segment count for arc discretization. |
|
|
424
|
+
| `scale?` | `number` | Global scale applied after SVG parsing. |
|
|
425
|
+
| `maxWidth?` | `number` | Maximum imported sketch width. If exceeded, geometry is uniformly downscaled to fit. |
|
|
426
|
+
| `maxHeight?` | `number` | Maximum imported sketch height. If exceeded, geometry is uniformly downscaled to fit. |
|
|
427
|
+
| `centerOnOrigin?` | `boolean` | Recenter imported geometry so its 2D bounds center is at CAD origin. |
|
|
428
|
+
| `simplify?` | `number` | Simplification tolerance for final sketch cleanup. |
|
|
429
|
+
| `invertY?` | `boolean` | Flip SVG Y-down coordinates to CAD Y-up. Enabled by default. |
|
|
340
430
|
|
|
341
|
-
|
|
431
|
+
#### `importMesh()` — Import an external mesh file (STL, OBJ, 3MF) as a Shape.
|
|
342
432
|
|
|
343
|
-
|
|
433
|
+
```ts
|
|
434
|
+
importMesh(fileName: string, options?: { scale?: number; center?: boolean; }): Shape
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
#### `importStep()` — Import a STEP file (.step, .stp) as an exact OCCT-backed Shape. Preserves NURBS curves, B-spline surfaces, and exact topology. Requires `setActiveBackend('occt')`.
|
|
344
438
|
|
|
345
439
|
```ts
|
|
346
|
-
|
|
440
|
+
importStep(fileName: string): Shape
|
|
347
441
|
```
|
|
348
442
|
|
|
349
|
-
|
|
443
|
+
### Parameters
|
|
350
444
|
|
|
351
|
-
#### `
|
|
445
|
+
#### `Param.number()` — Declare a numeric parameter that renders as a slider in the UI.
|
|
446
|
+
|
|
447
|
+
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.
|
|
448
|
+
|
|
449
|
+
Default range rules when options are omitted:
|
|
450
|
+
|
|
451
|
+
- `min` defaults to `0`
|
|
452
|
+
- `max` defaults to `defaultValue * 4`
|
|
453
|
+
- `step` is auto-calculated: `1` for integer params, `0.1` for ranges ≤ 100, `1` for larger ranges
|
|
454
|
+
|
|
455
|
+
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`).
|
|
352
456
|
|
|
353
457
|
```ts
|
|
354
|
-
|
|
458
|
+
const width = Param.number("Width", 50);
|
|
459
|
+
const angle = Param.number("Angle", 45, { min: 0, max: 180, unit: "°" });
|
|
460
|
+
const sides = Param.number("Sides", 6, { min: 3, max: 12, integer: true });
|
|
355
461
|
```
|
|
356
462
|
|
|
357
|
-
|
|
463
|
+
**Parameter overrides** — key must match `name` exactly:
|
|
358
464
|
|
|
359
|
-
|
|
465
|
+
```ts
|
|
466
|
+
// Via require()
|
|
467
|
+
const bracket = require("./bracket.forge.js", { Width: 80 });
|
|
360
468
|
|
|
361
|
-
|
|
469
|
+
// Via CLI
|
|
470
|
+
// forgecad run model.forge.js --param "Wall Thickness=3"
|
|
471
|
+
```
|
|
362
472
|
|
|
363
|
-
|
|
473
|
+
Also available as the shorthand alias `param()`.
|
|
364
474
|
|
|
365
475
|
```ts
|
|
366
|
-
|
|
476
|
+
Param.number(name: string, defaultValue: number, opts?: { min?: number; max?: number; step?: number; unit?: string; integer?: boolean; reverse?: boolean; }): number
|
|
367
477
|
```
|
|
368
478
|
|
|
369
|
-
|
|
479
|
+
#### `Param.string()` — Declare a string parameter that renders as a text input in the UI.
|
|
370
480
|
|
|
371
|
-
|
|
481
|
+
String parameters let users type free-form text — labels, names, inscriptions, file paths, etc. The `name` string is the override key.
|
|
372
482
|
|
|
373
|
-
|
|
483
|
+
```ts
|
|
484
|
+
const label = Param.string("Label", "Hello World");
|
|
485
|
+
const name = Param.string("Name", "Part-001", { maxLength: 20 });
|
|
486
|
+
```
|
|
374
487
|
|
|
375
|
-
|
|
488
|
+
Override via import:
|
|
376
489
|
|
|
377
490
|
```ts
|
|
378
|
-
|
|
491
|
+
const tag = require("./tag.forge.js", { Label: "Custom Text" });
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Only available as `Param.string()` — no standalone alias.
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
Param.string(name: string, defaultValue: string, opts?: { maxLength?: number; }): string
|
|
379
498
|
```
|
|
380
499
|
|
|
381
|
-
|
|
500
|
+
#### `Param.bool()` — Declare a boolean parameter that renders as a checkbox in the UI.
|
|
382
501
|
|
|
383
|
-
|
|
502
|
+
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.
|
|
384
503
|
|
|
385
504
|
```ts
|
|
386
|
-
|
|
505
|
+
const showHoles = Param.bool("Show Holes", true);
|
|
506
|
+
if (showHoles) return difference(plate, cylinder(10, 5).translate(50, 30, 0));
|
|
507
|
+
return plate;
|
|
387
508
|
```
|
|
388
509
|
|
|
389
|
-
|
|
510
|
+
Override via import:
|
|
390
511
|
|
|
391
|
-
|
|
512
|
+
```ts
|
|
513
|
+
const pan = require("./pan.forge.js", { "Show Lid": 0 });
|
|
514
|
+
```
|
|
392
515
|
|
|
393
|
-
|
|
516
|
+
Also available as the shorthand alias `boolParam()`.
|
|
394
517
|
|
|
395
518
|
```ts
|
|
396
|
-
|
|
519
|
+
Param.bool(name: string, defaultValue: boolean): boolean
|
|
397
520
|
```
|
|
398
521
|
|
|
399
|
-
|
|
522
|
+
#### `Param.choice()` — Declare a choice parameter that renders as a dropdown in the UI.
|
|
523
|
+
|
|
524
|
+
`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.
|
|
400
525
|
|
|
401
|
-
|
|
526
|
+
Overrides may be passed as the choice label string (preferred) or as a numeric index. The `name` string is the override key.
|
|
402
527
|
|
|
403
528
|
```ts
|
|
404
|
-
|
|
529
|
+
const panStyle = Param.choice("Pan Style", "frying-pan", ["frying-pan", "saute-pan", "wok"]);
|
|
530
|
+
if (panStyle === "wok") return buildWok();
|
|
405
531
|
```
|
|
406
532
|
|
|
407
|
-
|
|
533
|
+
Override via import:
|
|
408
534
|
|
|
409
535
|
```ts
|
|
410
|
-
|
|
411
|
-
kind?: JointType;
|
|
412
|
-
min?: number;
|
|
413
|
-
max?: number;
|
|
414
|
-
}
|
|
536
|
+
const pan = require("./pan.forge.js", { "Pan Style": "wok" });
|
|
415
537
|
```
|
|
416
538
|
|
|
417
|
-
|
|
539
|
+
Override via CLI:
|
|
418
540
|
|
|
419
|
-
|
|
541
|
+
```bash
|
|
542
|
+
forgecad run model.forge.js --param "Pan Style=wok"
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Also available as the shorthand alias `choiceParam()`.
|
|
420
546
|
|
|
421
547
|
```ts
|
|
422
|
-
|
|
423
|
-
origin: Vec3;
|
|
424
|
-
axis: Vec3;
|
|
425
|
-
up: Vec3;
|
|
426
|
-
extent?: number;
|
|
427
|
-
kind?: JointType;
|
|
428
|
-
min?: number;
|
|
429
|
-
max?: number;
|
|
430
|
-
connectorType?: string;
|
|
431
|
-
gender?: ConnectorGender;
|
|
432
|
-
measurements?: Record<string, number | string>;
|
|
433
|
-
}
|
|
548
|
+
Param.choice(name: string, defaultValue: string, choices: string[]): string
|
|
434
549
|
```
|
|
435
550
|
|
|
436
|
-
|
|
551
|
+
#### `Param.list()` — Declare a list parameter — an array of struct items with per-field UI controls.
|
|
437
552
|
|
|
438
|
-
|
|
553
|
+
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.
|
|
554
|
+
|
|
555
|
+
Field types:
|
|
556
|
+
|
|
557
|
+
- Boolean fields (`boolean: true` in field defs) return as `boolean`
|
|
558
|
+
- Choice fields (`choices: [...]` in field defs) return as `string`
|
|
559
|
+
- All other fields return as `number`
|
|
439
560
|
|
|
440
561
|
```ts
|
|
441
|
-
|
|
562
|
+
Param.list<T extends Record<string, number | boolean | string>>(name: string, defaultItems: T[], opts: { ... }): T[]
|
|
442
563
|
```
|
|
443
564
|
|
|
565
|
+
`ListParamFieldDef`: `{ min?: number, max?: number, step?: number, unit?: string, integer?: boolean, boolean?: boolean, choices?: string[] }`
|
|
566
|
+
|
|
567
|
+
### Grouping & Local Coordinates
|
|
568
|
+
|
|
569
|
+
#### `group()` — Group multiple shapes/sketches for joint transforms without merging into a single mesh.
|
|
570
|
+
|
|
571
|
+
Unlike union(), colors and individual identities are preserved. Children can be plain shapes, named descriptors ({ name, shape/sketch/group }), or nested groups. The returned ShapeGroup supports all Shape transforms (translate, rotate, etc.).
|
|
572
|
+
|
|
573
|
+
**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.
|
|
444
574
|
|
|
445
|
-
|
|
575
|
+
```js
|
|
576
|
+
// BAD — every sub-part repeats the parent's global offset
|
|
577
|
+
const unitX = 0, unitY = -18, unitZ = 70;
|
|
578
|
+
const body = roundedBox(100, 20, 32, 4).translate(unitX, unitY, unitZ);
|
|
579
|
+
const panel = box(98, 2, 18).translate(unitX, unitY - 12, unitZ + 4);
|
|
580
|
+
const louver = box(88, 2, 6).translate(unitX, unitY - 14, unitZ - 11);
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
// 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);
|
|
446
584
|
|
|
447
585
|
```ts
|
|
448
|
-
|
|
449
|
-
connectorType: string;
|
|
450
|
-
gender: ConnectorGender$1;
|
|
451
|
-
measurements?: Record<string, number | string>;
|
|
452
|
-
}
|
|
586
|
+
group(...items: GroupInput[]): ShapeGroup
|
|
453
587
|
```
|
|
454
588
|
|
|
455
|
-
|
|
589
|
+
### Section & Projection
|
|
456
590
|
|
|
457
|
-
#### `
|
|
591
|
+
#### `intersectWithPlane()` — Cross-section: slice a 3D shape with a plane and return the intersection as a 2D Sketch.
|
|
458
592
|
|
|
459
593
|
```ts
|
|
460
|
-
|
|
594
|
+
intersectWithPlane(shape: Shape, plane: PlaneSpec): Sketch
|
|
461
595
|
```
|
|
462
596
|
|
|
463
|
-
|
|
597
|
+
#### `faceProfile()` — Extract the boundary profile of a named face as a 2D sketch.
|
|
464
598
|
|
|
465
|
-
|
|
599
|
+
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.
|
|
466
600
|
|
|
467
601
|
```ts
|
|
468
|
-
|
|
602
|
+
faceProfile(shape: Shape, face: FaceSelector): Sketch
|
|
469
603
|
```
|
|
470
604
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
#### `chamfer()`
|
|
605
|
+
#### `projectToPlane()` — Orthographically project a 3D shape onto a plane and return the silhouette as a 2D Sketch.
|
|
474
606
|
|
|
475
607
|
```ts
|
|
476
|
-
|
|
608
|
+
projectToPlane(shape: Shape, plane: PlaneSpec): Sketch
|
|
477
609
|
```
|
|
478
610
|
|
|
479
|
-
|
|
611
|
+
### Transforms
|
|
480
612
|
|
|
481
|
-
#### `
|
|
613
|
+
#### `composeChain()` — Compose transforms in chain order. Equivalent to Transform.identity().mul(a).mul(b).mul(c)...
|
|
482
614
|
|
|
483
615
|
```ts
|
|
484
|
-
|
|
616
|
+
composeChain(...steps: TransformInput[]): Transform
|
|
485
617
|
```
|
|
486
618
|
|
|
487
|
-
|
|
619
|
+
### Verification
|
|
620
|
+
|
|
621
|
+
#### `spec()` — Create a named, reusable bundle of verification checks.
|
|
622
|
+
|
|
623
|
+
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.
|
|
624
|
+
|
|
625
|
+
Specs can be defined in separate `.forge.js` files and imported via `require()` to share them across models.
|
|
488
626
|
|
|
489
|
-
|
|
627
|
+
`spec.check()` returns a `SpecResult` — you can inspect it programmatically or ignore the return value and let the Checks panel show results.
|
|
490
628
|
|
|
491
629
|
```ts
|
|
492
|
-
|
|
493
|
-
|
|
630
|
+
const printable = spec("Fits printer bed", (shape) => {
|
|
631
|
+
verify.notEmpty("Has geometry", shape);
|
|
632
|
+
const bb = shape.boundingBox();
|
|
633
|
+
verify.lessThan("Width < 220mm", bb.max[0] - bb.min[0], 220);
|
|
634
|
+
verify.lessThan("Depth < 220mm", bb.max[1] - bb.min[1], 220);
|
|
635
|
+
verify.lessThan("Height < 250mm", bb.max[2] - bb.min[2], 250);
|
|
636
|
+
});
|
|
494
637
|
|
|
495
|
-
|
|
638
|
+
// Reuse on multiple shapes
|
|
639
|
+
printable.check(bracket);
|
|
640
|
+
printable.check(standoff);
|
|
496
641
|
|
|
497
|
-
|
|
642
|
+
// Check relationships between parts
|
|
643
|
+
const fitSpec = spec("Assembly fit", (partA, partB) => {
|
|
644
|
+
verify.notColliding("No interference", partA, partB, 10);
|
|
645
|
+
});
|
|
646
|
+
fitSpec.check(bracket, standoff);
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
**Spec-first workflow:** Write specs before building geometry. Checks go from red to green as you build — effectively TDD for CAD.
|
|
498
650
|
|
|
499
651
|
```ts
|
|
500
|
-
|
|
652
|
+
spec(name: string, checkFn: (...args: any[]) => void): Spec
|
|
501
653
|
```
|
|
502
654
|
|
|
503
|
-
|
|
655
|
+
**`Spec`**
|
|
656
|
+
- `name: string` — The display name of this spec
|
|
657
|
+
|
|
658
|
+
---
|
|
504
659
|
|
|
505
|
-
|
|
660
|
+
## Classes
|
|
661
|
+
|
|
662
|
+
### `Shape`
|
|
663
|
+
|
|
664
|
+
Core 3D solid shape. All operations are immutable and return new shapes.
|
|
665
|
+
|
|
666
|
+
Supports transforms (translate, rotate, scale, mirror, transform, rotateAround, pointAlong), booleans (add, subtract, intersect), cutting (split, splitByPlane, trimByPlane), shelling, anchor positioning (attachTo, onFace), placement references, and queries (volume, surfaceArea, boundingBox, isEmpty, numTri, geometryInfo).
|
|
667
|
+
|
|
668
|
+
**Properties:**
|
|
669
|
+
|
|
670
|
+
| Property | Type | Description |
|
|
671
|
+
|----------|------|-------------|
|
|
672
|
+
| `materialProps` | `ShapeMaterialProps | undefined` | — |
|
|
673
|
+
|
|
674
|
+
**Appearance**
|
|
675
|
+
|
|
676
|
+
#### `color()` — Set the color of this shape (hex string, e.g. "#ff0000"). Returns a new Shape with the color applied.
|
|
506
677
|
|
|
507
678
|
```ts
|
|
508
|
-
|
|
679
|
+
color(value: string | undefined): Shape
|
|
509
680
|
```
|
|
510
681
|
|
|
511
|
-
|
|
682
|
+
#### `material()` — Set PBR material properties for this shape's visual appearance.
|
|
683
|
+
|
|
684
|
+
Returns a new Shape with the specified material properties merged on top of any previously set properties. All properties are optional — omitted keys retain their current value. Material properties survive transforms and boolean operations.
|
|
512
685
|
|
|
513
|
-
|
|
686
|
+
Use `.color()` to set the base diffuse color; `.material()` controls how that color behaves under light (metalness, roughness, clearcoat) and can add emissive glow independent of lighting. Emissive glow pairs naturally with the `postProcessing.bloom` effect in [`scene()`](/docs/viewport#scene).
|
|
687
|
+
|
|
688
|
+
```js
|
|
689
|
+
box(50, 50, 50).material({ metalness: 0.9, roughness: 0.1 }); // polished metal
|
|
690
|
+
sphere(30).material({ emissive: '#ff6b35', emissiveIntensity: 2 }); // glowing
|
|
691
|
+
cylinder(40, 20).material({ opacity: 0.4, clearcoat: 1.0, clearcoatRoughness: 0.02 }); // ice
|
|
692
|
+
|
|
693
|
+
// Chainable with other shape methods
|
|
694
|
+
box(100, 100, 10).color('#gold').material({ metalness: 0.95, roughness: 0.05 }).translate(0, 0, 50);
|
|
695
|
+
```
|
|
514
696
|
|
|
515
697
|
```ts
|
|
516
|
-
|
|
517
|
-
min?: number;
|
|
518
|
-
max?: number;
|
|
519
|
-
step?: number;
|
|
520
|
-
unit?: string;
|
|
521
|
-
integer?: boolean;
|
|
522
|
-
boolean?: boolean;
|
|
523
|
-
choices?: string[];
|
|
524
|
-
}
|
|
698
|
+
material(props: ShapeMaterialProps): Shape
|
|
525
699
|
```
|
|
526
700
|
|
|
527
|
-
|
|
701
|
+
**Face Topology**
|
|
702
|
+
|
|
703
|
+
#### `face()` — Resolve a face by user-authored label or compiler-owned name. Returns a `FaceRef` that can be passed to `.onFace()`, `projectToPlane()`, or used directly in placement.
|
|
704
|
+
|
|
705
|
+
`.face(name)` is a pure label lookup — it finds faces by user-authored labels, not by geometric queries. Labels are born in sketches via `.label()` / `.labelEdges()` and grow into face names through extrude, loft, revolve, and sweep. They are stable references that travel with the geometry.
|
|
528
706
|
|
|
529
|
-
|
|
707
|
+
Labels must be unique within a shape. Use `.prefixLabels()` before combining shapes with `union()` / `difference()` to avoid collisions. Collision detection throws a clear error with a fix suggestion.
|
|
708
|
+
|
|
709
|
+
For compile-covered shapes (extrude, loft, etc.) the lookup resolves via the shape's compile plan. As a fallback, planar-faced mesh shapes (e.g. results of boolean ops) are resolved via coplanar triangle clustering.
|
|
530
710
|
|
|
531
711
|
```ts
|
|
532
|
-
|
|
533
|
-
|
|
712
|
+
// Edge labels become side face names after extrude
|
|
713
|
+
const profile = path()
|
|
714
|
+
.moveTo(0, 0)
|
|
715
|
+
.lineTo(100, 0).label('floor')
|
|
716
|
+
.lineTo(100, 50).label('wall')
|
|
717
|
+
.lineTo(0, 50).label('ceiling')
|
|
718
|
+
.closeLabel('left-wall');
|
|
719
|
+
const room = profile.extrude(30, { labels: { start: 'base', end: 'top' } });
|
|
720
|
+
room.face('floor'); // side face from the labeled edge
|
|
721
|
+
room.face('base'); // base cap (user-specified)
|
|
722
|
+
|
|
723
|
+
// .labelEdges() shorthand for sequential edge labeling
|
|
724
|
+
const plate = rect(100, 50).labelEdges('south', 'east', 'north', 'west');
|
|
725
|
+
const solid = plate.extrude(20, { labels: { start: 'bottom', end: 'top' } });
|
|
726
|
+
solid.face('south'); // side face
|
|
534
727
|
|
|
535
|
-
|
|
728
|
+
// Prefix before combining to avoid collisions
|
|
729
|
+
const left = wing.prefixLabels('l/');
|
|
730
|
+
const right = wing.mirror([1, 0, 0]).prefixLabels('r/');
|
|
731
|
+
const full = union(left, right);
|
|
732
|
+
full.face('l/upper'); // left wing upper surface
|
|
733
|
+
```
|
|
536
734
|
|
|
537
735
|
```ts
|
|
538
|
-
|
|
736
|
+
face(selector: FaceSelector): FaceRef
|
|
539
737
|
```
|
|
540
738
|
|
|
541
|
-
#### `
|
|
739
|
+
#### `faces()` — Return all faces matching a query, or all mesh-detected faces when no query is given.
|
|
542
740
|
|
|
543
741
|
```ts
|
|
544
|
-
|
|
742
|
+
faces(query?: FaceQuery): FaceRef[]
|
|
545
743
|
```
|
|
546
744
|
|
|
547
|
-
#### `
|
|
745
|
+
#### `faceNames()` — List defended semantic face names currently available on this shape, including user labels from `labelFaces()`.
|
|
548
746
|
|
|
549
747
|
```ts
|
|
550
|
-
|
|
748
|
+
faceNames(): string[]
|
|
551
749
|
```
|
|
552
750
|
|
|
553
|
-
#### `
|
|
751
|
+
#### `labelFaces()` — Assign user-chosen labels to faces identified by their canonical position keys.
|
|
752
|
+
|
|
753
|
+
Primitives (`box`, `cylinder`) and extrusions have internal canonical face positions (`top`, `bottom`, `side`, `side-left`, etc.) but these are **not** labels — they are just position selectors. Use `labelFaces()` to give faces meaningful, project-specific names that survive through transforms, booleans, fillets, and chamfers.
|
|
754
|
+
|
|
755
|
+
The mapping keys are canonical position selectors; the values are your labels. Labels are the recommended way to identify faces for topological edge queries (`edgesOf`, `edgesBetween`).
|
|
756
|
+
|
|
757
|
+
```js
|
|
758
|
+
// Full workflow: label → query edges → fillet
|
|
759
|
+
let plate = box(100, 60, 5).labelFaces({ top: 'work-surface', bottom: 'mount-face' })
|
|
760
|
+
plate = fillet(plate, 2, plate.edgesOf('work-surface'))
|
|
761
|
+
|
|
762
|
+
// Cylinder: fillet the rim where cap meets barrel
|
|
763
|
+
let tube = cylinder(30, 10).labelFaces({ top: 'cap', side: 'barrel' })
|
|
764
|
+
tube = fillet(tube, 1, tube.edgesBetween('cap', 'barrel'))
|
|
765
|
+
|
|
766
|
+
// Prefix before combining shapes to avoid label collisions
|
|
767
|
+
const left = plate.prefixLabels('l/')
|
|
768
|
+
const right = plate.mirror([1, 0, 0]).prefixLabels('r/')
|
|
769
|
+
const full = union(left, right)
|
|
770
|
+
full.edgesOf('l/work-surface') // still works
|
|
771
|
+
```
|
|
554
772
|
|
|
555
773
|
```ts
|
|
556
|
-
|
|
774
|
+
labelFaces(mapping: Record<string, string>): Shape
|
|
557
775
|
```
|
|
558
776
|
|
|
559
|
-
#### `
|
|
777
|
+
#### `prefixLabels()` — Prefix all user-authored face labels (both sketch-edge labels and labelFaces labels). Returns a new shape with modified labels.
|
|
560
778
|
|
|
561
779
|
```ts
|
|
562
|
-
|
|
780
|
+
prefixLabels(prefix: string): Shape
|
|
563
781
|
```
|
|
564
782
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
<details><summary><code>LoftAlongSpineOptions</code></summary>
|
|
783
|
+
#### `renameLabel()` — Rename a single face label. Returns a new shape.
|
|
568
784
|
|
|
569
785
|
```ts
|
|
570
|
-
|
|
571
|
-
/** Number of samples when spine is a Curve3D. Default 48. */
|
|
572
|
-
samples?: number;
|
|
573
|
-
/** Marching-grid edge length for level-set meshing. Smaller = finer. */
|
|
574
|
-
edgeLength?: number;
|
|
575
|
-
/** Optional extra bounds padding. */
|
|
576
|
-
boundsPadding?: number;
|
|
577
|
-
/** Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. */
|
|
578
|
-
up?: Vec3$4;
|
|
579
|
-
}
|
|
786
|
+
renameLabel(from: string, to: string): Shape
|
|
580
787
|
```
|
|
581
788
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
#### `variableSweep()`
|
|
789
|
+
#### `dropLabels()` — Remove specific face labels. Returns a new shape.
|
|
585
790
|
|
|
586
791
|
```ts
|
|
587
|
-
|
|
792
|
+
dropLabels(...names: string[]): Shape
|
|
588
793
|
```
|
|
589
794
|
|
|
590
|
-
|
|
795
|
+
#### `dropAllLabels()` — Remove all face labels. Returns a new shape.
|
|
796
|
+
|
|
797
|
+
```ts
|
|
798
|
+
dropAllLabels(): Shape
|
|
799
|
+
```
|
|
591
800
|
|
|
592
|
-
|
|
801
|
+
#### `faceHistory()` — Get the transformation history for a specific face.
|
|
593
802
|
|
|
594
803
|
```ts
|
|
595
|
-
|
|
596
|
-
/** Parameter along the spine (0 = start, 1 = end). */
|
|
597
|
-
t: number;
|
|
598
|
-
/** Cross-section profile at this station. */
|
|
599
|
-
profile: Sketch;
|
|
600
|
-
}
|
|
804
|
+
faceHistory(name: string): FaceTransformationHistory
|
|
601
805
|
```
|
|
602
806
|
|
|
603
|
-
|
|
807
|
+
**Edge Topology**
|
|
604
808
|
|
|
605
|
-
|
|
809
|
+
#### `edge()` — Get a named topology edge. Only available on shapes with tracked topology (from box/cylinder/extrude).
|
|
606
810
|
|
|
607
811
|
```ts
|
|
608
|
-
|
|
609
|
-
/** Number of samples when spine is a Curve3D. Default 48. */
|
|
610
|
-
samples?: number;
|
|
611
|
-
/** Marching-grid edge length for level-set meshing. Smaller = finer. */
|
|
612
|
-
edgeLength?: number;
|
|
613
|
-
/** Optional extra bounds padding. */
|
|
614
|
-
boundsPadding?: number;
|
|
615
|
-
/** Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. */
|
|
616
|
-
up?: Vec3$4;
|
|
617
|
-
}
|
|
812
|
+
edge(name: string): EdgeRef
|
|
618
813
|
```
|
|
619
814
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
#### `loadFont()`
|
|
815
|
+
#### `edgeNames()` — List named topology edge names. Returns empty array if shape has no tracked topology.
|
|
623
816
|
|
|
624
817
|
```ts
|
|
625
|
-
|
|
818
|
+
edgeNames(): string[]
|
|
626
819
|
```
|
|
627
820
|
|
|
628
|
-
|
|
821
|
+
#### `edgesOf()` — Return all boundary edges of a named face.
|
|
822
|
+
|
|
823
|
+
Finds edges where one adjacent mesh face belongs to the target face and the other belongs to a different face. The result is coalesced (tessellation fragments merged) and can be passed directly to `fillet()` or `chamfer()`.
|
|
824
|
+
|
|
825
|
+
This is a topological query — no coordinates, no tolerances, no minimum-length hacks. It works because an edge is the boundary between two faces.
|
|
826
|
+
|
|
827
|
+
```js
|
|
828
|
+
// Fillet all top edges of a mounting plate
|
|
829
|
+
let plate = box(120, 80, 6).labelFaces({ top: 'work-surface' })
|
|
830
|
+
plate = fillet(plate, 3, plate.edgesOf('work-surface'))
|
|
629
831
|
|
|
630
|
-
|
|
832
|
+
// Shelled enclosure — fillet the outer lip
|
|
833
|
+
let body = box(80, 50, 35).labelFaces({ top: 'opening' })
|
|
834
|
+
body = body.shell(2, { openFaces: ['top'] })
|
|
835
|
+
body = fillet(body, 1.5, body.edgesOf('opening'))
|
|
836
|
+
|
|
837
|
+
// Filter: only concave edges (after a boolean subtraction)
|
|
838
|
+
body.edgesOf('top', { concave: true })
|
|
839
|
+
```
|
|
631
840
|
|
|
632
841
|
```ts
|
|
633
|
-
|
|
842
|
+
edgesOf(faceLabel: string, options?: EdgesOfOptions): EdgeSegment[]
|
|
634
843
|
```
|
|
635
844
|
|
|
636
|
-
|
|
845
|
+
#### `edgesBetween()` — Return edges shared between two named faces.
|
|
846
|
+
|
|
847
|
+
An edge is "between" faces A and B when one of its adjacent mesh triangles belongs to A and the other belongs to B. This is the most precise topological edge selection — "fillet the edges where the top meets the wall."
|
|
637
848
|
|
|
638
|
-
|
|
849
|
+
The second argument can be a single face name or an array (edges between A and any of B1, B2, ...).
|
|
850
|
+
|
|
851
|
+
```js
|
|
852
|
+
// Fillet the edge where lid meets one wall
|
|
853
|
+
let body = box(100, 60, 30).labelFaces({ top: 'lid', 'side-left': 'wall' })
|
|
854
|
+
body = fillet(body, 2, body.edgesBetween('lid', 'wall'))
|
|
855
|
+
|
|
856
|
+
// Fillet a cylinder rim — where the flat cap meets the curved barrel
|
|
857
|
+
let tube = cylinder(30, 10).labelFaces({ top: 'cap', side: 'barrel' })
|
|
858
|
+
tube = fillet(tube, 1, tube.edgesBetween('cap', 'barrel'))
|
|
859
|
+
|
|
860
|
+
// Multiple target faces at once
|
|
861
|
+
body.edgesBetween('lid', ['left-wall', 'right-wall', 'front-wall', 'back-wall'])
|
|
862
|
+
```
|
|
639
863
|
|
|
640
864
|
```ts
|
|
641
|
-
|
|
642
|
-
/** Connection point on the edge */
|
|
643
|
-
point: Vec3$5;
|
|
644
|
-
/** Tangent direction along the edge at the connection point */
|
|
645
|
-
tangent: Vec3$5;
|
|
646
|
-
/** Surface normal at the connection point (optional, for future G2 support) */
|
|
647
|
-
normal?: Vec3$5;
|
|
648
|
-
/** Weight controlling how far the curve follows this edge's tangent. Default 1.0. */
|
|
649
|
-
weight?: number;
|
|
650
|
-
}
|
|
865
|
+
edgesBetween(faceA: string, faceB: string | string[]): EdgeSegment[]
|
|
651
866
|
```
|
|
652
867
|
|
|
653
|
-
|
|
868
|
+
**Transforms**
|
|
654
869
|
|
|
655
|
-
#### `
|
|
870
|
+
#### `translate()` — Move the shape relative to its current position. All transforms are immutable and return new shapes.
|
|
656
871
|
|
|
657
872
|
```ts
|
|
658
|
-
|
|
873
|
+
translate(x: number, y: number, z: number): Shape
|
|
659
874
|
```
|
|
660
875
|
|
|
661
|
-
|
|
876
|
+
#### `translatePolar()` — Translate using polar coordinates (radius + angle in degrees). Eliminates manual `r * Math.cos(angle * PI/180)` calculations.
|
|
662
877
|
|
|
663
|
-
|
|
878
|
+
Example: `shape.translatePolar(50, 30)` moves 50mm at 30 degrees from +X.
|
|
664
879
|
|
|
665
880
|
```ts
|
|
666
|
-
|
|
667
|
-
/** Position */
|
|
668
|
-
point: Vec3$5;
|
|
669
|
-
/** Tangent direction (will be normalized internally) */
|
|
670
|
-
tangent: Vec3$5;
|
|
671
|
-
/** Second derivative / curvature vector. Default [0, 0, 0]. */
|
|
672
|
-
curvature?: Vec3$5;
|
|
673
|
-
/** Weight: scales tangent magnitude relative to chord length. Default 1.0. */
|
|
674
|
-
weight?: number;
|
|
675
|
-
}
|
|
881
|
+
translatePolar(radius: number, angleDeg: number, z?: number): Shape
|
|
676
882
|
```
|
|
677
883
|
|
|
678
|
-
|
|
884
|
+
#### `moveTo()` — Position the shape so its bounding box min corner is at the given global coordinate.
|
|
679
885
|
|
|
680
|
-
|
|
886
|
+
```ts
|
|
887
|
+
moveTo(x: number, y: number, z: number): Shape
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
#### `moveToLocal()` — Position the shape relative to another shape's local coordinate system (bounding box min corner).
|
|
681
891
|
|
|
682
892
|
```ts
|
|
683
|
-
|
|
893
|
+
moveToLocal(target: Shape | { toShape(): Shape; }, x: number, y: number, z: number): Shape
|
|
684
894
|
```
|
|
685
895
|
|
|
686
|
-
|
|
896
|
+
#### `rotate()` — Rotate around an arbitrary axis through the origin.
|
|
897
|
+
|
|
898
|
+
```ts
|
|
899
|
+
rotate(axis: [ number, number, number ], angleDeg: number, options?: { pivot?: [ number, number, number ]; }): Shape
|
|
900
|
+
```
|
|
687
901
|
|
|
688
|
-
|
|
902
|
+
#### `rotateX()` — Rotate around the X axis by the given angle in degrees.
|
|
689
903
|
|
|
690
904
|
```ts
|
|
691
|
-
|
|
692
|
-
/** Angle of the first element in degrees (default: 0 = +X axis). */
|
|
693
|
-
startDeg?: number;
|
|
694
|
-
/** Center X coordinate (default: 0). */
|
|
695
|
-
centerX?: number;
|
|
696
|
-
/** Center Y coordinate (default: 0). */
|
|
697
|
-
centerY?: number;
|
|
698
|
-
}
|
|
905
|
+
rotateX(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): Shape
|
|
699
906
|
```
|
|
700
907
|
|
|
701
|
-
|
|
908
|
+
#### `rotateY()` — Rotate around the Y axis by the given angle in degrees.
|
|
909
|
+
|
|
910
|
+
```ts
|
|
911
|
+
rotateY(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): Shape
|
|
912
|
+
```
|
|
702
913
|
|
|
703
|
-
|
|
914
|
+
#### `rotateZ()` — Rotate around the Z axis by the given angle in degrees.
|
|
704
915
|
|
|
705
916
|
```ts
|
|
706
|
-
|
|
707
|
-
x: number;
|
|
708
|
-
y: number;
|
|
709
|
-
}
|
|
917
|
+
rotateZ(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): Shape
|
|
710
918
|
```
|
|
711
919
|
|
|
712
|
-
|
|
920
|
+
#### `rotateAroundTo()` — Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point. `movingPoint` / `targetPoint` may be raw world points or this shape's anchors/references.
|
|
713
921
|
|
|
714
|
-
|
|
922
|
+
```ts
|
|
923
|
+
rotateAroundTo(axis: [ number, number, number ], pivot: [ number, number, number ], movingPoint: RotationPointLike, targetPoint: RotationPointLike, options?: RotateAroundToOptions): Shape
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
#### `transform()` — Apply a 4x4 affine transform matrix (column-major) or a Transform object.
|
|
715
927
|
|
|
716
928
|
```ts
|
|
717
|
-
|
|
929
|
+
transform(m: Mat4 | Transform): Shape
|
|
718
930
|
```
|
|
719
931
|
|
|
720
|
-
|
|
932
|
+
#### `scale()` — Scale the shape uniformly or per-axis from the shape's bounding box center. Accepts a single number or [x, y, z] array.
|
|
933
|
+
|
|
934
|
+
```ts
|
|
935
|
+
scale(v: number | [ number, number, number ]): Shape
|
|
936
|
+
```
|
|
721
937
|
|
|
722
|
-
|
|
938
|
+
#### `scaleAround()` — Scale the shape uniformly or per-axis from an explicit pivot point.
|
|
723
939
|
|
|
724
940
|
```ts
|
|
725
|
-
|
|
726
|
-
/** Angle of the first vertex in degrees (default: 90 = top). */
|
|
727
|
-
startDeg?: number;
|
|
728
|
-
/** Center X coordinate (default: 0). */
|
|
729
|
-
centerX?: number;
|
|
730
|
-
/** Center Y coordinate (default: 0). */
|
|
731
|
-
centerY?: number;
|
|
732
|
-
}
|
|
941
|
+
scaleAround(pivot: [ number, number, number ], v: number | [ number, number, number ]): Shape
|
|
733
942
|
```
|
|
734
943
|
|
|
735
|
-
|
|
944
|
+
#### `mirror()` — Mirror across a plane through the shape's bounding box center, defined by its normal vector.
|
|
945
|
+
|
|
946
|
+
```ts
|
|
947
|
+
mirror(normal: [ number, number, number ]): Shape
|
|
948
|
+
```
|
|
736
949
|
|
|
737
|
-
#### `
|
|
950
|
+
#### `mirrorThrough()` — Mirror across a plane through an explicit point, defined by its normal vector.
|
|
738
951
|
|
|
739
952
|
```ts
|
|
740
|
-
|
|
953
|
+
mirrorThrough(point: [ number, number, number ], normal: [ number, number, number ]): Shape
|
|
741
954
|
```
|
|
742
955
|
|
|
743
|
-
|
|
956
|
+
#### `pointAlong()` — Reorient a shape so its primary axis (Z) points along the given direction. Useful for laying cylinders/extrusions along X or Y without thinking about Euler angles. The shape's origin stays at [0,0,0] — translate after pointAlong to position it.
|
|
744
957
|
|
|
745
|
-
|
|
958
|
+
Example: cylinder(40, 5).pointAlong([1, 0, 0]) — lays cylinder along X, starting at origin
|
|
746
959
|
|
|
747
960
|
```ts
|
|
748
|
-
|
|
961
|
+
pointAlong(direction: [ number, number, number ]): Shape
|
|
749
962
|
```
|
|
750
963
|
|
|
751
|
-
|
|
964
|
+
**Booleans & Cutting**
|
|
752
965
|
|
|
753
|
-
#### `
|
|
966
|
+
#### `add()` — Union this shape with others (additive boolean). Method form of union().
|
|
754
967
|
|
|
755
968
|
```ts
|
|
756
|
-
|
|
969
|
+
add(...others: ShapeOperandInput[]): Shape
|
|
757
970
|
```
|
|
758
971
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
#### `arcSlot()`
|
|
972
|
+
#### `subtract()` — Subtract other shapes from this one. Method form of difference().
|
|
762
973
|
|
|
763
974
|
```ts
|
|
764
|
-
|
|
975
|
+
subtract(...others: ShapeOperandInput[]): Shape
|
|
765
976
|
```
|
|
766
977
|
|
|
767
|
-
|
|
978
|
+
#### `intersect()` — Keep only the overlap with other shapes. Method form of intersection().
|
|
979
|
+
|
|
980
|
+
```ts
|
|
981
|
+
intersect(...others: ShapeOperandInput[]): Shape
|
|
982
|
+
```
|
|
768
983
|
|
|
769
|
-
#### `
|
|
984
|
+
#### `split()` — Split into [inside, outside] by another shape.
|
|
770
985
|
|
|
771
986
|
```ts
|
|
772
|
-
|
|
987
|
+
split(cutter: Shape | { toShape(): Shape; }): [ Shape, Shape ]
|
|
773
988
|
```
|
|
774
989
|
|
|
775
|
-
|
|
990
|
+
#### `splitByPlane()` — Split by infinite plane. Returns [positive-side, negative-side].
|
|
991
|
+
|
|
992
|
+
```ts
|
|
993
|
+
splitByPlane(normal: [ number, number, number ], originOffset?: number): [ Shape, Shape ]
|
|
994
|
+
```
|
|
776
995
|
|
|
777
|
-
|
|
996
|
+
#### `trimByPlane()` — Keep the positive side of the plane and discard the opposite side.
|
|
778
997
|
|
|
779
998
|
```ts
|
|
780
|
-
|
|
781
|
-
/** Number of samples along each direction. Default 24. */
|
|
782
|
-
resolution?: number;
|
|
783
|
-
/** Thickness of the generated solid. Default 0.5. */
|
|
784
|
-
thickness?: number;
|
|
785
|
-
}
|
|
999
|
+
trimByPlane(normal: [ number, number, number ], originOffset?: number): Shape
|
|
786
1000
|
```
|
|
787
1001
|
|
|
788
|
-
|
|
1002
|
+
**Features**
|
|
789
1003
|
|
|
790
|
-
#### `
|
|
1004
|
+
#### `shell()` — Hollow out compile-covered boxes, cylinders, and straight extrudes. `openFaces` names any subset of the base shape's labeled faces to leave open (no wall).
|
|
791
1005
|
|
|
792
1006
|
```ts
|
|
793
|
-
|
|
1007
|
+
shell(thickness: number, opts?: { openFaces?: string[]; }): Shape
|
|
794
1008
|
```
|
|
795
1009
|
|
|
796
|
-
|
|
1010
|
+
#### `pocket()` — Cut a pocket (cavity) into this solid through the named face.
|
|
797
1011
|
|
|
798
|
-
|
|
1012
|
+
```js
|
|
1013
|
+
box(100, 100, 20).pocket('top', 8)
|
|
1014
|
+
box(100, 100, 20).pocket('top', 8, { inset: 5 })
|
|
1015
|
+
box(100, 100, 20).pocket('top', 8, { scale: 0.8 })
|
|
1016
|
+
```
|
|
799
1017
|
|
|
800
1018
|
```ts
|
|
801
|
-
|
|
802
|
-
/** Connection point on the edge. Can be any point along the edge where the transition should connect. */
|
|
803
|
-
point: Vec3$7;
|
|
804
|
-
/** 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). */
|
|
805
|
-
tangent: Vec3$7;
|
|
806
|
-
/** Surface normal at the connection point (optional). Used as a hint for the sweep frame's up vector. */
|
|
807
|
-
normal?: Vec3$7;
|
|
808
|
-
}
|
|
1019
|
+
pocket(face: FaceSelector, depth: number, opts?: PocketOptions): Shape
|
|
809
1020
|
```
|
|
810
1021
|
|
|
811
|
-
|
|
1022
|
+
#### `boss()` — Add a boss (protrusion) from the named face.
|
|
812
1023
|
|
|
813
|
-
|
|
1024
|
+
```js
|
|
1025
|
+
box(100, 100, 20).boss('top', 5)
|
|
1026
|
+
box(100, 100, 20).boss('top', 10, { scale: 0.6 })
|
|
1027
|
+
```
|
|
814
1028
|
|
|
815
1029
|
```ts
|
|
816
|
-
|
|
817
|
-
/** Weight for the start edge. Controls tangent magnitude at the start. - 1.0 (default): balanced transition - > 1.0: curve follows start edge longer before turning - < 1.0: curve turns sooner at the start */
|
|
818
|
-
weightA?: number;
|
|
819
|
-
/** Weight for the end edge. Controls tangent magnitude at the end. - 1.0 (default): balanced transition - > 1.0: curve follows end edge longer before turning - < 1.0: curve turns sooner at the end */
|
|
820
|
-
weightB?: number;
|
|
821
|
-
/** Number of sample points for the output polyline. Default 64. Higher values give smoother curves at the cost of more geometry. */
|
|
822
|
-
samples?: number;
|
|
823
|
-
}
|
|
1030
|
+
boss(face: FaceSelector, height: number, opts?: BossOptions): Shape
|
|
824
1031
|
```
|
|
825
1032
|
|
|
826
|
-
|
|
1033
|
+
#### `hole()` — Drill a hole into this solid at a face.
|
|
827
1034
|
|
|
828
|
-
|
|
1035
|
+
```js
|
|
1036
|
+
box(50, 50, 20).hole('top', { diameter: 8, depth: 10 })
|
|
1037
|
+
box(50, 50, 20).hole('top', { diameter: 6, counterbore: { diameter: 12, depth: 3 } })
|
|
1038
|
+
```
|
|
829
1039
|
|
|
830
1040
|
```ts
|
|
831
|
-
|
|
1041
|
+
hole(faceOrRef: SketchFaceTarget | FaceRef, opts: ShapeHoleOptions): Shape
|
|
832
1042
|
```
|
|
833
1043
|
|
|
834
|
-
|
|
1044
|
+
#### `cutout()` — Cut a profile-shaped pocket through a face using a placed sketch.
|
|
835
1045
|
|
|
1046
|
+
The sketch must be placed on a face with `Sketch.onFace(...)`. The cut follows the sketch's 2D profile.
|
|
836
1047
|
|
|
837
|
-
|
|
1048
|
+
```js
|
|
1049
|
+
const profile = circle2d(10).onFace(body, 'top');
|
|
1050
|
+
body.cutout(profile, { depth: 5 })
|
|
1051
|
+
```
|
|
838
1052
|
|
|
839
1053
|
```ts
|
|
840
|
-
|
|
841
|
-
/** Cross-section profile to sweep along the transition curve. If omitted, a circular profile with `radius` is used. */
|
|
842
|
-
profile?: Sketch;
|
|
843
|
-
/** Radius of circular cross-section (used when `profile` is omitted). Default: 5% of chord length. */
|
|
844
|
-
radius?: number;
|
|
845
|
-
width: number;
|
|
846
|
-
height: number;
|
|
847
|
-
/** Preferred up vector for the sweep frame. Default: auto-detected. */
|
|
848
|
-
up?: Vec3$7;
|
|
849
|
-
/** Edge length for level-set meshing. Smaller = finer. */
|
|
850
|
-
edgeLength?: number;
|
|
851
|
-
/** Extra bounds padding for level-set meshing. */
|
|
852
|
-
boundsPadding?: number;
|
|
853
|
-
}
|
|
1054
|
+
cutout(sketch: Sketch, opts?: ShapeCutoutOptions): Shape
|
|
854
1055
|
```
|
|
855
1056
|
|
|
856
|
-
|
|
1057
|
+
**Placement**
|
|
857
1058
|
|
|
858
|
-
#### `
|
|
1059
|
+
#### `placeReference()` — Translate the shape so the given anchor or reference lands on the target coordinate.
|
|
859
1060
|
|
|
860
|
-
|
|
861
|
-
transitionCurveFromPoints(startPoint: Vec3$7, startTangent: Vec3$7, endPoint: Vec3$7, endTangent: Vec3$7, options?: TransitionCurveOptions): HermiteCurve3D
|
|
862
|
-
```
|
|
1061
|
+
Accepts any built-in anchor name (`'bottom'`, `'center'`, `'top-front-left'`, etc.) or a custom placement reference attached via `withReferences()`.
|
|
863
1062
|
|
|
864
|
-
|
|
1063
|
+
```javascript
|
|
1064
|
+
// Ground a shape — put its bottom face center at Z = 0
|
|
1065
|
+
shape.placeReference('bottom', [0, 0, 0])
|
|
865
1066
|
|
|
866
|
-
|
|
1067
|
+
// Center at the world origin
|
|
1068
|
+
shape.placeReference('center', [0, 0, 0])
|
|
1069
|
+
|
|
1070
|
+
// Align left edge to X = 10
|
|
1071
|
+
shape.placeReference('left', [10, 0, 0])
|
|
1072
|
+
```
|
|
867
1073
|
|
|
868
1074
|
```ts
|
|
869
|
-
|
|
1075
|
+
placeReference(ref: PlacementAnchorLike, target: [ number, number, number ], offset?: [ number, number, number ]): Shape
|
|
870
1076
|
```
|
|
871
1077
|
|
|
872
|
-
|
|
1078
|
+
#### `attachTo()` — Position this shape relative to another using named 3D anchor points.
|
|
1079
|
+
|
|
1080
|
+
Anchors are bounding-box-relative: 'center', face centers ('top', 'front', ...), edge midpoints ('top-front', 'back-left', ...), and corners ('top-front-left', ...). Anchor word order is flexible: 'front-left' and 'left-front' are equivalent. Named placement references (from withReferences) can also be used as anchors.
|
|
873
1081
|
|
|
874
1082
|
```ts
|
|
875
|
-
|
|
876
|
-
/** Stable index within the extraction (deterministic for a given mesh). */
|
|
877
|
-
index: number;
|
|
878
|
-
start: Vec3;
|
|
879
|
-
end: Vec3;
|
|
880
|
-
midpoint: Vec3;
|
|
881
|
-
/** Normalized direction from start → end. */
|
|
882
|
-
direction: Vec3;
|
|
883
|
-
length: number;
|
|
884
|
-
/** Dihedral angle in degrees (0 = coplanar, 180 = knife edge). */
|
|
885
|
-
dihedralAngle: number;
|
|
886
|
-
/** true = outside corner (convex), false = inside corner (concave). */
|
|
887
|
-
convex: boolean;
|
|
888
|
-
/** Normal of first adjacent face. */
|
|
889
|
-
normalA: Vec3;
|
|
890
|
-
/** Normal of second adjacent face (same as normalA for boundary edges). */
|
|
891
|
-
normalB: Vec3;
|
|
892
|
-
/** true if this is a boundary (unmatched) edge — unusual for closed solids. */
|
|
893
|
-
boundary: boolean;
|
|
894
|
-
}
|
|
1083
|
+
attachTo(target: ShapeAnchorTarget, targetAnchor: PlacementAnchorLike, selfAnchor?: PlacementAnchorLike, offset?: [ number, number, number ]): Shape
|
|
895
1084
|
```
|
|
896
1085
|
|
|
897
|
-
|
|
1086
|
+
#### `onFace()` — Place this shape on a face of a parent shape.
|
|
898
1087
|
|
|
1088
|
+
Think of it like sticking a label on a box surface:
|
|
899
1089
|
|
|
900
|
-
|
|
1090
|
+
- `face` picks which surface ('front', 'back', 'top', etc.)
|
|
1091
|
+
- `u, v` position within that face's 2D plane (from center)
|
|
1092
|
+
- front/back: u = left/right (X), v = up/down (Z)
|
|
1093
|
+
- left/right: u = forward/back (Y), v = up/down (Z)
|
|
1094
|
+
- top/bottom: u = left/right (X), v = forward/back (Y)
|
|
1095
|
+
- `protrude` = how far the child sticks out (positive = outward from face)
|
|
901
1096
|
|
|
902
1097
|
```ts
|
|
903
|
-
|
|
904
|
-
/** Which end of edge A to connect. Default: 'start'. */
|
|
905
|
-
endA?: EdgeEnd;
|
|
906
|
-
/** Which end of edge B to connect. Default: 'start'. */
|
|
907
|
-
endB?: EdgeEnd;
|
|
908
|
-
/** Tangent mode for edge A. Default: 'along'. */
|
|
909
|
-
tangentModeA?: TangentMode;
|
|
910
|
-
/** Tangent mode for edge B. Default: 'along'. */
|
|
911
|
-
tangentModeB?: TangentMode;
|
|
912
|
-
/** Explicit tangent for edge A. */
|
|
913
|
-
tangentA?: Vec3$7;
|
|
914
|
-
/** Explicit tangent for edge B. */
|
|
915
|
-
tangentB?: Vec3$7;
|
|
916
|
-
/** Flip tangent A. */
|
|
917
|
-
flipA?: boolean;
|
|
918
|
-
/** Flip tangent B. */
|
|
919
|
-
flipB?: boolean;
|
|
920
|
-
}
|
|
1098
|
+
onFace(parent: ShapeAnchorTarget, face: "front" | "back" | "left" | "right" | "top" | "bottom", opts?: { u?: number; v?: number; protrude?: number; }): Shape
|
|
921
1099
|
```
|
|
922
1100
|
|
|
923
|
-
|
|
1101
|
+
#### `seatInto()` — Slide this shape along an axis until a labeled face is embedded in the target body.
|
|
1102
|
+
|
|
1103
|
+
Position the shape roughly first (translate/rotate), then call seatInto to auto-adjust the penetration depth. No manual coordinate math needed.
|
|
1104
|
+
|
|
1105
|
+
```js
|
|
1106
|
+
// Wing root embeds into fuselage — adapts to any fuselage shape
|
|
1107
|
+
wing.translate(0, wingY, 0).seatInto(fuselage, 'root');
|
|
924
1108
|
|
|
925
|
-
|
|
1109
|
+
// Sensor pod sits flush on fuselage surface
|
|
1110
|
+
pod.translate(0, station, radius + 20).seatInto(fuselage, 'base', { depth: 'flush' });
|
|
1111
|
+
|
|
1112
|
+
// Antenna with 3mm gasket standoff
|
|
1113
|
+
mast.translate(0, station, radius + 50).seatInto(fuselage, 'mount', { depth: 'flush', gap: 3 });
|
|
1114
|
+
```
|
|
926
1115
|
|
|
927
1116
|
```ts
|
|
928
|
-
|
|
1117
|
+
seatInto(target: Shape, surface: string, options?: SeatIntoOptions): Shape
|
|
929
1118
|
```
|
|
930
1119
|
|
|
931
|
-
|
|
1120
|
+
#### `seatOver()` — Slide this shape until a target's labeled face is fully covered (inside this shape).
|
|
932
1121
|
|
|
933
|
-
|
|
1122
|
+
The inverse of `seatInto`: instead of embedding *your* face into the target, you move until the *target's* face is embedded inside you.
|
|
1123
|
+
|
|
1124
|
+
```js
|
|
1125
|
+
// Nacelle moves up until pylon's bottom face is inside the nacelle
|
|
1126
|
+
nacelle.translate(rough).seatOver(pylon, 'bottom');
|
|
1127
|
+
|
|
1128
|
+
// Cap slides down over a post until post's top face is covered
|
|
1129
|
+
cap.translate(rough).seatOver(post, 'top');
|
|
1130
|
+
```
|
|
934
1131
|
|
|
935
1132
|
```ts
|
|
936
|
-
|
|
937
|
-
/** The display name of this spec */
|
|
938
|
-
name: string;
|
|
939
|
-
}
|
|
1133
|
+
seatOver(target: Shape, targetSurface: string, options?: SeatIntoOptions): Shape
|
|
940
1134
|
```
|
|
941
1135
|
|
|
942
|
-
|
|
1136
|
+
**Connectors**
|
|
943
1137
|
|
|
944
|
-
#### `
|
|
1138
|
+
#### `withConnectors()` — Attach named connectors — attachment points that survive transforms and imports. Connectors can be bare (position + orientation) or typed (with connectorType/gender for compatibility matching).
|
|
945
1139
|
|
|
946
1140
|
```ts
|
|
947
|
-
|
|
1141
|
+
withConnectors(connectors: Record<string, ConnectorInput>): Shape
|
|
948
1142
|
```
|
|
949
1143
|
|
|
950
|
-
#### `
|
|
1144
|
+
#### `connectorNames()` — List all connector names on this shape.
|
|
951
1145
|
|
|
952
1146
|
```ts
|
|
953
|
-
|
|
1147
|
+
connectorNames(): string[]
|
|
954
1148
|
```
|
|
955
1149
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
<details><summary><code>FingerJointOptions</code></summary>
|
|
1150
|
+
#### `connectorsByType()` — Get all connectors of a given type.
|
|
959
1151
|
|
|
960
1152
|
```ts
|
|
961
|
-
|
|
962
|
-
/** Explicit finger count (must be odd, >= 3). Default: auto from length/thickness. */
|
|
963
|
-
fingers?: number;
|
|
964
|
-
/** Explicit finger width. Default: auto. */
|
|
965
|
-
fingerWidth?: number;
|
|
966
|
-
/** Extra clearance per side (mm). Default: 0. */
|
|
967
|
-
clearance?: number;
|
|
968
|
-
/** Laser kerf (mm). Default: 0. */
|
|
969
|
-
kerf?: number;
|
|
970
|
-
/** Whether edge starts with full finger or half. Default: 'full'. */
|
|
971
|
-
endStyle?: "full" | "half";
|
|
972
|
-
}
|
|
1153
|
+
connectorsByType(type: string): Array<{ name: string; port: PortDef; }>
|
|
973
1154
|
```
|
|
974
1155
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
<details><summary><code>FingerJointResult</code></summary>
|
|
1156
|
+
#### `connectorDistance()` — Distance between two connector origins on this shape.
|
|
978
1157
|
|
|
979
1158
|
```ts
|
|
980
|
-
|
|
981
|
-
/** Even-position finger rects (tabs for side A, slots for side B). */
|
|
982
|
-
tabProfile: Sketch;
|
|
983
|
-
/** Odd-position finger rects (tabs for side B, slots for side A). */
|
|
984
|
-
matingProfile: Sketch;
|
|
985
|
-
/** Legacy: full rectangle minus odd slot cuts. */
|
|
986
|
-
slotProfile: Sketch;
|
|
987
|
-
}
|
|
1159
|
+
connectorDistance(nameA: string, nameB: string): number
|
|
988
1160
|
```
|
|
989
1161
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
#### `tabSlotProfile()`
|
|
1162
|
+
#### `connectorMeasurements()` — Get measurements metadata from a connector.
|
|
993
1163
|
|
|
994
1164
|
```ts
|
|
995
|
-
|
|
1165
|
+
connectorMeasurements(name: string): Record<string, number | string>
|
|
996
1166
|
```
|
|
997
1167
|
|
|
998
|
-
|
|
1168
|
+
#### `matchTo()` — Position this shape by matching connectors to a target.
|
|
1169
|
+
|
|
1170
|
+
Overloads:
|
|
999
1171
|
|
|
1000
|
-
|
|
1172
|
+
- Single pair: `matchTo(target, selfConn, targetConn, options?)`
|
|
1173
|
+
- Dictionary (same target): `matchTo(target, { selfConn: targetConn, ... }, options?)`
|
|
1174
|
+
- Multi-target: `matchTo([ [target1, selfConn1, targetConn1], ... ], options?)`
|
|
1001
1175
|
|
|
1002
1176
|
```ts
|
|
1003
|
-
|
|
1004
|
-
/** Number of tabs. Default: auto (length / (4 * thickness)). */
|
|
1005
|
-
tabCount?: number;
|
|
1006
|
-
/** Tab width. Default: 2 * thickness. */
|
|
1007
|
-
tabWidth?: number;
|
|
1008
|
-
/** Extra clearance per side (mm). Default: 0. */
|
|
1009
|
-
clearance?: number;
|
|
1010
|
-
/** Laser kerf (mm). Default: 0. */
|
|
1011
|
-
kerf?: number;
|
|
1012
|
-
/** Distance from panel edges to first/last tab center. Default: thickness. */
|
|
1013
|
-
inset?: number;
|
|
1014
|
-
}
|
|
1177
|
+
matchTo(targetOrPairs: Shape | MatchTarget | Array<[ Shape | MatchTarget, string, string ]>, selfConnOrDict?: string | Record<string, string>, targetConnOrOptions?: string | MatchToOptions, maybeOptions?: MatchToOptions): Shape
|
|
1015
1178
|
```
|
|
1016
1179
|
|
|
1017
|
-
|
|
1180
|
+
**References**
|
|
1018
1181
|
|
|
1019
|
-
|
|
1182
|
+
#### `withReferences()` — Attach named placement references that survive normal transforms and imports.
|
|
1020
1183
|
|
|
1021
1184
|
```ts
|
|
1022
|
-
|
|
1023
|
-
tabs: Sketch;
|
|
1024
|
-
slots: Sketch;
|
|
1025
|
-
}
|
|
1185
|
+
withReferences(refs: PlacementReferenceInput): Shape
|
|
1026
1186
|
```
|
|
1027
1187
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
#### `livingHingeProfile()`
|
|
1188
|
+
#### `referenceNames()` — List named placement references carried by this shape.
|
|
1031
1189
|
|
|
1032
1190
|
```ts
|
|
1033
|
-
|
|
1191
|
+
referenceNames(kind?: PlacementReferenceKind): string[]
|
|
1034
1192
|
```
|
|
1035
1193
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
<details><summary><code>LivingHingeOptions</code></summary>
|
|
1194
|
+
#### `referencePoint()` — Resolve a named placement reference or built-in anchor to a 3D point.
|
|
1039
1195
|
|
|
1040
1196
|
```ts
|
|
1041
|
-
|
|
1042
|
-
/** Slit pattern style. Default: 'straight'. */
|
|
1043
|
-
pattern?: "straight" | "serpentine";
|
|
1044
|
-
/** Explicit slit width (beyond kerf). Default: 0. */
|
|
1045
|
-
slitWidth?: number;
|
|
1046
|
-
/** Distance between slit rows. Default: 2 * thickness. */
|
|
1047
|
-
rowSpacing?: number;
|
|
1048
|
-
/** Length of each slit. Default: 0.7 * (length - 2 * landWidth). */
|
|
1049
|
-
slitLength?: number;
|
|
1050
|
-
/** Uncut material between slit ends and row edges. Default: 2 * thickness. */
|
|
1051
|
-
landWidth?: number;
|
|
1052
|
-
/** Target bend radius - auto-computes row spacing. Overrides rowSpacing. */
|
|
1053
|
-
bendRadius?: number;
|
|
1054
|
-
/** Material thickness (needed for bend radius calc). Default: 3. */
|
|
1055
|
-
thickness?: number;
|
|
1056
|
-
}
|
|
1197
|
+
referencePoint(ref: PlacementAnchorLike): [ number, number, number ]
|
|
1057
1198
|
```
|
|
1058
1199
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
#### `snapFitProfile()`
|
|
1200
|
+
#### `withPorts()` — Deprecated alias for `withConnectors()`.
|
|
1062
1201
|
|
|
1063
1202
|
```ts
|
|
1064
|
-
|
|
1203
|
+
withPorts(ports: Record<string, PortInput>): Shape
|
|
1065
1204
|
```
|
|
1066
1205
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
<details><summary><code>SnapFitOptions</code></summary>
|
|
1206
|
+
#### `portNames()` — Deprecated alias for `connectorNames()`.
|
|
1070
1207
|
|
|
1071
1208
|
```ts
|
|
1072
|
-
|
|
1073
|
-
/** Tab beam length. Default: 4 * thickness. */
|
|
1074
|
-
tabLength?: number;
|
|
1075
|
-
/** Tab beam width. Default: thickness. */
|
|
1076
|
-
tabWidth?: number;
|
|
1077
|
-
/** How much the barb protrudes beyond the beam. Default: 0.3 * thickness. */
|
|
1078
|
-
overhang?: number;
|
|
1079
|
-
/** Slot clearance per side. Default: 0.1. */
|
|
1080
|
-
clearance?: number;
|
|
1081
|
-
/** Laser kerf. Default: 0. */
|
|
1082
|
-
kerf?: number;
|
|
1083
|
-
/** Barb style. Default: 'barb'. */
|
|
1084
|
-
style?: "arrow" | "barb";
|
|
1085
|
-
}
|
|
1209
|
+
portNames(): string[]
|
|
1086
1210
|
```
|
|
1087
1211
|
|
|
1088
|
-
|
|
1212
|
+
**Measurement**
|
|
1089
1213
|
|
|
1090
|
-
|
|
1214
|
+
#### `boundingBox()` — Get the axis-aligned bounding box as { min: [x,y,z], max: [x,y,z] }.
|
|
1091
1215
|
|
|
1092
1216
|
```ts
|
|
1093
|
-
|
|
1094
|
-
tab: Sketch;
|
|
1095
|
-
slot: Sketch;
|
|
1096
|
-
}
|
|
1217
|
+
boundingBox(): ShapeRuntimeBounds
|
|
1097
1218
|
```
|
|
1098
1219
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
#### `kerfCompensateOutline()`
|
|
1220
|
+
#### `volume()` — Volume in mm cubed.
|
|
1102
1221
|
|
|
1103
1222
|
```ts
|
|
1104
|
-
|
|
1223
|
+
volume(): number
|
|
1105
1224
|
```
|
|
1106
1225
|
|
|
1107
|
-
|
|
1226
|
+
#### `surfaceArea()` — Surface area in mm squared.
|
|
1108
1227
|
|
|
1109
|
-
|
|
1228
|
+
```ts
|
|
1229
|
+
surfaceArea(): number
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1232
|
+
#### `isEmpty()` — True if the shape contains no geometry.
|
|
1110
1233
|
|
|
1111
1234
|
```ts
|
|
1112
|
-
|
|
1235
|
+
isEmpty(): boolean
|
|
1113
1236
|
```
|
|
1114
1237
|
|
|
1115
|
-
|
|
1238
|
+
#### `numBodies()` — Number of disconnected solid bodies in this shape.
|
|
1239
|
+
|
|
1240
|
+
```ts
|
|
1241
|
+
numBodies(): number
|
|
1242
|
+
```
|
|
1116
1243
|
|
|
1117
|
-
#### `
|
|
1244
|
+
#### `numTri()` — Triangle count of the mesh representation.
|
|
1118
1245
|
|
|
1119
1246
|
```ts
|
|
1120
|
-
|
|
1247
|
+
numTri(): number
|
|
1121
1248
|
```
|
|
1122
1249
|
|
|
1123
|
-
|
|
1250
|
+
**Other**
|
|
1124
1251
|
|
|
1125
|
-
#### `
|
|
1252
|
+
#### `clone()` — Return a new Shape wrapper for explicit duplication in scripts.
|
|
1126
1253
|
|
|
1127
1254
|
```ts
|
|
1128
|
-
|
|
1255
|
+
clone(): Shape
|
|
1129
1256
|
```
|
|
1130
1257
|
|
|
1131
|
-
|
|
1258
|
+
#### `geometryInfo()` — Inspect which backend/representation produced this solid.
|
|
1132
1259
|
|
|
1133
|
-
|
|
1260
|
+
```ts
|
|
1261
|
+
geometryInfo(): GeometryInfo
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
#### `getMesh()` — Extract triangle mesh for Three.js rendering
|
|
1134
1265
|
|
|
1135
1266
|
```ts
|
|
1136
|
-
|
|
1137
|
-
/** Geometry to ADD to the base profile (tabs, fingers protruding from edges). */
|
|
1138
|
-
additions?: Sketch[];
|
|
1139
|
-
/** Geometry to SUBTRACT from the base profile (slots, holes for mating tabs). */
|
|
1140
|
-
subtractions?: Sketch[];
|
|
1141
|
-
}
|
|
1267
|
+
getMesh(): ShapeRuntimeMesh
|
|
1142
1268
|
```
|
|
1143
1269
|
|
|
1144
|
-
|
|
1270
|
+
#### `slice()` — Slice the runtime solid by a plane normal to local Z at the given offset.
|
|
1271
|
+
|
|
1272
|
+
```ts
|
|
1273
|
+
slice(offset?: number): any
|
|
1274
|
+
```
|
|
1145
1275
|
|
|
1146
|
-
#### `
|
|
1276
|
+
#### `project()` — Orthographically project the runtime solid onto the local XY plane.
|
|
1147
1277
|
|
|
1148
1278
|
```ts
|
|
1149
|
-
|
|
1279
|
+
project(): any
|
|
1150
1280
|
```
|
|
1151
1281
|
|
|
1152
|
-
|
|
1282
|
+
### `Transform`
|
|
1153
1283
|
|
|
1154
|
-
#### `
|
|
1284
|
+
#### `identity()` — Return the identity transform.
|
|
1155
1285
|
|
|
1156
1286
|
```ts
|
|
1157
|
-
|
|
1287
|
+
static identity(): Transform
|
|
1158
1288
|
```
|
|
1159
1289
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
<details><summary><code>FlatPartOptions</code></summary>
|
|
1290
|
+
#### `from()` — Wrap an existing `Transform` or raw 4x4 matrix as a `Transform`.
|
|
1163
1291
|
|
|
1164
1292
|
```ts
|
|
1165
|
-
|
|
1166
|
-
material?: string;
|
|
1167
|
-
qty?: number;
|
|
1168
|
-
color?: string;
|
|
1169
|
-
}
|
|
1293
|
+
static from(input: TransformInput): Transform
|
|
1170
1294
|
```
|
|
1171
1295
|
|
|
1172
|
-
|
|
1296
|
+
#### `translation()` — Create a translation transform.
|
|
1297
|
+
|
|
1298
|
+
```ts
|
|
1299
|
+
static translation(x: number, y: number, z: number): Transform
|
|
1300
|
+
```
|
|
1173
1301
|
|
|
1174
|
-
#### `
|
|
1302
|
+
#### `scale()` — Create a uniform or per-axis scale transform.
|
|
1175
1303
|
|
|
1176
1304
|
```ts
|
|
1177
|
-
|
|
1305
|
+
static scale(v: number | Vec3): Transform
|
|
1178
1306
|
```
|
|
1179
1307
|
|
|
1180
|
-
Create a
|
|
1308
|
+
#### `rotationAxis()` — Create a rotation around an arbitrary axis, optionally about a pivot.
|
|
1181
1309
|
|
|
1182
|
-
|
|
1310
|
+
```ts
|
|
1311
|
+
static rotationAxis(axis: Vec3, angleDeg: number, pivot?: Vec3): Transform
|
|
1312
|
+
```
|
|
1313
|
+
|
|
1314
|
+
#### `rotateAroundTo()` — Solve the rotation needed to move one point onto a target line or plane.
|
|
1183
1315
|
|
|
1184
1316
|
```ts
|
|
1185
|
-
|
|
1317
|
+
static rotateAroundTo(axis: Vec3, pivot: Vec3, movingPoint: Vec3, targetPoint: Vec3, options?: RotateAroundToOptions): Transform
|
|
1186
1318
|
```
|
|
1187
1319
|
|
|
1188
|
-
|
|
1320
|
+
#### `mul()` — Compose transforms in chain order: `a.mul(b)` applies `a`, then `b`.
|
|
1321
|
+
|
|
1322
|
+
```ts
|
|
1323
|
+
mul(other: TransformInput): Transform
|
|
1324
|
+
```
|
|
1189
1325
|
|
|
1190
|
-
#### `
|
|
1326
|
+
#### `translate()` — Translate after the current transform.
|
|
1191
1327
|
|
|
1192
1328
|
```ts
|
|
1193
|
-
|
|
1329
|
+
translate(x: number, y: number, z: number): Transform
|
|
1194
1330
|
```
|
|
1195
1331
|
|
|
1196
|
-
|
|
1332
|
+
#### `rotateAxis()` — Rotate after the current transform.
|
|
1197
1333
|
|
|
1198
|
-
|
|
1334
|
+
```ts
|
|
1335
|
+
rotateAxis(axis: Vec3, angleDeg: number, pivot?: Vec3): Transform
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
#### `inverse()` — Return the inverse transform.
|
|
1199
1339
|
|
|
1200
1340
|
```ts
|
|
1201
|
-
|
|
1341
|
+
inverse(): Transform
|
|
1202
1342
|
```
|
|
1203
1343
|
|
|
1204
|
-
|
|
1344
|
+
#### [`point()`](/docs/sketch#point) — Transform a point using homogeneous coordinates.
|
|
1205
1345
|
|
|
1206
1346
|
```ts
|
|
1207
|
-
|
|
1208
|
-
type: "finger" | "tabSlot" | "snapFit";
|
|
1209
|
-
partA: string;
|
|
1210
|
-
partB: string;
|
|
1211
|
-
edgeA: string;
|
|
1212
|
-
edgeB: string;
|
|
1213
|
-
/** Fold angle in degrees. Default: 90. */
|
|
1214
|
-
foldAngle: number;
|
|
1215
|
-
}
|
|
1347
|
+
point(p: Vec3): Vec3
|
|
1216
1348
|
```
|
|
1217
1349
|
|
|
1218
|
-
|
|
1350
|
+
#### `vector()` — Transform a direction vector without translation.
|
|
1351
|
+
|
|
1352
|
+
```ts
|
|
1353
|
+
vector(v: Vec3): Vec3
|
|
1354
|
+
```
|
|
1219
1355
|
|
|
1220
|
-
|
|
1356
|
+
#### `toArray()` — Return the transform as a raw 4x4 matrix array.
|
|
1221
1357
|
|
|
1222
1358
|
```ts
|
|
1223
|
-
|
|
1224
|
-
/** Kerf compensation passed to each part's solid(). Default: 0 */
|
|
1225
|
-
kerf?: number;
|
|
1226
|
-
/** Fold amount: 0 = flat layout, 1 = fully assembled. Default: 1 */
|
|
1227
|
-
fold?: number;
|
|
1228
|
-
/** Explode distance: 0 = assembled, >0 = parts spread outward. Default: 0 */
|
|
1229
|
-
explode?: number;
|
|
1230
|
-
}
|
|
1359
|
+
toArray(): Mat4
|
|
1231
1360
|
```
|
|
1232
1361
|
|
|
1233
|
-
|
|
1362
|
+
### `ShapeGroup`
|
|
1234
1363
|
|
|
1235
|
-
|
|
1364
|
+
**Properties:**
|
|
1365
|
+
|
|
1366
|
+
| Property | Type | Description |
|
|
1367
|
+
|----------|------|-------------|
|
|
1368
|
+
| `children` | `GroupChild[]` | — |
|
|
1369
|
+
| `childNames` | `Array<string | undefined>` | — |
|
|
1370
|
+
|
|
1371
|
+
**Children**
|
|
1372
|
+
|
|
1373
|
+
#### `child()` — Return the named child by name. Throws if not found. Useful when importing a multipart group and working on components individually.
|
|
1236
1374
|
|
|
1237
1375
|
```ts
|
|
1238
|
-
|
|
1239
|
-
/** All part shapes grouped for display. */
|
|
1240
|
-
shapes: ShapeGroup;
|
|
1241
|
-
/** Individual transformed shapes keyed by part name. */
|
|
1242
|
-
partShapes: Map<string, Shape>;
|
|
1243
|
-
}
|
|
1376
|
+
child(name: string): GroupChild
|
|
1244
1377
|
```
|
|
1245
1378
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
#### `assemblyInstructions()`
|
|
1379
|
+
#### `childName()` — Return the optional name of the child at `index`.
|
|
1249
1380
|
|
|
1250
1381
|
```ts
|
|
1251
|
-
|
|
1382
|
+
childName(index: number): string | undefined
|
|
1252
1383
|
```
|
|
1253
1384
|
|
|
1254
|
-
|
|
1385
|
+
**Transforms**
|
|
1255
1386
|
|
|
1256
|
-
|
|
1387
|
+
#### `translate()` — Move the entire group by (x, y, z). All children move together as a unit.
|
|
1257
1388
|
|
|
1258
1389
|
```ts
|
|
1259
|
-
|
|
1260
|
-
/** Part to start from. Default: part with most joint connections. */
|
|
1261
|
-
rootPart?: string;
|
|
1262
|
-
}
|
|
1390
|
+
translate(x: number, y: number, z: number): ShapeGroup
|
|
1263
1391
|
```
|
|
1264
1392
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
<details><summary><code>AssemblyInstructionsResult</code></summary>
|
|
1393
|
+
#### `moveTo()` — Move the group so its bounding-box min corner lands at the given coordinate.
|
|
1268
1394
|
|
|
1269
1395
|
```ts
|
|
1270
|
-
|
|
1271
|
-
steps: AssemblyStep[];
|
|
1272
|
-
/** Total number of parts in the assembly. */
|
|
1273
|
-
totalParts: number;
|
|
1274
|
-
/** Parts not connected to the joint graph (orphans). */
|
|
1275
|
-
orphanParts: string[];
|
|
1276
|
-
}
|
|
1396
|
+
moveTo(x: number, y: number, z: number): ShapeGroup
|
|
1277
1397
|
```
|
|
1278
1398
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
```ts
|
|
1284
|
-
interface AssemblyStep {
|
|
1285
|
-
/** 1-based step number. */
|
|
1286
|
-
stepNumber: number;
|
|
1287
|
-
/** Human-readable instruction. */
|
|
1288
|
-
description: string;
|
|
1289
|
-
/** The part being added in this step. */
|
|
1290
|
-
partName: string;
|
|
1291
|
-
/** Part number (for cross-ref with cut sheets). */
|
|
1292
|
-
partNumber: number;
|
|
1293
|
-
/** Which existing part it connects to. */
|
|
1294
|
-
connectsTo: string;
|
|
1295
|
-
/** Joint type used. */
|
|
1296
|
-
jointType: "finger" | "tabSlot" | "snapFit";
|
|
1297
|
-
/** The edge on the new part. */
|
|
1298
|
-
newPartEdge: string;
|
|
1299
|
-
/** The edge on the existing part. */
|
|
1300
|
-
existingPartEdge: string;
|
|
1301
|
-
/** Fold angle in degrees. */
|
|
1302
|
-
foldAngle: number;
|
|
1303
|
-
/** Part names in the assembly so far (after this step). */
|
|
1304
|
-
assembledParts: string[];
|
|
1305
|
-
}
|
|
1399
|
+
#### `moveToLocal()` — Move the group relative to another part's bounding-box min corner.
|
|
1400
|
+
|
|
1401
|
+
```ts
|
|
1402
|
+
moveToLocal(target: Shape | ShapeGroup, x: number, y: number, z: number): ShapeGroup
|
|
1306
1403
|
```
|
|
1307
1404
|
|
|
1308
|
-
|
|
1405
|
+
#### `rotate()` — Rotate the group around an arbitrary axis through the origin.
|
|
1406
|
+
|
|
1407
|
+
```ts
|
|
1408
|
+
rotate(axis: [ number, number, number ], angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
1409
|
+
```
|
|
1309
1410
|
|
|
1310
|
-
#### `
|
|
1411
|
+
#### `rotateX()` — Rotate the group around the X axis.
|
|
1311
1412
|
|
|
1312
1413
|
```ts
|
|
1313
|
-
|
|
1414
|
+
rotateX(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
1314
1415
|
```
|
|
1315
1416
|
|
|
1316
|
-
|
|
1417
|
+
#### `rotateY()` — Rotate the group around the Y axis.
|
|
1418
|
+
|
|
1419
|
+
```ts
|
|
1420
|
+
rotateY(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
1421
|
+
```
|
|
1317
1422
|
|
|
1318
|
-
#### `
|
|
1423
|
+
#### `rotateZ()` — Rotate the group around the Z axis.
|
|
1319
1424
|
|
|
1320
1425
|
```ts
|
|
1321
|
-
|
|
1426
|
+
rotateZ(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
1322
1427
|
```
|
|
1323
1428
|
|
|
1324
|
-
|
|
1429
|
+
#### `rotateAroundAxis()` — Rotate around an arbitrary axis, optionally through a pivot point.
|
|
1430
|
+
|
|
1431
|
+
```ts
|
|
1432
|
+
rotateAroundAxis(axis: [ number, number, number ], angleDeg: number, pivot?: [ number, number, number ]): ShapeGroup
|
|
1433
|
+
```
|
|
1325
1434
|
|
|
1326
|
-
|
|
1435
|
+
#### `rotateAroundTo()` — Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point. ShapeGroup string points use built-in anchors only.
|
|
1327
1436
|
|
|
1328
1437
|
```ts
|
|
1329
|
-
|
|
1330
|
-
/** Default material label for parts that don't specify one. */
|
|
1331
|
-
material?: string;
|
|
1332
|
-
/** Stock sheet width in mm (default 600). */
|
|
1333
|
-
sheetWidth?: number;
|
|
1334
|
-
/** Stock sheet height in mm (default 400). */
|
|
1335
|
-
sheetHeight?: number;
|
|
1336
|
-
/** Laser kerf in mm (default 0.2). */
|
|
1337
|
-
kerf?: number;
|
|
1338
|
-
}
|
|
1438
|
+
rotateAroundTo(axis: [ number, number, number ], pivot: [ number, number, number ], movingPoint: Anchor3D | [ number, number, number ], targetPoint: Anchor3D | [ number, number, number ], options?: RotateAroundToOptions): ShapeGroup
|
|
1339
1439
|
```
|
|
1340
1440
|
|
|
1341
|
-
|
|
1441
|
+
#### `pointAlong()` — Reorient the group so its local Z axis points along `direction`.
|
|
1442
|
+
|
|
1443
|
+
```ts
|
|
1444
|
+
pointAlong(direction: [ number, number, number ]): ShapeGroup
|
|
1445
|
+
```
|
|
1342
1446
|
|
|
1343
|
-
#### `
|
|
1447
|
+
#### `transform()` — Apply a 4x4 transform matrix or `Transform` to all 3D children.
|
|
1344
1448
|
|
|
1345
1449
|
```ts
|
|
1346
|
-
|
|
1450
|
+
transform(m: Mat4 | Transform): ShapeGroup
|
|
1347
1451
|
```
|
|
1348
1452
|
|
|
1349
|
-
|
|
1453
|
+
#### `scale()` — Scale uniformly or per-axis from the group's bounding-box center.
|
|
1350
1454
|
|
|
1351
|
-
|
|
1455
|
+
```ts
|
|
1456
|
+
scale(v: number | [ number, number, number ]): ShapeGroup
|
|
1457
|
+
```
|
|
1458
|
+
|
|
1459
|
+
#### `scaleAround()` — Scale uniformly or per-axis from an explicit pivot point.
|
|
1352
1460
|
|
|
1353
1461
|
```ts
|
|
1354
|
-
|
|
1462
|
+
scaleAround(pivot: [ number, number, number ], v: number | [ number, number, number ]): ShapeGroup
|
|
1355
1463
|
```
|
|
1356
1464
|
|
|
1357
|
-
|
|
1465
|
+
#### `mirror()` — Mirror across a plane through the group's bounding-box center.
|
|
1358
1466
|
|
|
1359
|
-
|
|
1467
|
+
```ts
|
|
1468
|
+
mirror(normal: [ number, number, number ]): ShapeGroup
|
|
1469
|
+
```
|
|
1470
|
+
|
|
1471
|
+
#### `mirrorThrough()` — Mirror across a plane through an explicit point.
|
|
1360
1472
|
|
|
1361
1473
|
```ts
|
|
1362
|
-
|
|
1474
|
+
mirrorThrough(point: [ number, number, number ], normal: [ number, number, number ]): ShapeGroup
|
|
1363
1475
|
```
|
|
1364
1476
|
|
|
1365
|
-
|
|
1477
|
+
**Placement**
|
|
1478
|
+
|
|
1479
|
+
#### `placeReference()` — Translate the group so the given anchor or reference lands on the target coordinate.
|
|
1366
1480
|
|
|
1367
|
-
|
|
1481
|
+
Accepts any built-in anchor name (`'bottom'`, `'center'`, `'top-front-left'`, etc.) or a custom placement reference attached via `withReferences()`.
|
|
1482
|
+
|
|
1483
|
+
```javascript
|
|
1484
|
+
// Ground a group — put its bottom at Z = 0
|
|
1485
|
+
assembly.placeReference('bottom', [0, 0, 0])
|
|
1486
|
+
|
|
1487
|
+
// Use a custom reference from a multi-file part
|
|
1488
|
+
const placed = require('./bracket-assembly.forge.js').group
|
|
1489
|
+
.placeReference('mountCenter', [0, 0, 50]);
|
|
1490
|
+
```
|
|
1368
1491
|
|
|
1369
1492
|
```ts
|
|
1370
|
-
|
|
1371
|
-
color?: string;
|
|
1372
|
-
label?: string;
|
|
1373
|
-
pulse?: boolean;
|
|
1374
|
-
/** Size hint for points (radius in mm) or planes (disc radius in mm). */
|
|
1375
|
-
size?: number;
|
|
1376
|
-
}
|
|
1493
|
+
placeReference(ref: PlacementAnchorLike, target: [ number, number, number ], offset?: [ number, number, number ]): ShapeGroup
|
|
1377
1494
|
```
|
|
1378
1495
|
|
|
1379
|
-
|
|
1496
|
+
#### `attachTo()` — Attach this group to a face or anchor on another part.
|
|
1380
1497
|
|
|
1381
|
-
|
|
1498
|
+
`targetAnchor` can be a built-in anchor name or a custom reference name on the target. `selfAnchor` selects the anchor on this group to align.
|
|
1382
1499
|
|
|
1383
1500
|
```ts
|
|
1384
|
-
|
|
1501
|
+
attachTo(target: Shape | ShapeGroup, targetAnchor: Anchor3D | string, selfAnchor?: Anchor3D, offset?: [ number, number, number ]): ShapeGroup
|
|
1385
1502
|
```
|
|
1386
1503
|
|
|
1387
|
-
#### `
|
|
1504
|
+
#### `onFace()` — Place this group on a face of a parent shape. See Shape.onFace() for full documentation.
|
|
1388
1505
|
|
|
1389
1506
|
```ts
|
|
1390
|
-
|
|
1507
|
+
onFace(parent: Shape | ShapeGroup, face: "front" | "back" | "left" | "right" | "top" | "bottom", opts?: { u?: number; v?: number; protrude?: number; }): ShapeGroup
|
|
1391
1508
|
```
|
|
1392
1509
|
|
|
1393
|
-
|
|
1510
|
+
**Connectors**
|
|
1511
|
+
|
|
1512
|
+
#### `withConnectors()` — Attach named connectors — attachment points that survive transforms. Connectors can be bare (position + orientation) or typed (with connectorType/gender for compatibility matching).
|
|
1394
1513
|
|
|
1395
1514
|
```ts
|
|
1396
|
-
|
|
1515
|
+
withConnectors(connectors: Record<string, ConnectorInput>): ShapeGroup
|
|
1397
1516
|
```
|
|
1398
1517
|
|
|
1399
|
-
#### `
|
|
1518
|
+
#### `connectorNames()` — List all connector names, including "ChildName.connectorName" from named children.
|
|
1400
1519
|
|
|
1401
1520
|
```ts
|
|
1402
|
-
|
|
1521
|
+
connectorNames(): string[]
|
|
1403
1522
|
```
|
|
1404
1523
|
|
|
1405
|
-
#### `
|
|
1524
|
+
#### `connectorsByType()` — Get all connectors of a given type, including from named children.
|
|
1406
1525
|
|
|
1407
1526
|
```ts
|
|
1408
|
-
|
|
1527
|
+
connectorsByType(type: string): Array<{ name: string; port: PortDef; }>
|
|
1409
1528
|
```
|
|
1410
1529
|
|
|
1411
|
-
#### `
|
|
1530
|
+
#### `connectorDistance()` — Distance between two connector origins on this group (supports dotted child paths).
|
|
1412
1531
|
|
|
1413
1532
|
```ts
|
|
1414
|
-
|
|
1533
|
+
connectorDistance(nameA: string, nameB: string): number
|
|
1415
1534
|
```
|
|
1416
1535
|
|
|
1417
|
-
|
|
1536
|
+
#### `connectorMeasurements()` — Get measurements metadata from a connector (supports dotted child paths).
|
|
1418
1537
|
|
|
1419
1538
|
```ts
|
|
1420
|
-
|
|
1421
|
-
name: FaceName;
|
|
1422
|
-
/** Compiler-owned face query when available. */
|
|
1423
|
-
query?: FaceQueryRef;
|
|
1424
|
-
/** True when the face can host a 2D sketch placement frame */
|
|
1425
|
-
planar?: boolean;
|
|
1426
|
-
/** Shared descendant-resolution metadata when this face is a semantic region/set. */
|
|
1427
|
-
descendant?: FaceDescendantMetadata;
|
|
1428
|
-
}
|
|
1539
|
+
connectorMeasurements(name: string): Record<string, number | string>
|
|
1429
1540
|
```
|
|
1430
1541
|
|
|
1431
|
-
|
|
1542
|
+
#### `matchTo()` — Position this group by matching connectors to a target. Connector names support dotted paths into named children: "ChildName.connectorName".
|
|
1432
1543
|
|
|
1433
|
-
|
|
1544
|
+
Overloads:
|
|
1545
|
+
|
|
1546
|
+
- Single pair: `matchTo(target, selfConn, targetConn, options?)`
|
|
1547
|
+
- Dictionary (same target): `matchTo(target, { selfConn: targetConn, ... }, options?)`
|
|
1548
|
+
- Multi-target: `matchTo([ [target1, selfConn1, targetConn1], ... ], options?)`
|
|
1434
1549
|
|
|
1435
1550
|
```ts
|
|
1436
|
-
|
|
1437
|
-
kind: "single" | "face-set";
|
|
1438
|
-
semantic: FaceDescendantSemantic;
|
|
1439
|
-
memberCount: number;
|
|
1440
|
-
memberNames: string[];
|
|
1441
|
-
coplanar: boolean;
|
|
1442
|
-
}
|
|
1551
|
+
matchTo(targetOrPairs: Shape | ShapeGroup | Array<[ Shape | ShapeGroup, string, string ]>, selfConnOrDict?: string | Record<string, string>, targetConnOrOptions?: string | MatchToOptions, maybeOptions?: MatchToOptions): ShapeGroup
|
|
1443
1552
|
```
|
|
1444
1553
|
|
|
1445
|
-
|
|
1554
|
+
**References**
|
|
1555
|
+
|
|
1556
|
+
#### `withReferences()` — Attach named placement references to this group. References survive normal transforms (translate/rotate/scale/mirror/transform).
|
|
1446
1557
|
|
|
1447
|
-
|
|
1558
|
+
```javascript
|
|
1559
|
+
const bracket = group(
|
|
1560
|
+
{ name: 'Left', shape: leftShape },
|
|
1561
|
+
{ name: 'Right', shape: rightShape },
|
|
1562
|
+
).withReferences({
|
|
1563
|
+
points: { mountCenter: [0, 0, 0] },
|
|
1564
|
+
});
|
|
1565
|
+
```
|
|
1448
1566
|
|
|
1449
1567
|
```ts
|
|
1450
|
-
|
|
1568
|
+
withReferences(refs: PlacementReferenceInput): ShapeGroup
|
|
1451
1569
|
```
|
|
1452
1570
|
|
|
1453
|
-
|
|
1571
|
+
#### `referenceNames()` — List named placement references carried by this group.
|
|
1454
1572
|
|
|
1455
1573
|
```ts
|
|
1456
|
-
|
|
1457
|
-
name: EdgeName;
|
|
1458
|
-
/** Compiler-owned edge query when available. */
|
|
1459
|
-
query?: EdgeQueryRef;
|
|
1460
|
-
}
|
|
1574
|
+
referenceNames(kind?: PlacementReferenceKind): string[]
|
|
1461
1575
|
```
|
|
1462
1576
|
|
|
1463
|
-
|
|
1577
|
+
#### `referencePoint()` — Resolve a named placement reference or built-in Anchor3D to a 3D point. Named refs take priority over built-in anchors.
|
|
1464
1578
|
|
|
1465
|
-
|
|
1579
|
+
```ts
|
|
1580
|
+
referencePoint(ref: PlacementAnchorLike): [ number, number, number ]
|
|
1581
|
+
```
|
|
1466
1582
|
|
|
1467
|
-
|
|
1583
|
+
#### `withPorts()` — Backward-compatible alias for `withConnectors()`.
|
|
1468
1584
|
|
|
1469
|
-
|
|
1585
|
+
```ts
|
|
1586
|
+
withPorts(ports: Record<string, PortInput>): ShapeGroup
|
|
1587
|
+
```
|
|
1470
1588
|
|
|
1471
|
-
|
|
1589
|
+
#### `portNames()` — Backward-compatible alias for `connectorNames()`.
|
|
1472
1590
|
|
|
1473
|
-
|
|
1591
|
+
```ts
|
|
1592
|
+
portNames(): string[]
|
|
1593
|
+
```
|
|
1474
1594
|
|
|
1475
|
-
|
|
1476
|
-
|----------|------|-------------|
|
|
1477
|
-
| `materialProps` | `ShapeMaterialProps | undefined` | — |
|
|
1595
|
+
**Other**
|
|
1478
1596
|
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
- `setColor()` — Set the color of this shape (hex string, e.g. "#ff0000")
|
|
1482
|
-
- `color()` — Alias for setColor
|
|
1483
|
-
- `material()` — Set material properties for this shape's visual appearance. Returns a new Shape with the specified material properties merged. ```js box(50, 50, 50).material({ metalness: 0.9, roughness: 0.1 }); sphere(30).material({ emissive: '#ff6b35', emissiveIntensity: 2 }); cylinder(40, 20).material({ opacity: 0.3 }); ```
|
|
1484
|
-
- `clone()` — Return a new Shape wrapper for explicit duplication in scripts.
|
|
1485
|
-
- `duplicate()` — Alias for clone()
|
|
1486
|
-
- `geometryInfo()` — Inspect which backend/representation produced this solid.
|
|
1487
|
-
- `withReferences()` — Attach named placement references that survive normal transforms and imports.
|
|
1488
|
-
- `referenceNames()` — List named placement references carried by this shape.
|
|
1489
|
-
- `withPorts()` — Attach named assembly ports (origin + axis + up) that survive transforms and imports.
|
|
1490
|
-
- `portNames()` — List named port identifiers carried by this shape.
|
|
1491
|
-
- `referencePoint()` — Resolve a named placement reference or built-in anchor to a 3D point.
|
|
1492
|
-
- `face()` — Resolve a semantic face by name or query. Works on compile-covered shapes and, as a fallback, on any planar-faced mesh (e.g. the result of boolean ops) via coplanar triangle clustering.
|
|
1493
|
-
- `faces()` — Return all faces matching a query, or all mesh-detected faces when no query is given.
|
|
1494
|
-
- `faceNames()` — List defended semantic face names currently available on this shape.
|
|
1495
|
-
- `edge()` — Get a named topology edge. Only available on shapes with tracked topology (from box/cylinder/extrude).
|
|
1496
|
-
- `edgeNames()` — List named topology edge names. Returns empty array if shape has no tracked topology.
|
|
1497
|
-
- `faceHistory()` — Get the transformation history for a specific face.
|
|
1498
|
-
- `placeReference()` — Translate the shape so the given reference lands on the target coordinate.
|
|
1499
|
-
- `translatePolar()` — Translate using polar coordinates (radius + angle in degrees). Eliminates manual `r * Math.cos(angle * PI/180)` calculations. Example: `shape.translatePolar(50, 30)` moves 50mm at 30 degrees from +X.
|
|
1500
|
-
- `translate()` — Move the shape relative to its current position. All transforms are immutable and return new shapes.
|
|
1501
|
-
- `moveTo()` — Position the shape so its bounding box min corner is at the given global coordinate.
|
|
1502
|
-
- `moveToLocal()` — Position the shape relative to another shape's local coordinate system (bounding box min corner).
|
|
1503
|
-
- `rotate()` — Rotate using Euler angles in degrees around the shape's bounding box center.
|
|
1504
|
-
- `rotateAround()` — Rotate using Euler angles in degrees around an explicit pivot point.
|
|
1505
|
-
- `transform()` — Apply a 4x4 affine transform matrix (column-major) or a Transform object.
|
|
1506
|
-
- `scale()` — Scale the shape uniformly or per-axis from the shape's bounding box center. Accepts a single number or [x, y, z] array.
|
|
1507
|
-
- `scaleAround()` — Scale the shape uniformly or per-axis from an explicit pivot point.
|
|
1508
|
-
- `mirror()` — Mirror across a plane through the shape's bounding box center, defined by its normal vector.
|
|
1509
|
-
- `mirrorThrough()` — Mirror across a plane through an explicit point, defined by its normal vector.
|
|
1510
|
-
- `pointAlong()` — Reorient a shape so its primary axis (Z) points along the given direction. Useful for laying cylinders/extrusions along X or Y without thinking about Euler angles. Example: cylinder(40, 5).pointAlong([1, 0, 0]) — lays cylinder along X
|
|
1511
|
-
- `rotateAroundAxis()` — Rotate around an arbitrary axis through a pivot point. Equivalent to: translate(-pivot) → rotate around axis → translate(+pivot)
|
|
1512
|
-
- `rotateAroundTo()` — Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point. `movingPoint` / `targetPoint` may be raw world points or this shape's anchors/references.
|
|
1513
|
-
- `add()` — Union this shape with others (additive boolean). Method form of union().
|
|
1514
|
-
- `subtract()` — Subtract other shapes from this one. Method form of difference().
|
|
1515
|
-
- `intersect()` — Keep only the overlap with other shapes. Method form of intersection().
|
|
1516
|
-
- `union()` — Alias for add() — matches the free-function union() naming.
|
|
1517
|
-
- `difference()` — Alias for subtract() — matches the free-function difference() naming.
|
|
1518
|
-
- `intersection()` — Alias for intersect() — matches the free-function intersection() naming.
|
|
1519
|
-
- `split()` — Split into [inside, outside] by another shape.
|
|
1520
|
-
- `splitByPlane()` — Split by infinite plane. Returns [positive-side, negative-side].
|
|
1521
|
-
- `trimByPlane()` — Keep the positive side of the plane and discard the opposite side.
|
|
1522
|
-
- `shell()` — Hollow out compile-covered boxes, cylinders, and straight extrudes. `openFaces` names any subset of the base shape's faces to leave open (no wall). Box bases accept any of: top, bottom, front (=side-bottom), back (=side-top), left (=side-left), right (=side-right), or the raw internal names. Cylinder and extrude bases accept top and bottom only.
|
|
1523
|
-
- `boundingBox()` — Get the axis-aligned bounding box as { min: [x,y,z], max: [x,y,z] }.
|
|
1524
|
-
- `volume()` — Volume in mm cubed.
|
|
1525
|
-
- `surfaceArea()` — Surface area in mm squared.
|
|
1526
|
-
- `isEmpty()` — True if the shape contains no geometry.
|
|
1527
|
-
- `numBodies()` — Number of disconnected solid bodies in this shape.
|
|
1528
|
-
- `numTri()` — Triangle count of the mesh representation.
|
|
1529
|
-
- `getMesh()` — Extract triangle mesh for Three.js rendering
|
|
1530
|
-
- `slice()` — Slice the runtime solid by a plane normal to local Z at the given offset.
|
|
1531
|
-
- `project()` — Orthographically project the runtime solid onto the local XY plane.
|
|
1532
|
-
- `attachTo()` — Position this shape relative to another using named 3D anchor points. Anchors are bounding-box-relative: 'center', face centers ('top', 'front', ...), edge midpoints ('top-front', 'back-left', ...), and corners ('top-front-left', ...). Anchor word order is flexible: 'front-left' and 'left-front' are equivalent. Named placement references (from withReferences) can also be used as anchors.
|
|
1533
|
-
- `onFace()` — Place this shape on a face of a parent shape. Think of it like sticking a label on a box surface: - `face` picks which surface ('front', 'back', 'top', etc.) - `u, v` position within that face's 2D plane (from center) - front/back: u = left/right (X), v = up/down (Z) - left/right: u = forward/back (Y), v = up/down (Z) - top/bottom: u = left/right (X), v = forward/back (Y) - `protrude` = how far the child sticks out (positive = outward from face)
|
|
1534
|
-
- `withConnectors()` — Attach named connectors (typed, gendered ports) that survive transforms.
|
|
1535
|
-
- `connectorNames()` — List connector names (ports that have a connectorType).
|
|
1536
|
-
- `connectorsByType()` — Get all connectors of a given type.
|
|
1537
|
-
- `connectorDistance()` — Distance between two connector origins on this shape.
|
|
1538
|
-
- `connectorMeasurements()` — Get measurements metadata from a connector.
|
|
1539
|
-
- `matchTo()` — Position this shape by matching connectors to a target. Overloads: - Single pair: `matchTo(target, selfConn, targetConn, options?)` - Dictionary (same target): `matchTo(target, { selfConn: targetConn, ... }, options?)` - Multi-target: `matchTo([ [target1, selfConn1, targetConn1], ... ], options?)`
|
|
1540
|
-
- `pocket()` — Cut a pocket (cavity) into this solid through the named face. box(100, 100, 20).pocket('top', 8) box(100, 100, 20).pocket('top', 8, { inset: 5 }) box(100, 100, 20).pocket('top', 8, { scale: 0.8 })
|
|
1541
|
-
- `boss()` — Add a boss (protrusion) from the named face. box(100, 100, 20).boss('top', 5) box(100, 100, 20).boss('top', 10, { scale: 0.6 })
|
|
1542
|
-
- `hole()` — Drill a hole into this solid at a face. box(50, 50, 20).hole('top', { diameter: 8, depth: 10 }) box(50, 50, 20).hole('top', { diameter: 6, counterbore: { diameter: 12, depth: 3 } })
|
|
1543
|
-
- `cutout()` — Cut a profile-shaped pocket through a face using a placed sketch. The sketch must be placed on a face with `Sketch.onFace(...)`. The cut follows the sketch's 2D profile. const profile = circle2d(10).onFace(body, 'top'); body.cutout(profile, { depth: 5 })
|
|
1597
|
+
#### `clone()` — Return a deep-cloned ShapeGroup tree (refs copied).
|
|
1544
1598
|
|
|
1545
|
-
|
|
1599
|
+
```ts
|
|
1600
|
+
clone(): ShapeGroup
|
|
1601
|
+
```
|
|
1546
1602
|
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
- `static identity()` — static identity(): Transform
|
|
1550
|
-
- `static from()` — static from(input: TransformInput): Transform
|
|
1551
|
-
- `static translation()` — static translation(x: number, y: number, z: number): Transform
|
|
1552
|
-
- `static scale()` — static scale(v: number | Vec3): Transform
|
|
1553
|
-
- `static rotationAxis()` — static rotationAxis(axis: Vec3, angleDeg: number, pivot?: Vec3): Transform
|
|
1554
|
-
- `static rotateAroundTo()` — static rotateAroundTo(axis: Vec3, pivot: Vec3, movingPoint: Vec3, targetPoint: V
|
|
1555
|
-
- `mul()` — Compose transforms in chain order. `a.mul(b)` means apply `a`, then `b`.
|
|
1556
|
-
- `translate()` — translate(x: number, y: number, z: number): Transform
|
|
1557
|
-
- `rotateAxis()` — rotateAxis(axis: Vec3, angleDeg: number, pivot?: Vec3): Transform
|
|
1558
|
-
- `inverse()` — inverse(): Transform
|
|
1559
|
-
- `point()` — point(p: Vec3): Vec3
|
|
1560
|
-
- `vector()` — vector(v: Vec3): Vec3
|
|
1561
|
-
- `toArray()` — toArray(): Mat4
|
|
1603
|
+
#### `boundingBox()` — Return the combined 3D bounding box of all children.
|
|
1562
1604
|
|
|
1563
|
-
|
|
1605
|
+
```ts
|
|
1606
|
+
boundingBox(): { min: [ number, number, number ]; max: [ number, number, number ]; }
|
|
1607
|
+
```
|
|
1564
1608
|
|
|
1565
|
-
|
|
1609
|
+
#### `color()` — Return a copy of the group with the given display color applied to each child.
|
|
1566
1610
|
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
| `childNames` | `Array<string | undefined>` | — |
|
|
1611
|
+
```ts
|
|
1612
|
+
color(hex: string): ShapeGroup
|
|
1613
|
+
```
|
|
1571
1614
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
- `childName()` — childName(index: number): string | undefined
|
|
1575
|
-
- `child()` — Return the named child by name. Throws if not found. Useful when importing a multipart group and working on components individually.
|
|
1576
|
-
- `clone()` — Return a deep-cloned ShapeGroup tree (refs copied).
|
|
1577
|
-
- `duplicate()` — Alias for clone()
|
|
1578
|
-
- `translate()` — translate(x: number, y: number, z: number): ShapeGroup
|
|
1579
|
-
- `boundingBox()` — boundingBox(): { min: [ number, number, number ]; max: [ number, number, number
|
|
1580
|
-
- `moveTo()` — Move so combined bounding box min corner is at the given global coordinate
|
|
1581
|
-
- `moveToLocal()` — Move so combined bounding box min corner is at target's bounding box min + (x, y, z) offset
|
|
1582
|
-
- `attachTo()` — attachTo(target: Shape | ShapeGroup, targetAnchor: Anchor3D | string, selfAnchor
|
|
1583
|
-
- `onFace()` — Place this group on a face of a parent shape. See Shape.onFace() for full documentation.
|
|
1584
|
-
- `rotate()` — Rotate using Euler angles in degrees around the group's bounding box center.
|
|
1585
|
-
- `rotateAround()` — Rotate using Euler angles in degrees around an explicit pivot point.
|
|
1586
|
-
- `rotateAroundAxis()` — Rotate around an arbitrary axis, optionally through a pivot point.
|
|
1587
|
-
- `rotateAroundTo()` — Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point. ShapeGroup string points use built-in anchors only.
|
|
1588
|
-
- `pointAlong()` — Reorient all 3D children so their primary axis (Z) points along direction. Sugar for a single group-wide axis rotation via Transform.rotationAxis(...).
|
|
1589
|
-
- `transform()` — Apply a 4x4 transform matrix or Transform object to all 3D children.
|
|
1590
|
-
- `scale()` — Scale uniformly or per-axis from the group's bounding box center.
|
|
1591
|
-
- `scaleAround()` — Scale uniformly or per-axis from an explicit pivot point.
|
|
1592
|
-
- `mirror()` — Mirror across a plane through the group's bounding box center.
|
|
1593
|
-
- `mirrorThrough()` — Mirror across a plane through an explicit point.
|
|
1594
|
-
- `color()` — color(hex: string): ShapeGroup
|
|
1595
|
-
- `withReferences()` — Attach named placement references to this group. References survive normal transforms (translate/rotate/scale/mirror/transform). ```javascript const bracket = group( { name: 'Left', shape: leftShape }, { name: 'Right', shape: rightShape }, ).withReferences({ points: { mountCenter: [0, 0, 0] }, }); ```
|
|
1596
|
-
- `referenceNames()` — List named placement references carried by this group.
|
|
1597
|
-
- `withPorts()` — Attach named assembly ports (origin + axis + up) that survive transforms.
|
|
1598
|
-
- `portNames()` — List named port identifiers carried by this group.
|
|
1599
|
-
- `referencePoint()` — Resolve a named placement reference or built-in Anchor3D to a 3D point. Named refs take priority over built-in anchors.
|
|
1600
|
-
- `placeReference()` — Translate the group so the given reference lands on the target coordinate. ```javascript const placed = require('./bracket-assembly.forge.js').group .placeReference('mountCenter', [0, 0, 50]); ```
|
|
1601
|
-
- `withConnectors()` — Attach named connectors (typed, gendered ports) that survive transforms.
|
|
1602
|
-
- `connectorNames()` — List connector names (ports that have a connectorType), including "ChildName.connectorName" from named children.
|
|
1603
|
-
- `connectorsByType()` — Get all connectors of a given type, including from named children.
|
|
1604
|
-
- `connectorDistance()` — Distance between two connector origins on this group (supports dotted child paths).
|
|
1605
|
-
- `connectorMeasurements()` — Get measurements metadata from a connector (supports dotted child paths).
|
|
1606
|
-
- `matchTo()` — Position this group by matching connectors to a target. Connector names support dotted paths into named children: "ChildName.connectorName". Overloads: - Single pair: `matchTo(target, selfConn, targetConn, options?)` - Dictionary (same target): `matchTo(target, { selfConn: targetConn, ... }, options?)` - Multi-target: `matchTo([ [target1, selfConn1, targetConn1], ... ], options?)`
|
|
1607
|
-
|
|
1608
|
-
### `RouteBuilder`
|
|
1609
|
-
|
|
1610
|
-
**Methods:**
|
|
1611
|
-
|
|
1612
|
-
- `up()` — Vertical line going +Y. Length is optional (solver determines it from constraints).
|
|
1613
|
-
- `down()` — Vertical line going -Y. Length is optional.
|
|
1614
|
-
- `right()` — Horizontal line going +X. Length is optional.
|
|
1615
|
-
- `left()` — Horizontal line going -X. Length is optional.
|
|
1616
|
-
- `lineAt()` — Line at an arbitrary angle (degrees from +X). Length is optional.
|
|
1617
|
-
- `line()` — Line with solver-determined direction. Length is optional. Direction comes from tangency to previous arc or from constraints.
|
|
1618
|
-
- `toward()` — Line toward a specific point. Length defaults to the distance to that point.
|
|
1619
|
-
- `arcLeft()` — Tangent arc turning left relative to travel direction. or `{ minSweep: degrees }` to seed the geometry without constraining. `minSweep` guides the solver to the correct branch for arcs that sweep more than the default 90° seed.
|
|
1620
|
-
- `arcRight()` — Tangent arc turning right relative to travel direction. or `{ minSweep: degrees }` to seed without constraining.
|
|
1621
|
-
- `close()` — Close the route with a straight line back to the start point.
|
|
1622
|
-
- `done()` — Close the route back to its start point and register as a profile loop. No extra line segment is added. A coincident constraint connects the last point to the start, and tangency is added for G1 smoothness when arcs are at the junction. The session's incremental solver processes these constraints, keeping seed positions accurate for the final solve.
|
|
1623
|
-
- `get start()` — PointId of the route's start point.
|
|
1624
|
-
- `get end()` — PointId of the current cursor (route's end).
|
|
1625
|
-
- `startOf()` — Get the start point of a segment.
|
|
1626
|
-
- `endOf()` — Get the end point of a segment.
|
|
1627
|
-
|
|
1628
|
-
### `FlatPart`
|
|
1615
|
+
### `SurfacePattern`
|
|
1629
1616
|
|
|
1630
1617
|
**Properties:**
|
|
1631
1618
|
|
|
1632
1619
|
| Property | Type | Description |
|
|
1633
1620
|
|----------|------|-------------|
|
|
1634
|
-
| `
|
|
1635
|
-
| `
|
|
1636
|
-
| `options` | `FlatPartOptions` | — |
|
|
1637
|
-
|
|
1638
|
-
**Methods:**
|
|
1639
|
-
|
|
1640
|
-
- `get edges()` — All edges as a read-only map.
|
|
1641
|
-
- `edge()` — Look up a named edge. Throws if the edge does not exist.
|
|
1642
|
-
- `edgeNames()` — All edge names on this part.
|
|
1643
|
-
- `get partNumber()` — get partNumber(): number
|
|
1644
|
-
- `get joints()` — get joints(): readonly JointRecord[]
|
|
1645
|
-
- `get quantity()` — get quantity(): number
|
|
1646
|
-
- `addGeometry()` — Add geometry (e.g. protruding tabs) to the part profile.
|
|
1647
|
-
- `subtractGeometry()` — Subtract geometry (e.g. slot cuts) from the part profile.
|
|
1648
|
-
- `addJoint()` — Record a joint connection for assembly preview.
|
|
1649
|
-
- `profile()` — Final 2D profile with joints and optional kerf compensation.
|
|
1650
|
-
- `solid()` — 3D solid — extrude the profile by material thickness.
|
|
1651
|
-
|
|
1652
|
-
### `LaserKit`
|
|
1653
|
-
|
|
1654
|
-
**Methods:**
|
|
1655
|
-
|
|
1656
|
-
- `get kerf()` — Laser kerf in mm.
|
|
1657
|
-
- `get parts()` — All registered parts (flat, in insertion order).
|
|
1658
|
-
- `get material()` — Default material label.
|
|
1659
|
-
- `get sheetWidth()` — Stock sheet width in mm.
|
|
1660
|
-
- `get sheetHeight()` — Stock sheet height in mm.
|
|
1661
|
-
- `addPart()` — Register a flat part with this kit. Assigns a sequential part number and records the quantity.
|
|
1662
|
-
- `cutSheets()` — Generate nested cut sheets using guillotine bin-packing.
|
|
1663
|
-
- `bom()` — Bill of materials listing every part with dimensions.
|
|
1664
|
-
- `partSvgs()` — Individual SVG string for each part profile, keyed by part name.
|
|
1665
|
-
- `inventorySvg()` — Combined inventory SVG showing all parts in a labeled grid.
|
|
1666
|
-
- `assemblyPreview()` — 3D fold-up preview of the assembled kit.
|
|
1667
|
-
- `assemblyInstructions()` — Step-by-step assembly instructions.
|
|
1668
|
-
- `formatInstructions()` — Human-readable assembly instructions text.
|
|
1621
|
+
| `body` | `string` | Function body: receives (u, v) in surface mm, returns height displacement. |
|
|
1622
|
+
| `constants` | `Record<string, number>` | Named constants injected into the function. |
|
|
1669
1623
|
|
|
1670
1624
|
---
|
|
1671
1625
|
|
|
@@ -1675,49 +1629,48 @@ Core 3D solid shape. All operations are immutable and return new shapes. Support
|
|
|
1675
1629
|
|
|
1676
1630
|
### `verify`
|
|
1677
1631
|
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
- `
|
|
1681
|
-
- `
|
|
1682
|
-
- `
|
|
1683
|
-
- `
|
|
1684
|
-
- `
|
|
1685
|
-
- `
|
|
1686
|
-
- `
|
|
1687
|
-
- `
|
|
1688
|
-
- `
|
|
1689
|
-
- `
|
|
1690
|
-
- `
|
|
1691
|
-
- `
|
|
1692
|
-
- `
|
|
1693
|
-
- `
|
|
1694
|
-
- `
|
|
1695
|
-
- `
|
|
1696
|
-
- `
|
|
1697
|
-
- `areaApprox()` — Check that a shape's surface area is approximately equal to expected (mm²).
|
|
1698
|
-
- `boundingBoxSize()` — Check that a shape's bounding box has approximately the given size.
|
|
1632
|
+
- `that(label: string, check: () => boolean, message?: string): void` — Custom predicate check.
|
|
1633
|
+
- `equal(label: string, actual: number, expected: number, tolerance?: number, message?: string): void` — Check that two numbers are approximately equal (within tolerance).
|
|
1634
|
+
- `notEqual(label: string, actual: number, unexpected: number, tolerance?: number, message?: string): void` — Check that two numbers are NOT equal (differ by more than tolerance).
|
|
1635
|
+
- `greaterThan(label: string, actual: number, min: number, message?: string): void` — Check that actual > min.
|
|
1636
|
+
- `lessThan(label: string, actual: number, max: number, message?: string): void` — Check that actual < max.
|
|
1637
|
+
- `inRange(label: string, actual: number, min: number, max: number, message?: string): void` — Check that min <= actual <= max.
|
|
1638
|
+
- `centersCoincide(label: string, a: ShapeLike, b: ShapeLike, tolerance?: number): void` — Check that the bounding-box centers of two shapes coincide within tolerance (mm).
|
|
1639
|
+
- `notColliding(label: string, a: ShapeLike, b: ShapeLike, searchLength?: number): void` — Check that two shapes do not collide (minGap > 0).
|
|
1640
|
+
- `minClearance(label: string, a: ShapeLike, b: ShapeLike, minGap: number, searchLength?: number): void` — Check that a minimum clearance gap exists between two shapes.
|
|
1641
|
+
- `parallel(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number): void` — Check that two face normals are parallel (within toleranceDeg degrees).
|
|
1642
|
+
- `perpendicular(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number): void` — Check that two face normals are perpendicular (within toleranceDeg degrees).
|
|
1643
|
+
- `coplanar(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number, toleranceMm?: number): void` — Check that a face is coplanar with (same plane as) another face, meaning they are parallel AND their centers lie on the same plane.
|
|
1644
|
+
- `faceAt(label: string, face: FaceRefLike, expectedPos: [ number` — Check that a face center lies at a specific position (within toleranceMm).
|
|
1645
|
+
- `sameDirection(label: string, faceA: FaceRefLike, faceB: FaceRefLike, toleranceDeg?: number): void` — Check that two face normals point in the same direction (not antiparallel). Stricter than parallel — both |angle| AND sign must match.
|
|
1646
|
+
- `isEmpty(label: string, shape: ShapeLike, message?: string): void` — Check that a shape is empty.
|
|
1647
|
+
- `notEmpty(label: string, shape: ShapeLike, message?: string): void` — Check that a shape is NOT empty.
|
|
1648
|
+
- `volumeApprox(label: string, shape: ShapeLike, expected: number, tolerance?: number): void` — Check that a shape's volume is approximately equal to expected (mm³).
|
|
1649
|
+
- `areaApprox(label: string, shape: ShapeLike, expected: number, tolerance?: number): void` — Check that a shape's surface area is approximately equal to expected (mm²).
|
|
1650
|
+
- `boundingBoxSize(label: string, shape: ShapeLike, expectedSize: [ number` — Check that a shape's bounding box has approximately the given size.
|
|
1699
1651
|
|
|
1700
1652
|
### `Constraint`
|
|
1701
1653
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
- `
|
|
1705
|
-
- `
|
|
1706
|
-
- `
|
|
1707
|
-
- `
|
|
1708
|
-
- `
|
|
1709
|
-
- `
|
|
1710
|
-
- `
|
|
1711
|
-
- `
|
|
1712
|
-
- `perpendicular()` — perpendicular(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): Constr
|
|
1713
|
-
- `length()` — length(builder: ConstrainedSketchBuilder, line: LineArg, value: number): Constra
|
|
1654
|
+
- `makeParallel(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): ConstrainedSketchBuilder` — Constrain two lines to be parallel.
|
|
1655
|
+
- `enforceAngle(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg, angleDeg: number): ConstrainedSketchBuilder` — Constrain the signed angle from line `a` to line `b`.
|
|
1656
|
+
- `horizontal(builder: ConstrainedSketchBuilder, line: LineArg): ConstrainedSketchBuilder` — Constrain a line to be horizontal.
|
|
1657
|
+
- `vertical(builder: ConstrainedSketchBuilder, line: LineArg): ConstrainedSketchBuilder` — Constrain a line to be vertical.
|
|
1658
|
+
- `equalLength(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): ConstrainedSketchBuilder` — Constrain two lines to have equal length.
|
|
1659
|
+
- `distance(builder: ConstrainedSketchBuilder, a: PointArg, b: PointArg, value: number): ConstrainedSketchBuilder` — Constrain the distance between two points.
|
|
1660
|
+
- `fix(builder: ConstrainedSketchBuilder, pt: PointArg, x: number, y: number): ConstrainedSketchBuilder` — Fix a point at a specific coordinate.
|
|
1661
|
+
- `coincident(builder: ConstrainedSketchBuilder, a: PointArg, b: PointArg): ConstrainedSketchBuilder` — Constrain two points to occupy the same location.
|
|
1662
|
+
- `perpendicular(builder: ConstrainedSketchBuilder, a: LineArg, b: LineArg): ConstrainedSketchBuilder` — Constrain two lines to be perpendicular.
|
|
1663
|
+
- `length(builder: ConstrainedSketchBuilder, line: LineArg, value: number): ConstrainedSketchBuilder` — Constrain the length of a line.
|
|
1714
1664
|
|
|
1715
1665
|
### `Points`
|
|
1716
1666
|
|
|
1717
|
-
|
|
1667
|
+
- `distance(a: Vec3, b: Vec3): number` — Euclidean distance between two 3D points.
|
|
1668
|
+
- `midpoint(a: Vec3, b: Vec3): Vec3` — Center point between two 3D points.
|
|
1669
|
+
- `lerp(a: Vec3, b: Vec3, t: number): Vec3` — Linearly interpolate between two 3D points. t=0 returns a, t=1 returns b.
|
|
1670
|
+
- `direction(a: Vec3, b: Vec3): Vec3` — Unit direction vector from a to b. Throws if a and b are the same point.
|
|
1671
|
+
- `offset(point: Vec3, dir: Vec3, amount: number): Vec3` — Move a point along a direction vector by a given amount.
|
|
1672
|
+
- `polar(length: number, angleDeg: number, from?: [ number, number ]): [ number, number ]` — Compute a 2D point at distance and angle (degrees) from an optional origin.
|
|
1673
|
+
|
|
1674
|
+
### `connector`
|
|
1718
1675
|
|
|
1719
|
-
|
|
1720
|
-
- `midpoint()` — Center point between two 3D points.
|
|
1721
|
-
- `lerp()` — Linearly interpolate between two 3D points. t=0 returns a, t=1 returns b.
|
|
1722
|
-
- `direction()` — Unit direction vector from a to b. Throws if a and b are the same point.
|
|
1723
|
-
- `offset()` — Move a point along a direction vector by a given amount.
|
|
1676
|
+
Connector factory. Create attachment points: `connector({...})`, `connector.male(type, {...})`, etc.
|