forgecad 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -11
- package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-DAu1C1ST.js} +250 -151
- package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
- package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-Gc_BCdqC.js} +269 -143
- package/dist/assets/EditorApp-D9bJvtf7.js +11338 -0
- package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-DG1-oUSV.css} +459 -87
- package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-CEO8XbV8.js} +2 -4
- package/dist/assets/LandingPage-CdCuEOdC.js +451 -0
- package/dist/assets/PricingPage-BSrxu6d7.js +232 -0
- package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-FUCSIRq6.js} +129 -5
- package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-KoR0SNKq.js} +6770 -2914
- package/dist/assets/{index-2hfs_ub0.css → index-CyVd1D4D.css} +227 -53
- package/dist/assets/{Viewport-CoB46f5R.js → index-wTEK39at.js} +31385 -6439
- package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
- package/dist/assets/{manifold-CqNMHHKO.js → manifold-B1sGWdYk.js} +4 -3
- package/dist/assets/{manifold-Cce9wRFz.js → manifold-D7o0N50J.js} +1 -1
- package/dist/assets/{manifold-D6BeHIOo.js → manifold-G5sBaXzi.js} +1 -1
- package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-DYcRHhv9.js} +6798 -3341
- package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
- package/dist/docs-raw/generated/assembly.md +691 -112
- package/dist/docs-raw/generated/concepts.md +1225 -1400
- package/dist/docs-raw/generated/core.md +464 -1412
- package/dist/docs-raw/generated/curves.md +593 -117
- package/dist/docs-raw/generated/lib.md +38 -748
- package/dist/docs-raw/generated/output.md +139 -245
- package/dist/docs-raw/generated/sheet-metal.md +473 -21
- package/dist/docs-raw/generated/sketch.md +553 -349
- package/dist/docs-raw/generated/viewport.md +345 -303
- package/dist/docs-raw/generated/wood.md +104 -0
- package/dist/index.html +2 -2
- package/dist/sitemap.xml +6 -6
- package/dist-cli/chunk-PZ5AY32C.js +10 -0
- package/dist-cli/chunk-PZ5AY32C.js.map +1 -0
- package/dist-cli/forgecad.js +9435 -5407
- package/dist-cli/forgecad.js.map +1 -0
- package/dist-cli/solver-FV7TJZGI.js +365 -0
- package/dist-cli/solver-FV7TJZGI.js.map +1 -0
- package/dist-skill/CONTEXT.md +3186 -7145
- package/dist-skill/SKILL-dev.md +21 -63
- package/dist-skill/SKILL.md +12 -56
- package/dist-skill/docs/API/core/concepts.md +16 -98
- package/dist-skill/docs/CLI/export.md +91 -0
- package/dist-skill/docs/CLI/projects.md +107 -0
- package/dist-skill/docs/CLI/studio_publishing.md +52 -0
- package/dist-skill/docs/CLI/validation.md +66 -0
- package/dist-skill/docs/generated/assembly.md +691 -112
- package/dist-skill/docs/generated/core.md +464 -1412
- package/dist-skill/docs/generated/curves.md +593 -117
- package/dist-skill/docs/generated/lib.md +38 -748
- package/dist-skill/docs/generated/output.md +139 -245
- package/dist-skill/docs/generated/sheet-metal.md +473 -21
- package/dist-skill/docs/generated/sketch.md +553 -349
- package/dist-skill/docs/generated/viewport.md +345 -303
- 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/modeling-recipes.md +22 -195
- package/dist-skill/docs/guides/positioning.md +88 -147
- package/dist-skill/docs-dev/API/core/concepts.md +51 -0
- package/dist-skill/docs-dev/API/core/sdf-advanced.md +92 -0
- package/dist-skill/docs-dev/API/core/sdf-primitives.md +58 -0
- package/dist-skill/docs-dev/API/core/sdf-workflow.md +42 -0
- package/dist-skill/docs-dev/CLI/export.md +91 -0
- package/dist-skill/docs-dev/CLI/projects.md +107 -0
- package/dist-skill/docs-dev/CLI/studio_publishing.md +52 -0
- package/dist-skill/docs-dev/CLI/validation.md +66 -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 +1 -3
- package/dist-skill/docs-dev/generated/assembly.md +771 -0
- package/dist-skill/docs-dev/generated/core.md +775 -0
- package/dist-skill/docs-dev/generated/curves.md +688 -0
- package/dist-skill/docs-dev/generated/lib.md +50 -0
- package/dist-skill/docs-dev/generated/output.md +234 -0
- package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
- package/dist-skill/docs-dev/generated/sketch.md +801 -0
- package/dist-skill/docs-dev/generated/viewport.md +486 -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/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 +5 -5
- package/examples/api/boolean-operations.forge.js +3 -3
- package/examples/api/bounding-box-visualizer.forge.js +2 -2
- package/examples/api/clone-duplicate.forge.js +1 -1
- package/examples/api/colors-union-vs-array.forge.js +6 -6
- package/examples/api/connector-assembly.forge.js +4 -4
- package/examples/api/connector-basics.forge.js +2 -2
- package/examples/api/extrude-options.forge.js +4 -10
- package/examples/api/feature-created-faces.forge.js +6 -10
- package/examples/api/fillet-showcase.forge.js +1 -1
- package/examples/api/folded-service-panel-cover.forge.js +2 -2
- package/examples/api/group-test.forge.js +1 -1
- 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 +1 -1
- package/examples/api/pointAlong-orientation.forge.js +1 -1
- package/examples/api/profile-2020-b-slot6.forge.js +0 -1
- 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/transition-curves.forge.js +1 -1
- 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/experiments/drone-arm.forge.js +53 -0
- package/examples/furniture/adjustable-table.forge.js +2 -2
- package/examples/furniture/bathroom.forge.js +11 -11
- package/examples/furniture/chair.forge.js +1 -1
- package/examples/generative/crystal-growth.forge.js +2 -2
- package/examples/generative/frost-spires.forge.js +3 -3
- package/examples/generative/golden-spiral-tower.forge.js +3 -3
- package/examples/mechanical/3d-printer.forge.js +28 -28
- package/examples/mechanical/5-finger-robot-hand.forge.js +15 -15
- package/examples/mechanical/airplane-propeller.forge.js +2 -2
- package/examples/mechanical/fillet-enclosure.forge.js +1 -1
- package/examples/mechanical/headphone-hanger-v2.forge.js +2 -2
- package/examples/mechanical/robot_hand.forge.js +15 -15
- package/examples/mechanical/robot_hand_2.forge.js +9 -9
- package/examples/products/bottle.forge.js +1 -1
- package/examples/products/chess-set.forge.js +19 -19
- package/examples/products/classical-piano.forge.js +11 -11
- package/examples/products/clock.forge.js +12 -12
- package/examples/products/iphone.forge.js +8 -8
- package/examples/products/laptop.forge.js +15 -15
- package/examples/products/liquid-soap-dispenser.forge.js +18 -18
- package/examples/products/origami-fish.forge.js +8 -6
- package/examples/products/spiderman-cake.forge.js +4 -4
- package/examples/toolbox/bolted-joint.forge.js +2 -2
- package/package.json +7 -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/docs-raw/CLI.md +0 -865
- 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/CLI.md +0 -865
- 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,85 +5,78 @@ skill-order: 100
|
|
|
5
5
|
|
|
6
6
|
# Assembly 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
|
Kinematic assemblies, joints, couplings, and robot export.
|
|
11
9
|
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [Assembly & Joints](#assembly-joints) — `bomToCsv`, `assembly`, `joint`
|
|
13
|
+
- [Assembly](#assembly) — Structure, Joints, Solving
|
|
14
|
+
- [ImportedAssembly](#importedassembly)
|
|
15
|
+
- [SolvedAssembly](#solvedassembly)
|
|
16
|
+
- [MateBuilder](#matebuilder)
|
|
17
|
+
|
|
12
18
|
## Functions
|
|
13
19
|
|
|
14
20
|
### Assembly & Joints
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
#### `bomToCsv()` — Convert an array of BOM rows into a CSV string.
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
Produces a CSV with columns: `part`, `qty`, `material`, `process`, `tolerance`, `notes`. String values are quoted and internal double-quotes are escaped. Prefer calling `solvedAssembly.bomCsv()` directly — this function is exposed for custom BOM processing.
|
|
19
25
|
|
|
20
26
|
```ts
|
|
21
27
|
bomToCsv(rows: BomRow[]): string
|
|
22
28
|
```
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
**`BomRow`**: `part: string`, `qty: number`, `material?: string`, `process?: string`, `tolerance?: string`, `notes?: string`, `metadata?: PartMetadata`
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
**`PartMetadata`**: `material?: string`, `process?: string`, `tolerance?: string`, `qty?: number`, `notes?: string`, `densityKgM3?: number`, `massKg?: number`
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
interface BomRow {
|
|
30
|
-
part: string;
|
|
31
|
-
qty: number;
|
|
32
|
-
material?: string;
|
|
33
|
-
process?: string;
|
|
34
|
-
tolerance?: string;
|
|
35
|
-
notes?: string;
|
|
36
|
-
metadata?: PartMetadata;
|
|
37
|
-
}
|
|
38
|
-
```
|
|
34
|
+
#### `assembly()` — Create an assembly container with named parts and joints for kinematic mechanisms.
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
An assembly models a mechanism as a directed graph of parts connected by joints. Parts are the nodes; joints are directed edges from parent to child. The graph must be a forest (no cycles). Root parts (those with no incoming joint) are anchored to world space.
|
|
41
37
|
|
|
42
|
-
|
|
38
|
+
Three joint types are supported: `'revolute'` (hinge), `'prismatic'` (slider), and `'fixed'` (rigid attachment). Use `addPart()` to add geometry, `addJoint()` (or the shorthands `addRevolute()`, `addPrismatic()`, `addFixed()`) to connect parts, and `solve()` to compute world-space positions at a given joint state.
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
interface PartMetadata {
|
|
46
|
-
material?: string;
|
|
47
|
-
process?: string;
|
|
48
|
-
tolerance?: string;
|
|
49
|
-
qty?: number;
|
|
50
|
-
notes?: string;
|
|
51
|
-
densityKgM3?: number;
|
|
52
|
-
massKg?: number;
|
|
53
|
-
}
|
|
54
|
-
```
|
|
40
|
+
The higher-level `connect()` API uses declared **connectors** to compute joint frames automatically. The `match()` API uses typed connectors (with gender and type metadata) for automatic compatibility validation and joint creation.
|
|
55
41
|
|
|
56
|
-
|
|
42
|
+
For multi-file assemblies, a file that returns an `Assembly` is importable via [`require()`](/docs/core#require) and yields an `ImportedAssembly`. Use `mergeInto()` to flatten a sub-assembly into a parent assembly.
|
|
57
43
|
|
|
58
|
-
|
|
44
|
+
```ts
|
|
45
|
+
const mech = assembly("Arm")
|
|
46
|
+
.addPart("base", box(80, 80, 20, true), {
|
|
47
|
+
metadata: { material: "PETG", process: "FDM", qty: 1 },
|
|
48
|
+
})
|
|
49
|
+
.addPart("link", box(140, 24, 24).translate(0, -12, -12))
|
|
50
|
+
.addRevolute("shoulder", "base", "link", {
|
|
51
|
+
axis: [0, 1, 0],
|
|
52
|
+
min: -30, max: 120, default: 25,
|
|
53
|
+
frame: Transform.identity().translate(0, 0, 20),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return mech; // auto-solved at defaults, renders all parts
|
|
57
|
+
```
|
|
59
58
|
|
|
60
59
|
```ts
|
|
61
60
|
assembly(name?: string): Assembly
|
|
62
61
|
```
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
#### `joint()` — Create a revolute joint that auto-generates a parameter slider and rotates the shape.
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
This is a convenience wrapper for single-shape, single-joint use cases. It calls [`param()`](/docs/core#param) to create a named angle slider, then applies `rotateAroundAxis()` to the shape. Use the full `Assembly` API for mechanisms with multiple parts and joints.
|
|
67
66
|
|
|
68
67
|
```ts
|
|
69
|
-
joint(
|
|
68
|
+
const arm = joint("Shoulder", armShape, [0, 0, 20], {
|
|
69
|
+
axis: [0, 1, 0],
|
|
70
|
+
min: -30, max: 120, default: 25,
|
|
71
|
+
});
|
|
72
|
+
return arm;
|
|
70
73
|
```
|
|
71
74
|
|
|
72
|
-
Create a revolute (hinge) joint. Auto-creates a param slider and rotates the shape.
|
|
73
|
-
|
|
74
|
-
<details><summary><code>RevoluteJointOpts</code></summary>
|
|
75
|
-
|
|
76
75
|
```ts
|
|
77
|
-
|
|
78
|
-
min?: number;
|
|
79
|
-
max?: number;
|
|
80
|
-
default?: number;
|
|
81
|
-
unit?: string;
|
|
82
|
-
reverse?: boolean;
|
|
83
|
-
}
|
|
76
|
+
joint(name: string, shape: Shape, pivot: [ number, number, number ], opts?: RevoluteJointOpts): Shape
|
|
84
77
|
```
|
|
85
78
|
|
|
86
|
-
|
|
79
|
+
`RevoluteJointOpts`: `{ min?: number, max?: number, default?: number, unit?: string, reverse?: boolean }`
|
|
87
80
|
|
|
88
81
|
---
|
|
89
82
|
|
|
@@ -91,61 +84,507 @@ interface RevoluteJointOpts {
|
|
|
91
84
|
|
|
92
85
|
### `Assembly`
|
|
93
86
|
|
|
87
|
+
Container for a kinematic mechanism made up of named parts and joints.
|
|
88
|
+
|
|
89
|
+
An assembly is a directed graph where **parts** are nodes and **joints** are directed edges from parent to child. The graph must be a forest (one or more trees with no cycles). Root parts (no incoming joint) are fixed to world space.
|
|
90
|
+
|
|
91
|
+
Each joint carries a `frame` transform (from the parent part frame to the joint's zero-state frame) and a motion formula:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
childWorld = parentWorld × frame × motion(value) × childBase
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Three joint types are supported:
|
|
98
|
+
|
|
99
|
+
- **revolute** — rotates the child around an axis by `value` degrees
|
|
100
|
+
- **prismatic** — translates the child along an axis by `value` mm
|
|
101
|
+
- **fixed** — no motion; rigidly attaches the child at `frame`
|
|
102
|
+
|
|
103
|
+
**Quick start**
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const mech = assembly("Arm")
|
|
107
|
+
.addPart("base", box(80, 80, 20, true))
|
|
108
|
+
.addPart("link", box(140, 24, 24).translate(0, -12, -12))
|
|
109
|
+
.addJoint("shoulder", "revolute", "base", "link", {
|
|
110
|
+
axis: [0, 1, 0],
|
|
111
|
+
min: -30, max: 120, default: 25,
|
|
112
|
+
frame: Transform.identity().translate(0, 0, 20),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return mech; // auto-solved at defaults
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Returning an unsolved `Assembly` auto-solves at default joint values. Return a `SolvedAssembly` directly for a specific pose:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
return mech.solve({ shoulder: 60 });
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Return types**
|
|
125
|
+
|
|
126
|
+
| Return value | Standalone | `require()` result type | |---|---|---| | `Assembly` (unsolved) | yes | `ImportedAssembly` | | `SolvedAssembly` | yes | `SolvedAssembly` |
|
|
127
|
+
|
|
94
128
|
**Properties:**
|
|
95
129
|
|
|
96
130
|
| Property | Type | Description |
|
|
97
131
|
|----------|------|-------------|
|
|
98
132
|
| `name` | `string` | — |
|
|
99
133
|
|
|
100
|
-
**
|
|
134
|
+
**Solving**
|
|
135
|
+
|
|
136
|
+
#### `solve()` — Solve the assembly at the given joint state and return positioned parts.
|
|
137
|
+
|
|
138
|
+
Performs a depth-first traversal of the joint graph. Each joint's value is taken from `state`, falling back to `defaultValue`. Coupled joints compute their value from source joints. Values outside `[min, max]` are clamped (a warning is added to `SolvedAssembly.warnings()`).
|
|
139
|
+
|
|
140
|
+
If mate constraints were registered via `mate()`, the solver runs a pre-pass to derive base transforms, then the kinematic DFS applies joints on top of those positions.
|
|
141
|
+
|
|
142
|
+
**Pitfall — [`jointsView`](/docs/viewport#jointsview) double-rotation:** When calling `toJointsView()`, always solve at the rest pose (all joint values = 0 or default). Solving at a non-zero angle and then animating will double-rotate parts. Use the `defaults` option on `toJointsView()` to set the initial display angle instead.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const solved = mech.solve({ shoulder: 45, elbow: -20 });
|
|
146
|
+
return solved.toGroup();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
solve(state?: JointState): SolvedAssembly
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Other**
|
|
101
154
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
155
|
+
#### `usedPortRefs()` — Connector refs (e.g. "PartName.connectorName") consumed by connect/match calls.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
get usedPortRefs(): ReadonlySet<string>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `mate()` — Register mate constraints between parts. Constraints are solved during `solve()` to derive part positions and explode hints. Part references use "partName:featureName" format.
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
mate(fn: (m: MateBuilder) => void): Assembly
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### `withReferences()` — Attach named placement reference points to this assembly. These are surfaced automatically on the ImportedAssembly when this file is imported via require(), so consumers can use placeReference() without re-declaring them. Returns `this` for chaining.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
withReferences(refs: Pick<PlacementReferenceInput, "points">): Assembly
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### `withConnectors()` — Attach named connectors to a specific part or the assembly as a whole.
|
|
174
|
+
|
|
175
|
+
Connectors declared this way are in the part's local coordinate system. They are captured automatically if the incoming [`Shape`](/docs/core#shape) already has connectors via `shape.withConnectors(...)`, but you can also add or override connectors after the fact with this method.
|
|
176
|
+
|
|
177
|
+
Use the single-argument overload to attach assembly-level connectors — these are exposed when this assembly is imported as a sub-assembly.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
withConnectors(partName: string, connectors: Record<string, ConnectorInput>): Assembly
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### `withPorts()` — Backward-compatible alias for `withConnectors()`.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
withPorts(partNameOrPorts: string | Record<string, PortInput>, maybePorts?: Record<string, PortInput>): Assembly
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### `getConnectors()` — Get connectors declared on a part in part-local space.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
getConnectors(partName: string): PortMap
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### `getPorts()` — Backward-compatible alias for `getConnectors()`.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
getPorts(partName: string): PortMap
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### `getPort()` — Parse a "PartName.connectorName" reference and return the resolved connector. Throws descriptive errors if the part or connector doesn't exist.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
getPort(ref: string): { partName: string; portName: string; port: PortDef; }
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### `addFrame()` — Add a virtual reference frame (no geometry) to the assembly graph.
|
|
208
|
+
|
|
209
|
+
Useful when you need a named pivot point or coordinate frame that has no visual geometry. Acts like a zero-volume part and can be connected to other parts via joints.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
addFrame(name: string, options?: PartOptions): Assembly
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### `addPart()` — Add a named part to the assembly.
|
|
216
|
+
|
|
217
|
+
Connectors declared on the part (via `withConnectors()`) are captured automatically. Parts are positioned at world origin by default unless a `transform` is provided in `options`. For root parts (no incoming joint), `transform` is their final world position.
|
|
218
|
+
|
|
219
|
+
When a part is a [`ShapeGroup`](/docs/core#shapegroup), name the group children explicitly to get readable viewport labels (e.g. `"Base Assembly.Body"` instead of `"Base Assembly.1"`):
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const housing = group(
|
|
223
|
+
{ name: "Body", shape: body },
|
|
224
|
+
{ name: "Lid", shape: lid },
|
|
225
|
+
);
|
|
226
|
+
assembly.addPart("Base Assembly", housing);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
addPart(name: string, part: AssemblyPart, options?: PartOptions): Assembly
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### `addJoint()` — Add a kinematic joint between a parent and child part.
|
|
234
|
+
|
|
235
|
+
`frame` is a transform from the **parent part frame** to the **joint frame at zero state**. The child's world position is computed as:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
childWorld = parentWorld × frame × motion(value) × childBase
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
For revolute joints `value` is in degrees; for prismatic joints `value` is in mm. Coupled joints (see `addJointCoupling`) ignore the `state` value passed to `solve()` and compute their value from source joints.
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
addJoint(name: string, type: JointType, parent: string, child: string, options?: JointOptions): Assembly
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### `addRevolute()` — Shorthand for `addJoint(name, 'revolute', parent, child, options)`.
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
addRevolute(name: string, parent: string, child: string, options?: JointOptions): Assembly
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### `addPrismatic()` — Shorthand for `addJoint(name, 'prismatic', parent, child, options)`.
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
addPrismatic(name: string, parent: string, child: string, options?: JointOptions): Assembly
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### `addFixed()` — Shorthand for `addJoint(name, 'fixed', parent, child, options)`.
|
|
260
|
+
|
|
261
|
+
Fixed joints rigidly attach a child part to its parent at `frame` with no motion. Before calling `mergeInto()`, use `addFixed()` to collapse multiple root parts into a single root.
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
addFixed(name: string, parent: string, child: string, options?: JointOptions): Assembly
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### `connect()` — Connect two parts by aligning their declared connectors, automatically computing frame and axis.
|
|
268
|
+
|
|
269
|
+
Connector references use `"PartName.connectorName"` format. The system aligns connector origins (child connector lands exactly on parent connector) and derives the joint frame and axis from the connector geometry — no manual `frame` or `axis` math needed.
|
|
270
|
+
|
|
271
|
+
The joint type is inferred from the connector's `kind` field if not specified in `options`. Use `flip: true` for mirrored parts whose connector axis is reflected.
|
|
272
|
+
|
|
273
|
+
When connectors are defined with `start`/`end`, you can control which point on each connector meets via `align` / `parentAlign` / `childAlign` (`'start'`, `'middle'`, `'end'`).
|
|
274
|
+
|
|
275
|
+
Use `connect()` when connector origins must physically coincide (flange-to-flange, bolt-into-bore). For mechanisms where parts share an axis but are deliberately spaced apart, use `addRevolute()` with pre-positioned parts instead.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
const mech = assembly("Arm")
|
|
279
|
+
.addPart("Base", base)
|
|
280
|
+
.addPart("Link", link)
|
|
281
|
+
.connect("Base.top", "Link.shoulder", {
|
|
282
|
+
as: "J1",
|
|
283
|
+
min: -90, max: 90, default: 0,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
return mech.solve({ J1: 45 }).toGroup();
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
connect(parentPortRef: string, childPortRef: string, options?: ConnectOptions): Assembly
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### `match()` — Auto-create a joint by matching typed connectors between two parts.
|
|
294
|
+
|
|
295
|
+
Connectors are ports with a `connectorType` string and a `gender` (`'male'`, `'female'`, or `'neutral'`). `match()` validates type and gender compatibility (use `{ force: true }` to skip validation) and creates the joint automatically from the connector's `kind` metadata.
|
|
296
|
+
|
|
297
|
+
The `pairs` map is `{ childConnector: parentConnector }`. The first pair drives joint creation; additional pairs are validated but do not create additional joints (they constrain the same rigid connection).
|
|
298
|
+
|
|
299
|
+
Define connectors on shapes with `shape.withConnectors(...)`:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
const door = doorShape.withConnectors({
|
|
303
|
+
hinge_top: connector.male("hinge", { origin: [0, 0, 90], axis: [0, 0, 1] }),
|
|
304
|
+
hinge_bottom: connector.male("hinge", { origin: [0, 0, 10], axis: [0, 0, 1] }),
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Then match in the assembly:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
const mech = assembly("Door")
|
|
312
|
+
.addPart("Frame", frame)
|
|
313
|
+
.addPart("Door", door)
|
|
314
|
+
.match("Door", "Frame", { hinge_top: "hinge_top", hinge_bottom: "hinge_bottom" });
|
|
315
|
+
// Revolute connectors → auto-creates revolute joint. No manual addRevolute needed.
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
match(childPartName: string, parentPartName: string, pairs: Record<string, string>, options?: MatchToOptions & { as?: string; }): Assembly
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### `addJointCoupling()` — Link a joint's value to a linear combination of other joint values.
|
|
323
|
+
|
|
324
|
+
The driven joint's value is computed as:
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
driven = offset + Σ(ratio_i × source_i)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Coupled joints ignore any value passed in `solve(state)` — a warning is emitted if you try to override one. Coupling cycles are rejected. You cannot sweep a coupled joint directly; sweep one of its source joints instead.
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
assembly
|
|
334
|
+
.addRevolute("Steering", "Base", "Turret", { axis: [0, 0, 1] })
|
|
335
|
+
.addRevolute("WheelDrive", "Turret", "Wheel", { axis: [1, 0, 0] })
|
|
336
|
+
.addRevolute("TopGear", "Base", "TopInput", { axis: [0, 0, 1] })
|
|
337
|
+
.addJointCoupling("TopGear", {
|
|
338
|
+
terms: [
|
|
339
|
+
{ joint: "Steering", ratio: 1 },
|
|
340
|
+
{ joint: "WheelDrive", ratio: 20 / 14 },
|
|
341
|
+
],
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
addJointCoupling(jointName: string, options: JointCouplingOptions): Assembly
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### `addGearCoupling()` — Link two revolute joints via a gear ratio.
|
|
350
|
+
|
|
351
|
+
Choose exactly one ratio source:
|
|
352
|
+
|
|
353
|
+
- `ratio` — explicit numeric ratio (driven/driver, negative for external mesh)
|
|
354
|
+
- `pair` — a `GearRatioLike` from `lib.gearPair`, `lib.bevelGearPair`, etc. (uses `pair.jointRatio`)
|
|
355
|
+
- `driverTeeth` + `drivenTeeth` — auto-computes ratio; use `mesh` to control sign (`'external'` = negative/opposite rotation, `'internal'` = positive, `'bevel'`/`'face'` = negative)
|
|
356
|
+
|
|
357
|
+
When `pair` carries a `phaseDeg`, it is auto-applied as the coupling `offset` to align teeth correctly. Override with `offset: 0` if gear shapes already have the phase baked in.
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
const pair = lib.gearPair({ pinion: { module: 1.25, teeth: 14 }, gear: { module: 1.25, teeth: 42 } });
|
|
361
|
+
assembly
|
|
362
|
+
.addRevolute("Pinion", "Base", "PinionPart", { axis: [0, 0, 1] })
|
|
363
|
+
.addRevolute("Driven", "Base", "GearPart", { axis: [0, 0, 1] })
|
|
364
|
+
.addGearCoupling("Driven", "Pinion", { pair });
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
addGearCoupling(drivenJointName: string, driverJointName: string, options?: GearCouplingOptions): Assembly
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### `sweepJoint()` — Sample a joint through its motion range, collecting collision data at each step.
|
|
372
|
+
|
|
373
|
+
Divides `[from, to]` into `steps` intervals (producing `steps + 1` frames). At each sample, the assembly is solved with the sweeping joint at that value and `baseState` for all others. Returns one `JointSweepFrame` per sample with the joint value, collision findings, and any solve warnings.
|
|
374
|
+
|
|
375
|
+
You cannot sweep a coupled joint — sweep one of its source joints instead.
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
const sweep = mech.sweepJoint("elbow", -10, 135, 12, { shoulder: 35 });
|
|
379
|
+
const hits = sweep.filter(frame => frame.collisions.length > 0);
|
|
380
|
+
console.log(`Collisions at ${hits.length} of ${sweep.length} poses`);
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
sweepJoint(jointName: string, from: number, to: number, steps: number, baseState?: JointState, collisionOptions?: CollisionOptions): JointSweepFrame[]
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### `toJointsView()` — Derive viewport joint controls from the assembly graph and register them.
|
|
388
|
+
|
|
389
|
+
Solves the assembly at rest (all joints = default), then converts each joint into a `JointViewInput` with world-space pivot and axis. Fixed joints become hidden zero-range revolute entries so attached parts follow their parent during animation. Joint couplings are forwarded to the viewport automatically.
|
|
390
|
+
|
|
391
|
+
**Critical pitfall:** Always call `toJointsView()` before solving for display. Then solve at the **rest pose** (no state overrides) and return that result. Do not solve at a non-zero angle when using `toJointsView()` — the viewport will apply the same rotation again, double-rotating the part.
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
mech.toJointsView({
|
|
395
|
+
defaults: { J1: 30 },
|
|
396
|
+
animations: [{
|
|
397
|
+
name: "Swing", duration: 2, loop: true,
|
|
398
|
+
keyframes: [{ values: { J1: -45 } }, { values: { J1: 45 } }, { values: { J1: -45 } }],
|
|
399
|
+
}],
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Solve at REST — viewport handles posing
|
|
403
|
+
return mech.solve().toGroup();
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
toJointsView(options?: ToJointsViewOptions): void
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
#### `describe()` — Return the serializable assembly definition used by solve/inspect pipelines.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
describe(): AssemblyDefinition
|
|
414
|
+
```
|
|
125
415
|
|
|
126
416
|
### `ImportedAssembly`
|
|
127
417
|
|
|
128
|
-
|
|
418
|
+
A wrapper around an imported `Assembly` that provides kinematic access and convenient transform helpers.
|
|
129
419
|
|
|
130
|
-
|
|
420
|
+
When a `.forge.js` file returns an unsolved `Assembly`, [`require()`](/docs/core#require) wraps it in an `ImportedAssembly`. This preserves the kinematic structure — you can call `solve()`, `sweepJoint()`, and `mergeInto()` — while also allowing convenience transforms that auto-solve at default values.
|
|
421
|
+
|
|
422
|
+
**Kinematic access**
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
const arm = require("./arm.forge.js");
|
|
426
|
+
|
|
427
|
+
const solved = arm.solve({ shoulder: 45 }); // full kinematic solve
|
|
428
|
+
const link = arm.part("Link", { shoulder: 60 }); // single part at state
|
|
429
|
+
const group = arm.toGroup({ shoulder: 45 }); // ShapeGroup with named children
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Convenience transforms** (auto-solve at defaults, return [`ShapeGroup`](/docs/core#shapegroup)):
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
const positioned = arm.rotateZ(-90).translate(0, -20, 50);
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Merging into a parent**
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
require("./arm.forge.js").mergeInto(robot, {
|
|
442
|
+
prefix: "Left Arm",
|
|
443
|
+
mountParent: "Chassis",
|
|
444
|
+
mountJoint: "leftMount",
|
|
445
|
+
mountOptions: { frame: Transform.identity().translate(-70, 0, 10) },
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
#### `assembly()` — The underlying Assembly — use for sweepJoint, addPart into parent, etc.
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
get assembly(): Assembly
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
#### `solve()` — Solve the assembly at the given joint state (defaults to each joint's default value).
|
|
131
456
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
457
|
+
```ts
|
|
458
|
+
solve(state?: JointState): SolvedAssembly
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
#### `part()` — Return a specific named part positioned at the given joint state, with any stored placement offset applied.
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
part(name: string, state?: JointState): AssemblyPart
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### `toGroup()` — Convert all assembly parts to a ShapeGroup with named children. Child names match the part names used in the assembly. Any stored placement offset and placement references are forwarded to the group.
|
|
468
|
+
|
|
469
|
+
```ts
|
|
470
|
+
toGroup(state?: JointState): ShapeGroup
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
#### `withReferences()` — Attach named placement reference points to this assembly. Points are simple 3D coordinates (relative to the assembly's own origin). Returns a new ImportedAssembly — does not mutate.
|
|
474
|
+
|
|
475
|
+
```ts
|
|
476
|
+
withReferences(refs: Pick<PlacementReferenceInput, "points">): ImportedAssembly
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
#### `referenceNames()` — List all attached placement reference names.
|
|
480
|
+
|
|
481
|
+
```ts
|
|
482
|
+
referenceNames(kind?: PlacementReferenceKind): string[]
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
#### `placeReference()` — Translate the assembly so the named reference point lands on `target`. Returns a new ImportedAssembly — does not mutate. All point refs are translated by the same delta.
|
|
486
|
+
|
|
487
|
+
```ts
|
|
488
|
+
placeReference(ref: string, target: [ number, number, number ], offset?: [ number, number, number ]): ImportedAssembly
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
#### `translate()` — Solve at defaults and return a translated ShapeGroup.
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
translate(x: number, y: number, z: number): ShapeGroup
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
#### `rotate()` — Solve at defaults and return a rotated ShapeGroup.
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
rotate(axis: [ number, number, number ], angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
#### `rotateX()` — Solve at defaults and return a ShapeGroup rotated around X.
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
rotateX(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### `rotateY()` — Solve at defaults and return a ShapeGroup rotated around Y.
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
rotateY(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### `rotateZ()` — Solve at defaults and return a ShapeGroup rotated around Z.
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
rotateZ(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
#### `scale()` — Solve at defaults and return a scaled ShapeGroup.
|
|
522
|
+
|
|
523
|
+
```ts
|
|
524
|
+
scale(v: number | [ number, number, number ]): ShapeGroup
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### `mirror()` — Solve at defaults and return a mirrored ShapeGroup.
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
mirror(normal: [ number, number, number ]): ShapeGroup
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
#### `color()` — Solve at defaults and return a colored ShapeGroup.
|
|
534
|
+
|
|
535
|
+
```ts
|
|
536
|
+
color(hex: string): ShapeGroup
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
#### `child()` — Solve at defaults, get a named child part from the resulting group.
|
|
540
|
+
|
|
541
|
+
```ts
|
|
542
|
+
child(name: string): Shape | Sketch | ShapeGroup
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### `mergeInto()` — Flatten this sub-assembly's parts and joints into `parent` and wire a mount joint.
|
|
546
|
+
|
|
547
|
+
All part and joint names from the sub-assembly are prefixed with `"${options.prefix}."` to avoid collisions. After the merge, sub-assembly joints are driven from the parent using the prefixed names:
|
|
548
|
+
|
|
549
|
+
```ts
|
|
550
|
+
parent.solve({ "Left Arm.shoulder": 45, "Right Arm.shoulder": -20 })
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Joint couplings inside the sub-assembly are preserved and rewritten with the prefix. Ports from sub-assembly parts are forwarded with the prefix.
|
|
554
|
+
|
|
555
|
+
The sub-assembly must have exactly one root part. If it has multiple roots, use `addFixed()` first to consolidate them before merging.
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
const robot = assembly("Robot").addPart("Chassis", chassis);
|
|
559
|
+
|
|
560
|
+
require("./arm.forge.js").mergeInto(robot, {
|
|
561
|
+
prefix: "Left Arm",
|
|
562
|
+
mountParent: "Chassis",
|
|
563
|
+
mountJoint: "leftMount",
|
|
564
|
+
mountOptions: { frame: Transform.identity().translate(-70, 0, 10) },
|
|
565
|
+
});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
mergeInto(parent: Assembly, options: MergeIntoOptions): Assembly
|
|
570
|
+
```
|
|
146
571
|
|
|
147
572
|
### `SolvedAssembly`
|
|
148
573
|
|
|
574
|
+
The result of solving an assembly at a specific joint state.
|
|
575
|
+
|
|
576
|
+
`SolvedAssembly` holds world-space transforms for every part at a given pose. Use `toGroup()` to convert all parts into a renderable [`ShapeGroup`](/docs/core#shapegroup), or use `getPart()` / `getTransform()` to inspect individual parts programmatically.
|
|
577
|
+
|
|
578
|
+
**Validation**
|
|
579
|
+
|
|
580
|
+
Call `collisionReport()` to detect overlapping parts, or `sweepJoint()` on the parent `Assembly` to check for interference across the joint's motion range.
|
|
581
|
+
|
|
582
|
+
```ts
|
|
583
|
+
const solved = mech.solve({ shoulder: 45, elbow: -20 });
|
|
584
|
+
console.log("Collisions", solved.collisionReport());
|
|
585
|
+
return solved.toGroup();
|
|
586
|
+
```
|
|
587
|
+
|
|
149
588
|
**Properties:**
|
|
150
589
|
|
|
151
590
|
| Property | Type | Description |
|
|
@@ -154,20 +593,106 @@ Wraps an imported Assembly, giving access to named parts and group conversion wi
|
|
|
154
593
|
|
|
155
594
|
**Methods:**
|
|
156
595
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
596
|
+
#### `warnings()` — Return any warnings generated during solve (clamped joints, unconverged mates, etc.).
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
warnings(): string[]
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
#### `getJointState()` — Return a snapshot of resolved joint values (after clamping and coupling).
|
|
603
|
+
|
|
604
|
+
```ts
|
|
605
|
+
getJointState(): JointState
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
#### `mateExplodeHints()` — Explode direction hints derived from mate constraints, or null if no mates.
|
|
609
|
+
|
|
610
|
+
```ts
|
|
611
|
+
get mateExplodeHints(): Record<string, { direction: Vec3; }> | null
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
#### `mateDof()` — Remaining degrees of freedom after mate constraints, or null if no mates.
|
|
615
|
+
|
|
616
|
+
```ts
|
|
617
|
+
get mateDof(): number | null
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
#### `mateConverged()` — Whether the mate constraint solver converged, or null if no mates.
|
|
621
|
+
|
|
622
|
+
```ts
|
|
623
|
+
get mateConverged(): boolean | null
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
#### `getTransform()` — Return the world-space [`Transform`](/docs/core#transform) for the named part at the solved pose.
|
|
627
|
+
|
|
628
|
+
```ts
|
|
629
|
+
getTransform(partName: string): Transform
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
#### `getPart()` — Return the named part already positioned at its solved world transform.
|
|
633
|
+
|
|
634
|
+
```ts
|
|
635
|
+
getPart(partName: string): AssemblyPart
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
#### `toGroup()` — Convert all solved parts into a [`ShapeGroup`](/docs/core#shapegroup) with named children.
|
|
639
|
+
|
|
640
|
+
Each part becomes a named child in the group, already positioned at its solved world transform. This is the primary method for rendering, passing to `show()`, or embedding the assembly into a parent model.
|
|
641
|
+
|
|
642
|
+
```ts
|
|
643
|
+
return mech.solve({ shoulder: 60 }).toGroup();
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
```ts
|
|
647
|
+
toGroup(): ShapeGroup
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
#### `toSceneObjects()` — Return an array of named scene objects for the viewport renderer.
|
|
651
|
+
|
|
652
|
+
Each part becomes `{ name, shape }` or `{ name, group: [...] }` if the part is a [`ShapeGroup`](/docs/core#shapegroup). Prefer `toGroup()` for most use cases. This method exists for advanced scene-graph control where you need access to the flat per-part array with metadata.
|
|
653
|
+
|
|
654
|
+
```ts
|
|
655
|
+
toSceneObjects(): Array<{ name: string; shape?: Shape; group?: Array<{ name: string; shape: Shape; }>; metadata?: PartMetadata; }>
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
#### `toScene()` — Backward-compatible alias for `toSceneObjects()`.
|
|
659
|
+
|
|
660
|
+
```ts
|
|
661
|
+
toScene(): Array<{ name: string; shape?: Shape; group?: Array<{ name: string; shape: Shape; }>; metadata?: PartMetadata; }>
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
#### [`bom()`](/docs/output#bom) — Generate a bill of materials for all parts in the solved assembly.
|
|
665
|
+
|
|
666
|
+
```ts
|
|
667
|
+
bom(): BomRow[]
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
#### `bomCsv()` — Generate a bill of materials as a CSV string.
|
|
671
|
+
|
|
672
|
+
```ts
|
|
673
|
+
bomCsv(): string
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
#### `collisionReport()` — Detect overlapping (colliding) part pairs in this solved pose.
|
|
677
|
+
|
|
678
|
+
Computes boolean intersections between all part pairs and returns findings where the overlap volume exceeds `minOverlapVolume` (default 0.1 mm³).
|
|
679
|
+
|
|
680
|
+
```ts
|
|
681
|
+
const solved = mech.solve({ shoulder: 35, elbow: 60 });
|
|
682
|
+
console.log("Collisions", solved.collisionReport());
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
```ts
|
|
686
|
+
collisionReport(options?: CollisionOptions): CollisionFinding[]
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
#### `minClearance()` — Compute the minimum gap (clearance) between two parts in this solved pose.
|
|
690
|
+
|
|
691
|
+
Returns `0` if the parts are touching or overlapping. Requires the Manifold backend. `searchLength` bounds the search radius in mm — increase it for widely separated parts.
|
|
692
|
+
|
|
693
|
+
```ts
|
|
694
|
+
minClearance(partA: string, partB: string, searchLength?: number): number
|
|
695
|
+
```
|
|
171
696
|
|
|
172
697
|
### `MateBuilder`
|
|
173
698
|
|
|
@@ -179,14 +704,68 @@ Wraps an imported Assembly, giving access to named parts and group conversion wi
|
|
|
179
704
|
|
|
180
705
|
**Methods:**
|
|
181
706
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
707
|
+
#### `flush()` — Constrain two faces so they stay flush.
|
|
708
|
+
|
|
709
|
+
```ts
|
|
710
|
+
flush(faceA: string, faceB: string): string
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
#### `align()` — Constrain two faces so their normals align.
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
align(faceA: string, faceB: string): string
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
#### `parallel()` — Constrain two faces so they remain parallel.
|
|
720
|
+
|
|
721
|
+
```ts
|
|
722
|
+
parallel(faceA: string, faceB: string): string
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
#### `faceDistance()` — Constrain the distance between two faces.
|
|
726
|
+
|
|
727
|
+
```ts
|
|
728
|
+
faceDistance(faceA: string, faceB: string, distance: number): string
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
#### `concentric()` — Constrain two axes to share the same center line.
|
|
732
|
+
|
|
733
|
+
```ts
|
|
734
|
+
concentric(axisA: string, axisB: string): string
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
#### `axisParallel()` — Constrain two axes to remain parallel.
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
axisParallel(axisA: string, axisB: string): string
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### `pointCoincident()` — Constrain two points to coincide.
|
|
744
|
+
|
|
745
|
+
```ts
|
|
746
|
+
pointCoincident(pointA: string, pointB: string): string
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
#### `pointOnFace()` — Constrain a point to lie on a face.
|
|
750
|
+
|
|
751
|
+
```ts
|
|
752
|
+
pointOnFace(point: string, face: string): string
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
#### `pointOnAxis()` — Constrain a point to lie on an axis.
|
|
756
|
+
|
|
757
|
+
```ts
|
|
758
|
+
pointOnAxis(point: string, axis: string): string
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### `angle()` — Constrain the angle between two faces.
|
|
762
|
+
|
|
763
|
+
```ts
|
|
764
|
+
angle(faceA: string, faceB: string, degrees: number): string
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### `totalEquations()` — Total constraint equations.
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
get totalEquations(): number
|
|
771
|
+
```
|