forgecad 0.9.16 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AdminPage-CXvls4-J.js → AdminPage-DcCnj0qo.js} +1 -1
- package/dist/assets/{BenchmarkPage-B27zk8xL.js → BenchmarkPage-BVEpJSVk.js} +1 -1
- package/dist/assets/{BlogPage-CMAVvgQL.js → BlogPage-DHaGP50_.js} +1 -1
- package/dist/assets/{DocsPage-knf4I4h7.js → DocsPage-CDoxHkz8.js} +40 -859
- package/dist/assets/EditorApp-BJ0Dloyh.js +16446 -0
- package/dist/assets/{EmbedViewer-D7ZGlFjx.js → EmbedViewer-CRKZbY0y.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-CnevhTE8.js → LandingPageProofDriven-BxHkYRE7.js} +1 -1
- package/dist/assets/{LegalPage-BPTUmqeg.js → LegalPage-B-u6FrVv.js} +1 -1
- package/dist/assets/{PricingPage-B0D4goG_.js → PricingPage-CzpZ6-Ce.js} +1 -1
- package/dist/assets/{SettingsPage-CFF-UgjI.js → SettingsPage-CIZSSAd0.js} +1 -1
- package/dist/assets/{app-CE3sYcV7.css → app-CjsbDlb7.css} +143 -0
- package/dist/assets/{app-T0pDcSX4.js → app-DaTMg3nH.js} +1310 -290
- package/dist/assets/cli/{render-C5pcIISc.js → render-DPf4AYJK.js} +55 -60
- package/dist/assets/{constructionHistoryWorker-Ba2Hm58b.js → constructionHistoryWorker-AwMMWSxg.js} +1103 -349
- package/dist/assets/{evalWorker-vkx310U2.js → evalWorker-CjZZWRWW.js} +5209 -2643
- package/dist/assets/{inspectWorker-BuTJDVX6.js → inspectWorker-CZsCFtQT.js} +1163 -409
- package/dist/assets/{jointPose-B_Cgedn9.js → jointPose-DzQOViQH.js} +1 -1
- package/dist/assets/{manifold-BWgsjmAM.js → manifold-BYlzU521.js} +1 -1
- package/dist/assets/{manifold-D6IFSkhH.js → manifold-DgXo0T5P.js} +2 -2
- package/dist/assets/{manifold-rZexZI0G.js → manifold-K1SkarlQ.js} +1 -1
- package/dist/assets/{reportWorker-0AGij1Ru.js → reportWorker-B9nWwSrB.js} +8501 -3393
- package/dist/assets/{scalar-sampling-budget-J5cuzxT1.js → scalar-sampling-budget-prBw_s8t.js} +6067 -3479
- package/dist/assets/{scanProxyWorker-Vl4Wxa1y.js → scanProxyWorker-2GtDLk-R.js} +1 -1
- package/dist/assets/{javascript-1kQXfVaz.js → typescript-DBQ6RN5l.js} +874 -22
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +3 -3
- package/dist/docs-raw/AI/usage.md +1 -1
- package/dist/docs-raw/CLI.md +77 -240
- package/dist/docs-raw/README.md +6 -0
- package/dist/docs-raw/component-model.md +17 -150
- package/dist/docs-raw/generated/assembly.md +188 -582
- package/dist/docs-raw/generated/concepts.md +259 -3501
- package/dist/docs-raw/generated/core.md +283 -1250
- package/dist/docs-raw/generated/curves.md +387 -1608
- package/dist/docs-raw/generated/legacy.md +162 -0
- package/dist/docs-raw/generated/lib.md +227 -85
- package/dist/docs-raw/generated/output.md +35 -99
- package/dist/docs-raw/generated/runtime-names.md +23 -23
- package/dist/docs-raw/generated/sdf.md +68 -284
- package/dist/docs-raw/generated/sheet-metal.md +68 -335
- package/dist/docs-raw/generated/sketch.md +240 -1161
- package/dist/docs-raw/generated/viewport.md +75 -316
- package/dist/docs-raw/generated/wood.md +21 -49
- package/dist/docs-raw/guides/coordinate-system.md +4 -42
- package/dist/docs-raw/guides/inspection-bundles.md +44 -442
- package/dist/docs-raw/guides/joint-design.md +18 -79
- package/dist/docs-raw/guides/positioning.md +21 -143
- package/dist/docs-raw/guides/scene-presentation.md +89 -0
- package/dist/docs-raw/guides/simready-quickstart.md +171 -0
- package/dist/docs-raw/simulation-workflow.md +273 -0
- package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +25 -111
- package/dist/docs-raw/skills/forgecad-blockout-model.md +20 -117
- package/dist/docs-raw/skills/forgecad-component-model.md +23 -107
- package/dist/docs-raw/skills/forgecad-high-level-spec.md +47 -155
- package/dist/docs-raw/skills/forgecad-image-replicator.md +26 -143
- package/dist/docs-raw/skills/forgecad-lld.md +19 -113
- package/dist/docs-raw/skills/forgecad-make-a-model.md +112 -532
- package/dist/docs-raw/skills/forgecad-model-grader.md +38 -108
- package/dist/docs-raw/skills/forgecad-prepare-prompt.md +24 -211
- package/dist/docs-raw/skills/forgecad-project.md +13 -131
- package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +42 -134
- package/dist/docs-raw/skills/forgecad-render-inspect.md +27 -174
- package/dist/docs-raw/skills/forgecad-visual-spec.md +32 -112
- package/dist/docs-raw/skills/forgecad.md +19 -18
- package/dist/docs-raw/skills/index.md +2 -0
- package/dist/docs-raw/welcome.md +2 -2
- package/dist/index.html +2 -2
- package/dist/llms.txt +1 -2
- package/dist/sitemap.xml +25 -13
- package/dist-cli/{check-compiler-SYQ2PWOB.js → check-compiler-II7NLPAB.js} +1 -1
- package/dist-cli/{check-query-propagation-HIAGV62W.js → check-query-propagation-7462TR3R.js} +1 -1
- package/dist-cli/{chunk-SPZE3DUY.js → chunk-UWTJCGXF.js} +5848 -2915
- package/dist-cli/forgecad.js +3496 -703
- package/dist-skill/CONTEXT.md +1797 -7963
- package/dist-skill/SKILL.md +15 -15
- package/dist-skill/docs/API/core/concepts.md +27 -157
- package/dist-skill/docs/CLI.md +77 -240
- package/dist-skill/docs/generated/assembly.md +182 -532
- package/dist-skill/docs/generated/core.md +283 -1250
- package/dist-skill/docs/generated/curves.md +387 -1609
- package/dist-skill/docs/generated/lib.md +227 -85
- package/dist-skill/docs/generated/output.md +35 -99
- package/dist-skill/docs/generated/runtime-names.md +16 -21
- package/dist-skill/docs/generated/sdf.md +68 -284
- package/dist-skill/docs/generated/sheet-metal.md +68 -335
- package/dist-skill/docs/generated/sketch.md +240 -1160
- package/dist-skill/docs/generated/viewport.md +75 -223
- package/dist-skill/docs/generated/wood.md +21 -49
- package/dist-skill/docs/guides/coordinate-system.md +4 -42
- package/dist-skill/docs/guides/inspection-bundles.md +44 -442
- package/dist-skill/docs/guides/joint-design.md +18 -79
- package/dist-skill/docs/guides/positioning.md +21 -143
- package/dist-skill/docs/guides/scene-presentation.md +89 -0
- package/dist-skill/docs/guides/surface-members.md +26 -0
- package/dist-skill/library/forgecad-3d-reconstruction/SKILL.md +23 -111
- package/dist-skill/library/forgecad-blockout-model/SKILL.md +18 -117
- package/dist-skill/library/forgecad-component-model/SKILL.md +21 -107
- package/dist-skill/library/forgecad-high-level-spec/SKILL.md +45 -155
- package/dist-skill/library/forgecad-image-replicator/SKILL.md +24 -143
- package/dist-skill/library/forgecad-lld/SKILL.md +17 -113
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +110 -532
- package/dist-skill/library/forgecad-model-grader/SKILL.md +36 -108
- package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +35 -224
- package/dist-skill/library/forgecad-prepare-prompt/references/default-profiles.md +43 -271
- package/dist-skill/library/forgecad-prepare-prompt/references/master-prompt.md +30 -99
- package/dist-skill/library/forgecad-project/SKILL.md +13 -133
- package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +29 -123
- package/dist-skill/library/forgecad-render-inspect/SKILL.md +25 -174
- package/dist-skill/library/forgecad-visual-spec/SKILL.md +30 -111
- package/dist-skill/website/skills/forgecad-3d-reconstruction.md +58 -0
- package/dist-skill/website/skills/forgecad-blockout-model.md +49 -0
- package/dist-skill/website/skills/forgecad-component-model.md +53 -0
- package/dist-skill/website/skills/forgecad-high-level-spec.md +101 -0
- package/dist-skill/website/skills/forgecad-image-replicator.md +63 -0
- package/dist-skill/website/skills/forgecad-lld.md +41 -0
- package/dist-skill/website/skills/forgecad-make-a-model.md +186 -0
- package/dist-skill/website/skills/forgecad-model-grader.md +82 -0
- package/dist-skill/website/skills/forgecad-prepare-prompt.md +63 -0
- package/dist-skill/website/skills/forgecad-project.md +26 -0
- package/dist-skill/website/skills/forgecad-reconstruction-benchmark.md +60 -0
- package/dist-skill/website/skills/forgecad-render-inspect.md +80 -0
- package/dist-skill/website/skills/forgecad-visual-spec.md +71 -0
- package/dist-skill/website/skills/forgecad.md +122 -0
- package/dist-skill/website/skills/index.md +26 -0
- package/examples/api/comparison-imported-sphere-candidate.forge.js +1 -1
- package/examples/api/conformal-product-ribbon.forge.js +1 -1
- package/examples/api/exact-sheet-shell-assembly.forge.js +1 -1
- package/examples/api/extrude-options.forge.js +4 -2
- package/examples/api/field-loft-drive-tip.forge.js +40 -0
- package/examples/api/guided-loft-olive-oil-bottle.forge.js +1 -1
- package/examples/api/highlight-debug.forge.js +10 -10
- package/examples/api/mesh-import-slats.forge.js +1 -1
- package/examples/api/real-product-curves.forge.js +1 -1
- package/examples/api/sculpt-box-circle-booleans.forge.js +1 -1
- package/examples/api/sdf-shapes.forge.js +2 -5
- package/examples/api/sketch-rounding-strategies.forge.js +6 -6
- package/examples/api/surface-member-bottle-cage.forge.js +3 -3
- package/examples/api/surface-member-conformal-product-ribbon.forge.js +3 -3
- package/examples/api/surface-member-razor-inlay.forge.js +1 -1
- package/examples/api/variable-sweep-test.forge.js +3 -3
- package/examples/mechanical/airplane-propeller.forge.js +74 -39
- package/examples/nurbs-surface.forge.js +1 -1
- package/examples/products/iphone.forge.js +1 -1
- package/examples/robotics/README.md +46 -0
- package/examples/robotics/scout-cam-rover-simready/README.md +119 -0
- package/examples/robotics/scout-cam-rover-simready/lib/dims.js +140 -0
- package/examples/robotics/scout-cam-rover-simready/main.forge.js +343 -0
- package/examples/robotics/scout-cam-rover-simready/parts/body.forge.js +304 -0
- package/examples/robotics/scout-cam-rover-simready/parts/chassis.forge.js +320 -0
- package/examples/robotics/scout-cam-rover-simready/parts/hardware.forge.js +21 -0
- package/examples/robotics/scout-cam-rover-simready/parts/turret.forge.js +70 -0
- package/examples/robotics/scout-cam-rover-simready/parts/wheel.forge.js +116 -0
- package/examples/robotics/simready-asset-crate.forge.js +79 -0
- package/examples/robotics/simready-diff-drive-rover.forge.js +141 -0
- package/examples/robotics/simready-parallel-gripper.forge.js +102 -0
- package/package.json +1 -1
- package/dist/assets/EditorApp-BHMQlJ-D.js +0 -14686
- package/dist/docs-raw/guides/geometry-conventions.md +0 -52
- package/dist/docs-raw/guides/modeling-recipes.md +0 -78
- package/dist-skill/docs/guides/geometry-conventions.md +0 -52
- package/dist-skill/docs/guides/modeling-recipes.md +0 -78
- package/dist-skill/library/forgecad-visual-spec/references/prompt-template.md +0 -79
|
@@ -5,98 +5,94 @@ skill-order: 100
|
|
|
5
5
|
|
|
6
6
|
# Assembly API
|
|
7
7
|
|
|
8
|
-
Assembly-owned links, constraints, connectors, solved poses, and
|
|
8
|
+
Assembly-owned links, constraints, connectors, solved poses, and source-level simulation metadata.
|
|
9
9
|
|
|
10
10
|
## Contents
|
|
11
11
|
|
|
12
|
-
- [Assembly & Joints](#assembly-joints)
|
|
12
|
+
- [Assembly & Joints](#assembly-joints)
|
|
13
13
|
- [Assembly](#assembly) — Kinematics, Structure, Connectors, References, Solving
|
|
14
14
|
- [ImportedAssembly](#importedassembly)
|
|
15
15
|
- [SolvedAssembly](#solvedassembly)
|
|
16
|
-
- [MateBuilder](#matebuilder)
|
|
17
16
|
|
|
18
17
|
## Functions
|
|
19
18
|
|
|
20
19
|
### Assembly & Joints
|
|
21
20
|
|
|
22
|
-
#### `
|
|
21
|
+
#### `Sim.material(name: string, options?: SimMaterialOptions): SimMaterialDef` — Create a named physical material with density and contact coefficients for simulation export and checks.
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
`SimMaterialOptions`: `{ densityKgM3?: number, staticFriction?: number, dynamicFriction?: number, restitution?: number }`
|
|
25
24
|
|
|
26
|
-
```ts
|
|
27
|
-
bomToCsv(rows: BomRow[]): string
|
|
28
|
-
```
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
`SimMaterialDef`: `{ kind: "material", name: string }`
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
#### `Sim.body(options: SimBodyOptions): SimBodyDef` — Describe one assembly part as a physical body with mass/density, material, collider intent, and optional contact surfaces.
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|--------|------|-------------|
|
|
36
|
-
| `tags?` | `string \| readonly string[]` | Viewport organization tags applied to scene objects produced from this part. |
|
|
37
|
-
| `material?`, `process?`, `tolerance?`, `qty?`, `notes?`, `densityKgM3?`, `massKg?` | | — |
|
|
30
|
+
**`SimBodyOptions`**: `massKg?: number`, `densityKgM3?: number`, `material?: SimMaterialDef`, `collider?: SimColliderDef`, `contacts?: Record<string, SimContactDef>`
|
|
38
31
|
|
|
39
|
-
|
|
32
|
+
`SimColliderDef`: `{ kind: "collider", mode: SimColliderMode, reason?: string }`
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
`SimContactDef`: `{ kind: "wheelSurface" | "gripperSurface", connectorName: string }`
|
|
42
35
|
|
|
43
|
-
Links are named kinematic markers in the assembly. `edgeBetweenLinks()` records structural distances or visual relationships. `addAngleBetweenLinks()` records measured, limited, or controlled angles. These APIs solve point positions, not rigid-body frames.
|
|
44
36
|
|
|
45
|
-
`
|
|
37
|
+
`SimBodyDef`: `{ kind: "body" }`
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
#### `Sim.collider` — Collision-geometry intent constructors for physical parts.
|
|
48
40
|
|
|
49
|
-
|
|
41
|
+
- `Sim.collider.convexHull(): SimColliderDef` — Use a generated collision mesh for the part. This is the default fast rigid-body collider for irregular parts.
|
|
42
|
+
- `Sim.collider.boundingBox(): SimColliderDef` — Use the part bounding box as the collision geometry. This is fastest and works well for chassis and simple blocks.
|
|
43
|
+
- `Sim.collider.visualMesh(): SimColliderDef` — Use the visual mesh as collision geometry. This is exact but usually slower in physics engines.
|
|
44
|
+
- `Sim.collider.none(reason: string): SimColliderDef` — Disable collision for a part with an explicit reason, such as a sensor-only or decorative object.
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
#### `Sim.drive` — Joint-drive intent constructors for passive or powered assembly joints.
|
|
52
47
|
|
|
53
|
-
|
|
48
|
+
- `Sim.drive.passive(options?: SimPassiveDriveOptions): SimDriveDef` — Mark a joint as passive while preserving damping and friction metadata for simulation export.
|
|
49
|
+
- `Sim.drive.velocity(options: SimVelocityDriveOptions): SimDriveDef` — Mark a revolute joint as velocity-driven with torque and speed limits. Speed is authored in rpm and exported as deg/s or rad/s as needed.
|
|
54
50
|
|
|
55
|
-
|
|
51
|
+
`SimPassiveDriveOptions`: `{ damping?: number, friction?: number }`
|
|
56
52
|
|
|
57
|
-
This snippet mates a marker to the solved `tip` point. It does not orient a bar along `ground -> tip`.
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
const marker = box(8, 8, 4).withConnectors({
|
|
61
|
-
center: connector({ origin: [0, 0, 0], axis: [0, 0, 1] }),
|
|
62
|
-
});
|
|
54
|
+
`SimVelocityDriveOptions`: `{ maxTorqueNm: number, maxSpeedRpm: number }`
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
.link("ground", { at: [0, 0, 0], fixed: true })
|
|
66
|
-
.link("worldX", { at: [10, 0, 0], fixed: true })
|
|
67
|
-
.link("tip", { at: [40, 0, 0] })
|
|
68
|
-
.edgeBetweenLinks("ground", "tip", { name: "bar" })
|
|
69
|
-
.addAngleBetweenLinks("worldX", "ground", "tip", {
|
|
70
|
-
name: "theta",
|
|
71
|
-
control: { min: 0, max: 120, default: 30 },
|
|
72
|
-
})
|
|
73
|
-
.addPart("Tip marker", marker, { mate: { connector: "center", toLink: "tip" } });
|
|
56
|
+
#### `Sim.contact` — Contact-surface metadata over existing part connectors.
|
|
74
57
|
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
- `Sim.contact.wheelSurface(connectorName: string): SimContactDef` — Mark a connector as the wheel tread contact surface for offline checks and downstream simulation metadata.
|
|
59
|
+
- `Sim.contact.gripperSurface(connectorName: string): SimContactDef` — Mark a connector as a gripper pad/contact surface for offline checks and downstream grasp-readiness metadata.
|
|
77
60
|
|
|
78
|
-
|
|
79
|
-
assembly(name?: string): Assembly
|
|
80
|
-
```
|
|
61
|
+
#### `Sim.profile` — Named validation/export profile constructors.
|
|
81
62
|
|
|
82
|
-
|
|
63
|
+
- `Sim.profile.robotBodyRunnable(): SimProfileDef` — SimReady-style profile for a robot body that should be runnable in a physics simulator.
|
|
64
|
+
- `Sim.profile.robotBodyIsaac(): SimProfileDef` — SimReady-style profile for robot bodies targeting Isaac Sim readiness.
|
|
65
|
+
- `Sim.profile.roboticsAssetPhysx(): SimProfileDef` — SimReady-style profile for robotics assets with PhysX-ready rigid bodies and colliders.
|
|
83
66
|
|
|
84
|
-
|
|
67
|
+
`SimProfileDef`: `{ kind: "profile", name: SimProfileName }`
|
|
85
68
|
|
|
86
|
-
|
|
69
|
+
#### `Sim.controller` — Standard controller metadata constructors for simulator package generation.
|
|
70
|
+
|
|
71
|
+
- `Sim.controller.diffDrive(options: SimDiffDriveControllerOptions): SimDiffDriveControllerDef` — Describe a differential-drive controller from left/right wheel joints and wheel dimensions.
|
|
72
|
+
|
|
73
|
+
**`SimDiffDriveControllerOptions`**: `leftJoints: string[]`, `rightJoints: string[]`, `wheelSeparationMm: number`, `wheelRadiusMm: number`, `topic?: string`, `odomTopic?: string`, `tfTopic?: string`, `frameId?: string`, `odomFrameId?: string`, `maxLinearVelocity?: number`, `maxAngularVelocity?: number`, `linearAcceleration?: number`, `angularAcceleration?: number`
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
`SimDiffDriveControllerDef`: `{ kind: "diffDrive" }`
|
|
77
|
+
|
|
78
|
+
#### `assembly(name?: string): Assembly` — Create an assembly container with named parts, connectors, and kinematic links.
|
|
87
79
|
|
|
88
|
-
|
|
80
|
+
**Use this from iteration 1 for any model with moving parts.** Do not build one static pose and retrofit motion later.
|
|
81
|
+
|
|
82
|
+
Two motion tools:
|
|
83
|
+
|
|
84
|
+
- **Link-graph kinematics** (`link()`, `edgeBetweenLinks()`, `addAngleBetweenLinks()`) solve named point positions — a link is a point, not a rigid-body frame. Use when the hard part is solving positions, especially closed loops.
|
|
85
|
+
- **Connector-frame joints** (`connect()` / `match()`) align full connector frames (`origin`, `axis`, `up`) and derive joint frame + axis. Use for serial articulated parts whose orientation matters: hips, hinges, drums, sliders, wheels.
|
|
89
86
|
|
|
90
|
-
|
|
87
|
+
`addPart(..., { mate })` places geometry on the solved link graph by **translation only**: one mate pins a connector origin to a link, two mates orient a part to span two solved links, a third pins roll. Right for markers and point-following geometry; use `connect()`/`match()` when the part needs a deterministic rest orientation.
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
- **Connector-frame joints** (`connect()` / `match()`) align full connector frames and derive joint frame + axis from `origin`, `axis`, and `up`. Use this for serial articulated geometry such as hips, knees, hinges, drums, sliders, and wheels where the physical part orientation matters.
|
|
89
|
+
Return the `Assembly` itself to expose its joints and driven link controls in the editor; moving a control re-runs `solve(state)`, so closed loops move through the real solver instead of a viewport-only FK approximation.
|
|
94
90
|
|
|
95
|
-
|
|
91
|
+
If no link in a connected kinematic component is fixed, ForgeCAD chooses a deterministic gauge link for solving and reports a floating-component warning.
|
|
96
92
|
|
|
97
|
-
|
|
93
|
+
A file that returns an `Assembly` is importable via [`require()`](/docs/core#require) and yields an `ImportedAssembly`; use `mergeInto()` to flatten it into a parent assembly.
|
|
98
94
|
|
|
99
|
-
|
|
95
|
+
**Point-link example** (mates a marker to the solved `tip` point; does not orient a bar along `ground -> tip`):
|
|
100
96
|
|
|
101
97
|
```ts
|
|
102
98
|
const marker = box(8, 8, 4).withConnectors({
|
|
@@ -112,46 +108,20 @@ const mech = assembly("Linkage")
|
|
|
112
108
|
name: "theta",
|
|
113
109
|
control: { min: 0, max: 120, default: 30 },
|
|
114
110
|
})
|
|
115
|
-
.addPart("Tip marker", marker, {
|
|
116
|
-
mate: { connector: "center", toLink: "tip" },
|
|
117
|
-
});
|
|
111
|
+
.addPart("Tip marker", marker, { mate: { connector: "center", toLink: "tip" } });
|
|
118
112
|
|
|
119
113
|
return mech;
|
|
120
114
|
```
|
|
121
115
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
return mech.solve({ theta: 60 });
|
|
126
|
-
```
|
|
116
|
+
---
|
|
127
117
|
|
|
128
|
-
|
|
118
|
+
## Classes
|
|
129
119
|
|
|
130
|
-
|
|
131
|
-
const hip = cylinder(12, 10).withConnectors({
|
|
132
|
-
socket: connector("hinge", {
|
|
133
|
-
origin: [0, 0, 6],
|
|
134
|
-
axis: [0, 0, 1],
|
|
135
|
-
up: [1, 0, 0],
|
|
136
|
-
kind: "revolute",
|
|
137
|
-
}),
|
|
138
|
-
});
|
|
120
|
+
### `Assembly`
|
|
139
121
|
|
|
140
|
-
|
|
141
|
-
hip: connector("hinge", {
|
|
142
|
-
origin: [0, 0, 0],
|
|
143
|
-
axis: [0, 0, -1],
|
|
144
|
-
up: [1, 0, 0],
|
|
145
|
-
kind: "revolute",
|
|
146
|
-
}),
|
|
147
|
-
});
|
|
122
|
+
Container for a kinematic mechanism made up of links, relationships, and parts. See `assembly` for the link-graph vs connector-frame decision rules.
|
|
148
123
|
|
|
149
|
-
return
|
|
150
|
-
.addPart("Hip", hip)
|
|
151
|
-
.addPart("Upper Leg", upperLeg)
|
|
152
|
-
.connect("Hip.socket", "Upper Leg.hip", { as: "hip", min: -35, max: 55 })
|
|
153
|
-
.solve({ hip: 20 });
|
|
154
|
-
```
|
|
124
|
+
Returning an unsolved `Assembly` keeps the graph available to the runtime; return `mech.solve({ theta: 60 })` for a fixed pose instead.
|
|
155
125
|
|
|
156
126
|
**Return types**
|
|
157
127
|
|
|
@@ -168,64 +138,61 @@ return assembly("Leg")
|
|
|
168
138
|
|
|
169
139
|
**Kinematics**
|
|
170
140
|
|
|
171
|
-
#### `link()` — Add a named kinematic link to the assembly graph.
|
|
141
|
+
#### `link(name: string, options?: AssemblyLinkOptions): Assembly` — Add a named kinematic link to the assembly graph.
|
|
172
142
|
|
|
173
143
|
Links are assembly-native solved points. They can exist before any geometry is attached, can be displayed by the viewport, and are solved by link/edge/angle constraints.
|
|
174
144
|
|
|
175
145
|
A link is not a rigid-body frame. It has a world position but no orientation basis. Use `connect()` when a physical part must inherit a connector frame and rotate about a real hinge/slider axis.
|
|
176
146
|
|
|
177
|
-
```ts
|
|
178
|
-
link(name: string, options?: AssemblyLinkOptions): Assembly
|
|
179
|
-
```
|
|
180
|
-
|
|
181
147
|
**`AssemblyLinkOptions`**
|
|
182
|
-
- `at?:
|
|
148
|
+
- `at?: Vec3` — Initial world-space position of this link before kinematic constraints solve it.
|
|
183
149
|
- `fixed?: boolean` — Keep the link locked at its authored `at` position during solves.
|
|
184
150
|
- `metadata?: Record<string, unknown>` — User metadata carried through the kinematic graph for inspection and tooling.
|
|
185
151
|
|
|
186
|
-
#### `
|
|
152
|
+
#### `linkAlong(name: string, fromLink: string, towardLink: string, distance: number): Assembly` — Create a derived link on the line through `fromLink` and `towardLink`, at a **signed** distance from `fromLink`.
|
|
187
153
|
|
|
188
|
-
|
|
154
|
+
**Sign convention** (read this first):
|
|
155
|
+
|
|
156
|
+
- `distance > 0` — the point moves from `fromLink` **toward** `towardLink`.
|
|
157
|
+
- `distance < 0` — the point moves from `fromLink` **away from** `towardLink` (the coupler-extension case, e.g. the Chebyshev lambda linkage's trace point beyond the rocker joint).
|
|
158
|
+
- `distance` greater than the solved edge length places the point **beyond** `towardLink`, still on the same line.
|
|
159
|
+
|
|
160
|
+
Derived links are trace/reference points. They are recomputed after the primary link solve and cannot participate in structural edges or angle constraints. Because the distance is one signed parameter, a `param()`-driven value can sweep continuously from extension (negative) through `fromLink` (zero) to beyond `towardLink` (large positive).
|
|
189
161
|
|
|
190
162
|
```ts
|
|
191
|
-
|
|
163
|
+
// Chebyshev lambda linkage: trace point C3 extends beyond C2, away from C1.
|
|
164
|
+
mech.linkAlong('C3', 'C2', 'C1', -2.5 * a);
|
|
165
|
+
// Midpoint-style reference 30 mm from A toward B:
|
|
166
|
+
mech.linkAlong('probe', 'A', 'B', 30);
|
|
192
167
|
```
|
|
193
168
|
|
|
169
|
+
#### `edgeBetweenLinks(a: string, b: string, options?: AssemblyEdgeBetweenLinksOptions): Assembly` — Add a relationship edge between two kinematic links.
|
|
170
|
+
|
|
171
|
+
By default the edge captures the authored distance between links as a structural length. Pass `{ length: 'free' }` or `{ visualOnly: true }` for a non-structural overlay edge.
|
|
172
|
+
|
|
194
173
|
**`AssemblyEdgeBetweenLinksOptions`**: `name?: string`, `length?: number | "lockCurrent" | "free"`, `min?: number`, `max?: number`, `visualOnly?: boolean`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
195
174
|
|
|
196
175
|
`AssemblyKinematicControlOptions`: `{ min?: number, max?: number, default?: number, unit?: string }`
|
|
197
176
|
|
|
198
|
-
#### `addAngleBetweenLinks()` — Add an angle relationship among three kinematic links.
|
|
177
|
+
#### `addAngleBetweenLinks(a: string, b: string, c: string, options?: AssemblyAngleBetweenLinksOptions): Assembly` — Add an angle relationship among three kinematic links.
|
|
199
178
|
|
|
200
179
|
The middle link is the vertex. When `control` is set, `solve(state)` reads the control value from `state[name]` and solves dependent links from that driven angle.
|
|
201
180
|
|
|
202
|
-
```ts
|
|
203
|
-
addAngleBetweenLinks(a: string, b: string, c: string, options?: AssemblyAngleBetweenLinksOptions): Assembly
|
|
204
|
-
```
|
|
205
|
-
|
|
206
181
|
**`AssemblyAngleBetweenLinksOptions`**: `name?: string`, `value?: number`, `min?: number`, `max?: number`, `control?: boolean | AssemblyKinematicControlOptions`, `limit?: AssemblyKinematicLimitOptions`, `metadata?: Record<string, unknown>`
|
|
207
182
|
|
|
208
183
|
`AssemblyKinematicLimitOptions`: `{ min?: number, max?: number }`
|
|
209
184
|
|
|
210
|
-
#### `addAngleBetweenLinkSegmentAndWorldDirection()` — Add an absolute angle relationship from a world direction to a link segment.
|
|
185
|
+
#### `addAngleBetweenLinkSegmentAndWorldDirection(fromLink: string, toLink: string, direction: Vec3, options?: AssemblyAngleBetweenLinksOptions): Assembly` — Add an absolute angle relationship from a world direction to a link segment.
|
|
211
186
|
|
|
212
187
|
The first link is the vertex/pivot and the second link is the moving point. A value of `0` places `fromLink -> toLink` along `direction` in the mechanism plane; positive angles rotate counter-clockwise in that plane.
|
|
213
188
|
|
|
214
189
|
Use `Points.polar(1, angleDeg)` when the reference direction is planar and angle-based instead of axis-aligned.
|
|
215
190
|
|
|
216
|
-
|
|
217
|
-
addAngleBetweenLinkSegmentAndWorldDirection(fromLink: string, toLink: string, direction: Vec3, options?: AssemblyAngleBetweenLinksOptions): Assembly
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
#### `describeKinematics()` — Return the assembly-native kinematic graph definition.
|
|
221
|
-
|
|
222
|
-
```ts
|
|
223
|
-
describeKinematics(): AssemblyKinematicGraphDef
|
|
224
|
-
```
|
|
191
|
+
#### `describeKinematics(): AssemblyKinematicGraphDef` — Return the assembly-native kinematic graph definition.
|
|
225
192
|
|
|
226
193
|
**Structure**
|
|
227
194
|
|
|
228
|
-
#### `addPart()` — Add a named part to the assembly.
|
|
195
|
+
#### `addPart(name: string, part: AssemblyPart, options?: PartOptions): Assembly` — Add a named part to the assembly.
|
|
229
196
|
|
|
230
197
|
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.
|
|
231
198
|
|
|
@@ -241,144 +208,104 @@ const housing = group(
|
|
|
241
208
|
assembly.addPart("Base Assembly", housing);
|
|
242
209
|
```
|
|
243
210
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
211
|
+
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `sim?: SimBodyDef`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
212
|
+
|
|
213
|
+
**`PartMetadata`**
|
|
247
214
|
|
|
248
|
-
|
|
215
|
+
| Option | Type | Description |
|
|
216
|
+
|--------|------|-------------|
|
|
217
|
+
| `tags?` | `string \| readonly string[]` | Viewport organization tags applied to scene objects produced from this part. |
|
|
218
|
+
|
|
219
|
+
Also: `material?: string`, `process?: string`, `tolerance?: string`, `qty?: number`, `notes?: string`, `densityKgM3?: number`, `massKg?: number`.
|
|
249
220
|
|
|
250
221
|
**`AssemblyPartMateInput`**
|
|
251
222
|
- `connector: string` — Name of a connector declared on the part (via `withConnectors()`).
|
|
252
223
|
- `toLink: string` — Name of the link this connector's origin is pinned to.
|
|
253
224
|
- `aimLink?: string` — Optional second link to orient toward. When set, the part is rotated so the connector's **axis** aims from `toLink` toward `aimLink`, posing an oriented bone instead of only translating it. For full pose without relying on a connector axis, declare a second mate (two connectors → two links).
|
|
254
225
|
|
|
255
|
-
#### `frame()` — Add a named rig frame to the assembly.
|
|
226
|
+
#### `frame(name: string, options: AssemblyFrameOptions): Assembly` — Add a named rig frame to the assembly.
|
|
256
227
|
|
|
257
228
|
A frame is a solved pose: `origin` plus orientation. `axis` is the frame's primary direction and `up` fixes roll around that axis. Use frames for robot links, joint axes, and parts that must carry orientation. Use `link()` for solved points in distance/angle graphs.
|
|
258
229
|
|
|
259
|
-
|
|
260
|
-
frame(name: string, options: AssemblyFrameOptions): Assembly
|
|
261
|
-
```
|
|
230
|
+
`AssemblyFrameOptions`: `{ origin: Vec3, axis: Vec3, up: Vec3, fixed?: boolean, metadata?: Record<string, unknown> }`
|
|
262
231
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
#### `fixedJoint()` — Rigidly attach a child rig frame to a parent rig frame.
|
|
232
|
+
#### `fixedJoint(name: string, options: AssemblyFixedFrameJointOptions): Assembly` — Rigidly attach a child rig frame to a parent rig frame.
|
|
266
233
|
|
|
267
234
|
Fixed joints carry frame hierarchy but do not expose a Motion control.
|
|
268
235
|
|
|
269
|
-
```ts
|
|
270
|
-
fixedJoint(name: string, options: AssemblyFixedFrameJointOptions): Assembly
|
|
271
|
-
```
|
|
272
|
-
|
|
273
236
|
`AssemblyFixedFrameJointOptions`: `{ parent: string, child: string, metadata?: Record<string, unknown> }`
|
|
274
237
|
|
|
275
|
-
#### `revoluteJoint()` — Add a revolute rig-frame joint.
|
|
238
|
+
#### `revoluteJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly` — Add a revolute rig-frame joint.
|
|
276
239
|
|
|
277
240
|
The child frame rotates around the parent frame's `axis` direction. Moving frame joints appear in Motion by default; pass `control: false` to keep the joint solved at its default value without showing a Motion control.
|
|
278
241
|
|
|
279
|
-
```ts
|
|
280
|
-
revoluteJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly
|
|
281
|
-
```
|
|
282
|
-
|
|
283
242
|
**`AssemblyMovingFrameJointOptions`**: `parent: string`, `child: string`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `control?: boolean`, `metadata?: Record<string, unknown>`
|
|
284
243
|
|
|
285
|
-
#### `prismaticJoint()` — Add a prismatic rig-frame joint.
|
|
244
|
+
#### `prismaticJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly` — Add a prismatic rig-frame joint.
|
|
286
245
|
|
|
287
246
|
The child frame translates along the parent frame's `axis` direction. Moving frame joints appear in Motion by default; pass `control: false` to keep the joint solved at its default value without showing a Motion control.
|
|
288
247
|
|
|
289
|
-
```ts
|
|
290
|
-
prismaticJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly
|
|
291
|
-
```
|
|
292
|
-
|
|
293
248
|
**Connectors**
|
|
294
249
|
|
|
295
|
-
#### `usedConnectorRefs()
|
|
296
|
-
|
|
297
|
-
```ts
|
|
298
|
-
get usedConnectorRefs(): ReadonlySet<string>
|
|
299
|
-
```
|
|
250
|
+
#### `get usedConnectorRefs(): ReadonlySet<string>` — Connector refs (e.g. "PartName.connectorName") consumed by connect/match calls.
|
|
300
251
|
|
|
301
|
-
#### `withConnectors()` — Attach named connectors to a specific part or the assembly as a whole.
|
|
252
|
+
#### `withConnectors(partName: string, connectors: Record<string, ConnectorInput>): Assembly` — Attach named connectors to a specific part or the assembly as a whole.
|
|
302
253
|
|
|
303
254
|
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.
|
|
304
255
|
|
|
305
256
|
Use the single-argument overload to attach assembly-level connectors — these are exposed when this assembly is imported as a sub-assembly.
|
|
306
257
|
|
|
307
|
-
|
|
308
|
-
withConnectors(partName: string, connectors: Record<string, ConnectorInput>): Assembly
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
**`PortInput`**: `origin?: [ number, number, number ]`, `axis?: [ number, number, number ]`, `start?: [ number, number, number ]`, `end?: [ number, number, number ]`, `up?: [ number, number, number ]`, `kind?: JointType`, `min?: number`, `max?: number`
|
|
312
|
-
|
|
313
|
-
`ConnectorInput`: `{ connectorType?: string, gender?: ConnectorGender, measurements?: Record<string, number | string> }`
|
|
314
|
-
|
|
315
|
-
#### `getConnectors()` — Get connectors declared on a part in part-local space.
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
getConnectors(partName: string): ConnectorMap
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
#### `getConnector()` — Parse a "PartName.connectorName" reference and return the resolved connector. Throws descriptive errors if the part or connector doesn't exist.
|
|
322
|
-
|
|
323
|
-
```ts
|
|
324
|
-
getConnector(ref: string): { partName: string; connectorName: string; connector: ConnectorDef; }
|
|
325
|
-
```
|
|
258
|
+
`ConnectorInput` — defined in [core](/docs/core).
|
|
326
259
|
|
|
327
|
-
#### `
|
|
260
|
+
#### `getConnectors(partName: string): ConnectorMap` — Get connectors declared on a part in part-local space.
|
|
328
261
|
|
|
329
|
-
|
|
262
|
+
#### `getConnector(ref: string): { partName: string; connectorName: string; connector: ConnectorDef; }` — Parse a "PartName.connectorName" reference and return the resolved connector. Throws descriptive errors if the part or connector doesn't exist.
|
|
330
263
|
|
|
331
|
-
|
|
264
|
+
#### `connect(parentConnectorRef: string, childConnectorRef: string, options?: ConnectOptions): Assembly` — Connect two parts by aligning their declared connectors, automatically computing frame and axis.
|
|
332
265
|
|
|
333
|
-
|
|
266
|
+
Connector refs use `"PartName.connectorName"`. The child connector origin lands exactly on the parent connector origin; joint frame and axis are derived from the connector geometry — no manual `frame`/`axis` math.
|
|
334
267
|
|
|
335
|
-
|
|
268
|
+
Frame semantics: `origin` is the pivot/contact point, `axis` the hinge or slide direction, `up` locks the part's zero-state twist. Omitted `up` gets a deterministic perpendicular — provide `up` whenever rest orientation matters. (`addPart(..., { mate })` translates only; see `addPart`.)
|
|
336
269
|
|
|
337
|
-
**
|
|
270
|
+
**Face-to-face:** each connector's axis points outward from its part; mating makes the axes anti-parallel, like a plug meeting a socket (same convention as `matchTo()`).
|
|
338
271
|
|
|
339
|
-
|
|
272
|
+
**Revolute sign:** a positive joint value follows the right-hand rule about the **child** connector's placed axis. Because face-to-face mating makes the axes anti-parallel, that is the *left*-hand rule about the parent connector's outward axis — if `+30` swings the opposite way you expected, you predicted from the parent's axis. `forgecad debug assembly` prints each joint's resolved world axis.
|
|
340
273
|
|
|
341
|
-
|
|
274
|
+
**Mirrored revolute axes:** because of the right-hand rule, a mirrored hinge axis (`[1, 0, 0]` vs `[-1, 0, 0]`) rotates oppositely for the same `+theta`: negate the mirrored side's value and mirror limits as `[min, max] -> [-max, -min]`. Prismatic joints have no handedness flip. Use an explicit per-side sign mapping (or side-neutral link controls) for bilateral mechanisms.
|
|
342
275
|
|
|
343
|
-
|
|
276
|
+
Joint type defaults to the connector's `kind`. For `start`/`end` connectors, `align` / `parentAlign` / `childAlign` (`'start' | 'middle' | 'end'`) choose which point meets.
|
|
344
277
|
|
|
345
278
|
```ts
|
|
346
|
-
// Hinge: both axes point outward along the hinge line
|
|
347
279
|
const frame = box(100, 10, 80).withConnectors({
|
|
348
|
-
hinge: connector("hinge", {
|
|
349
|
-
origin: [0, 0, 40],
|
|
350
|
-
axis: [0, 0, 1],
|
|
351
|
-
up: [1, 0, 0],
|
|
352
|
-
}),
|
|
280
|
+
hinge: connector("hinge", { origin: [0, 0, 40], axis: [0, 0, 1], up: [1, 0, 0] }),
|
|
353
281
|
});
|
|
354
282
|
const door = box(60, 4, 80).withConnectors({
|
|
355
|
-
hinge: connector("hinge", {
|
|
356
|
-
origin: [0, 0, 40],
|
|
357
|
-
axis: [0, 0, -1],
|
|
358
|
-
up: [1, 0, 0],
|
|
359
|
-
}),
|
|
283
|
+
hinge: connector("hinge", { origin: [0, 0, 40], axis: [0, 0, -1], up: [1, 0, 0] }),
|
|
360
284
|
});
|
|
361
|
-
assembly("Door")
|
|
362
|
-
.addPart("Frame", frame)
|
|
363
|
-
.addPart("Door", door)
|
|
285
|
+
assembly("Door").addPart("Frame", frame).addPart("Door", door)
|
|
364
286
|
.connect("Frame.hinge", "Door.hinge", { as: "swing", min: 0, max: 110 });
|
|
365
287
|
```
|
|
366
288
|
|
|
367
|
-
```ts
|
|
368
|
-
connect(parentConnectorRef: string, childConnectorRef: string, options?: ConnectOptions): Assembly
|
|
369
|
-
```
|
|
370
|
-
|
|
371
289
|
**`ConnectOptions`**
|
|
372
290
|
|
|
373
291
|
| Option | Type | Description |
|
|
374
292
|
|--------|------|-------------|
|
|
293
|
+
| `min?` | `number` | Lower joint-slider limit; solve clamps to it with a warning. Not a physical stop — enforce real travel limits with stop geometry. |
|
|
294
|
+
| `max?` | `number` | Upper joint-slider limit; same semantics as `min`. |
|
|
375
295
|
| `flip?` | `boolean` | This parameter is ignored. If your connectors produce wrong orientation, fix the connector axis directions instead of using flip. |
|
|
376
296
|
| `parentAlign?` | `PortAlign` | Which point on the parent connector to align: 'start', 'middle' (default), or 'end'. |
|
|
377
297
|
| `childAlign?` | `PortAlign` | Which point on the child connector to align: 'start', 'middle' (default), or 'end'. |
|
|
378
298
|
| `align?` | `PortAlign` | Shorthand: set both parentAlign and childAlign at once. |
|
|
379
|
-
| `
|
|
299
|
+
| `follows?` | `JointFollowOptions` | Slave this joint to another joint: `value = ratio × source + offset` (e.g. a mirrored jaw with `ratio: -1`). |
|
|
300
|
+
|
|
301
|
+
Also: `as?: string`, `type?: JointType`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `drive?: SimDriveDef`.
|
|
380
302
|
|
|
381
|
-
|
|
303
|
+
**`JointFollowOptions`**
|
|
304
|
+
- `joint: string` — Name of the source joint that drives this one.
|
|
305
|
+
- `ratio?: number` — Multiplier applied to the source joint value (default 1).
|
|
306
|
+
- `offset?: number` — Constant added after the ratio (default 0).
|
|
307
|
+
|
|
308
|
+
#### `match(childPartName: string, parentPartName: string, pairs: Record<string, string>, options?: MatchToOptions & { as?: string; }): Assembly` — Auto-create a joint by matching typed connectors between two parts.
|
|
382
309
|
|
|
383
310
|
Connectors can carry 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.
|
|
384
311
|
|
|
@@ -403,29 +330,17 @@ const mech = assembly("Door")
|
|
|
403
330
|
// Matching connectors computes the placement relationship automatically.
|
|
404
331
|
```
|
|
405
332
|
|
|
406
|
-
|
|
407
|
-
match(childPartName: string, parentPartName: string, pairs: Record<string, string>, options?: MatchToOptions & { as?: string; }): Assembly
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
`MatchToOptions`: `{ force?: boolean, angle?: number, distance?: number }`
|
|
333
|
+
`MatchToOptions` — defined in [core](/docs/core).
|
|
411
334
|
|
|
412
335
|
**References**
|
|
413
336
|
|
|
414
|
-
#### `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 a new Assembly — does not mutate.
|
|
337
|
+
#### `withReferences(refs: Pick<PlacementReferenceInput, "points">): Assembly` — 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 a new Assembly — does not mutate.
|
|
415
338
|
|
|
416
|
-
|
|
417
|
-
withReferences(refs: Pick<PlacementReferenceInput, "points">): Assembly
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
**`PlacementReferenceInput`**: `points?: Record<string, [ number, number, number ]>`, `edges?: Record<string, PlacementEdgeRef>`, `surfaces?: Record<string, PlacementSurfaceRef>`, `objects?: Record<string, PlacementObjectInput>`
|
|
421
|
-
|
|
422
|
-
`PlacementEdgeRef`: `{ start: Vec3, end: Vec3 }`
|
|
423
|
-
|
|
424
|
-
`PlacementSurfaceRef`: `{ center: Vec3, normal: Vec3 }`
|
|
339
|
+
`PlacementReferenceInput` — defined in [core](/docs/core).
|
|
425
340
|
|
|
426
341
|
**Solving**
|
|
427
342
|
|
|
428
|
-
#### `solve()` — Solve the assembly at the given control state and return positioned parts.
|
|
343
|
+
#### `solve(state?: JointState): SolvedAssembly` — Solve the assembly at the given control state and return positioned parts.
|
|
429
344
|
|
|
430
345
|
Solves assembly-native kinematic links first. Controlled `addAngleBetweenLinks()` relationships read values from `state` by name, clamp to their declared limits, and expose the solved graph on `SolvedAssembly.kinematics`. Angles solve in the plane of their three authored link positions, so a limb that swings out of the `z = 0` plane poses correctly; structural edges hold their bone lengths so a fully angle-driven serial chain follows forward kinematics.
|
|
431
346
|
|
|
@@ -441,123 +356,79 @@ Connector-frame joints created by `connect()` / `match()` are also evaluated; th
|
|
|
441
356
|
return mech.solve({ theta: 45 });
|
|
442
357
|
```
|
|
443
358
|
|
|
444
|
-
```ts
|
|
445
|
-
solve(state?: JointState): SolvedAssembly
|
|
446
|
-
```
|
|
447
|
-
|
|
448
359
|
<!-- forgecad-skill:exclude-start symbol="Assembly.Compatibility methods" reason="Compatibility-only renamed API. Use `addAngleBetweenLinkSegmentAndWorldDirection()` instead." -->
|
|
449
360
|
**Compatibility**
|
|
450
361
|
<!-- forgecad-skill:exclude-end -->
|
|
451
362
|
|
|
452
363
|
<!-- forgecad-skill:exclude-start symbol="Assembly.addAngleOfLinkSegmentFromXAxis" reason="Compatibility-only renamed API. Use `addAngleBetweenLinkSegmentAndWorldDirection()` instead." -->
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
> **Not included in ForgeCAD AI skill context yet.** This API remains visible in human docs, but is intentionally omitted from shipped agent skills until it is ready for agent-first use. Compatibility-only renamed API. Use `addAngleBetweenLinkSegmentAndWorldDirection()` instead.
|
|
456
|
-
|
|
457
|
-
```ts
|
|
458
|
-
addAngleOfLinkSegmentFromXAxis(fromLink: string, toLink: string, options?: AssemblyAngleBetweenLinksOptions): Assembly
|
|
459
|
-
```
|
|
364
|
+
- `addAngleOfLinkSegmentFromXAxis(fromLink: string, toLink: string, options?: AssemblyAngleBetweenLinksOptions): Assembly`
|
|
460
365
|
<!-- forgecad-skill:exclude-end -->
|
|
461
366
|
|
|
462
367
|
<!-- forgecad-skill:exclude-start symbol="Assembly.addAngleOfLinkSegmentFromYAxis" reason="Compatibility-only renamed API. Use `addAngleBetweenLinkSegmentAndWorldDirection()` instead." -->
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
> **Not included in ForgeCAD AI skill context yet.** This API remains visible in human docs, but is intentionally omitted from shipped agent skills until it is ready for agent-first use. Compatibility-only renamed API. Use `addAngleBetweenLinkSegmentAndWorldDirection()` instead.
|
|
466
|
-
|
|
467
|
-
```ts
|
|
468
|
-
addAngleOfLinkSegmentFromYAxis(fromLink: string, toLink: string, options?: AssemblyAngleBetweenLinksOptions): Assembly
|
|
469
|
-
```
|
|
368
|
+
- `addAngleOfLinkSegmentFromYAxis(fromLink: string, toLink: string, options?: AssemblyAngleBetweenLinksOptions): Assembly`
|
|
470
369
|
<!-- forgecad-skill:exclude-end -->
|
|
471
370
|
|
|
472
|
-
<!-- forgecad-skill:exclude-start symbol="Assembly.toJointsView" reason="Compatibility-only viewport FK adapter. Prefer returning `Assembly` directly so controls move through the solver-backed link/edge kinematics model." -->
|
|
473
|
-
#### `toJointsView()` — Deprecated adapter that derives viewport-only FK controls from the assembly graph.
|
|
474
|
-
|
|
475
|
-
> **Not included in ForgeCAD AI skill context yet.** This API remains visible in human docs, but is intentionally omitted from shipped agent skills until it is ready for agent-first use. Compatibility-only viewport FK adapter. Prefer returning `Assembly` directly so controls move through the solver-backed link/edge kinematics model.
|
|
476
|
-
|
|
477
|
-
Prefer returning the `Assembly` itself. The runtime now exposes returned assembly controls automatically and re-evaluates the assembly with `solve(state)` when a control changes. That path is the source of truth for link/edge kinematics, handles closed-loop mechanisms through the real solver, and avoids stacking a viewport transform on top of already-solved geometry.
|
|
478
|
-
|
|
479
|
-
`toJointsView()` remains for legacy scripts that intentionally want the old viewport-only FK behavior.
|
|
480
|
-
|
|
481
|
-
**Legacy mirrored revolute tracks:** Viewport defaults and animation keyframes use physical joint values. If two mirrored revolute joints have opposite axes, equal keyframe values are not a mirrored pose; negate the mirrored side's values, or prefer returned-assembly controls so the solver owns the side-neutral state.
|
|
482
|
-
|
|
483
|
-
**Preferred**
|
|
484
|
-
|
|
485
|
-
```ts
|
|
486
|
-
return mech; // editor controls call mech.solve(state)
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
```ts
|
|
490
|
-
toJointsView(options?: ToJointsViewOptions): void
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
**`ToJointsViewOptions`**: `defaults?: Record<string, number>`, `overrides?: Record<string, Partial<JointViewInput>>`, `animations?: JointViewAnimationInput[]`, `couplings?: JointViewCouplingInput[]`, `defaultAnimation?: string`, `enabled?: boolean`
|
|
494
|
-
|
|
495
|
-
**`JointViewInput`**: `name: string`, `child: string`, `parent?: string`, `type?: JointViewType`, `axis?: JointViewAxis`, `pivot?: [ number, number, number ]`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `hidden?: boolean`
|
|
496
|
-
|
|
497
|
-
`JointViewAnimationInput`: `{ name: string, duration?: number, loop?: boolean, continuous?: boolean, keyframes: JointViewAnimationKeyframeInput[] }`
|
|
498
|
-
|
|
499
|
-
**`JointViewAnimationKeyframeInput`**
|
|
500
|
-
- `at?: number` — Timeline position [0, 1]. If omitted from ALL keyframes, positions are auto-computed from tick weights.
|
|
501
|
-
- `ticks?: number` — Relative weight of the segment from this keyframe to the next (default 1). Only used in tick-based mode (when `at` is omitted). Last keyframe's ticks value is ignored.
|
|
502
|
-
- Also: `values: Record<string, number>`
|
|
503
|
-
|
|
504
|
-
`JointViewCouplingInput`: `{ joint: string, terms: JointViewCouplingTermInput[], offset?: number }`
|
|
505
|
-
|
|
506
|
-
`JointViewCouplingTermInput`: `{ joint: string, ratio?: number }`
|
|
507
|
-
<!-- forgecad-skill:exclude-end -->
|
|
508
371
|
|
|
509
372
|
**Other**
|
|
510
373
|
|
|
511
|
-
#### `
|
|
374
|
+
#### `withSimulation(options: SimAssemblySimulationOptions): Assembly` — Attach the root simulation contract for this assembly.
|
|
512
375
|
|
|
513
|
-
|
|
514
|
-
mate(fn: (m: MateBuilder) => void): Assembly
|
|
515
|
-
```
|
|
376
|
+
Use this after adding physical parts and joints. Robot-body profiles require `rootPart`; asset profiles can describe one-part or multi-part physical assets. URDF/SDF exporters and `forgecad check simready` read this contract directly, so model files no longer need a separate `robotExport(...)` side effect.
|
|
516
377
|
|
|
517
|
-
|
|
378
|
+
`SimAssemblySimulationOptions`: `{ profile: SimProfileDef, rootPart?: string, controllers?: SimControllerDef[] }`
|
|
518
379
|
|
|
519
|
-
|
|
380
|
+
#### `edgeBetweenFrames(a: string, b: string, options?: AssemblyFrameEdgeOptions): Assembly` — Add a visual skeleton edge between two rig frame origins.
|
|
520
381
|
|
|
521
|
-
|
|
522
|
-
edgeBetweenFrames(a: string, b: string, options?: AssemblyFrameEdgeOptions): Assembly
|
|
523
|
-
```
|
|
382
|
+
Frame edges follow the solved frame poses produced by `fixedJoint()`, `revoluteJoint()`, and `prismaticJoint()`. They do not add constraints, degrees of freedom, parts, or geometry; use them to make a frame-only rig readable in the Motion/rig inspection overlay.
|
|
524
383
|
|
|
525
384
|
`AssemblyFrameEdgeOptions`: `{ name?: string, metadata?: Record<string, unknown> }`
|
|
526
385
|
|
|
527
|
-
#### `
|
|
386
|
+
#### `addAnimation(name: string, options: AssemblyAnimationOptions): Assembly` — Register a named keyframe animation for this assembly's Motion view.
|
|
528
387
|
|
|
529
|
-
|
|
388
|
+
Works with the returned-assembly controls path: return the unsolved `Assembly` and the animation appears in the Motion tab alongside the solver-backed joint controls. Keyframes hold control values by joint name; joints declared with `follows` are derived automatically and must not appear in keyframes.
|
|
530
389
|
|
|
531
390
|
```ts
|
|
532
|
-
|
|
391
|
+
robot.addAnimation("Pick and place", {
|
|
392
|
+
duration: 12,
|
|
393
|
+
loop: true,
|
|
394
|
+
keyframes: [
|
|
395
|
+
{ values: { J1: 0, J2: -90 } },
|
|
396
|
+
{ values: { J1: 45, J2: -30 } },
|
|
397
|
+
{ values: { J1: 0, J2: -90 } },
|
|
398
|
+
],
|
|
399
|
+
});
|
|
400
|
+
return robot;
|
|
533
401
|
```
|
|
534
402
|
|
|
535
|
-
|
|
403
|
+
**`AssemblyAnimationOptions`**
|
|
536
404
|
|
|
537
|
-
|
|
405
|
+
| Option | Type | Description |
|
|
406
|
+
|--------|------|-------------|
|
|
407
|
+
| `duration?` | `number` | Animation length in seconds (default chosen by the viewer). |
|
|
408
|
+
| `loop?` | `boolean` | Loop the animation (default false). |
|
|
409
|
+
| `continuous?` | `boolean` | Interpolate continuously through keyframes instead of pausing on each. |
|
|
410
|
+
| `keyframes` | `JointViewAnimationInput["keyframes"]` | Keyframes of control values by joint/control name. `at` (0..1) or `ticks` control timing. |
|
|
411
|
+
| `default?` | `boolean` | Make this the animation that plays when the model loads. |
|
|
538
412
|
|
|
539
|
-
|
|
540
|
-
linkAwayFrom(name: string, fromLink: string, awayFromLink: string, distance: number): Assembly
|
|
541
|
-
```
|
|
413
|
+
`JointViewAnimationInput`: `{ name: string, duration?: number, loop?: boolean, continuous?: boolean, keyframes: JointViewAnimationKeyframeInput[] }`
|
|
542
414
|
|
|
543
|
-
|
|
415
|
+
**`JointViewAnimationKeyframeInput`**
|
|
416
|
+
- `at?: number` — Timeline position [0, 1]. If omitted from ALL keyframes, positions are auto-computed from tick weights.
|
|
417
|
+
- `ticks?: number` — Relative weight of the segment from this keyframe to the next (default 1). Only used in tick-based mode (when `at` is omitted). Last keyframe's ticks value is ignored.
|
|
418
|
+
- Also: `values: Record<string, number>`.
|
|
544
419
|
|
|
545
|
-
|
|
546
|
-
describe(): AssemblyDefinition
|
|
547
|
-
```
|
|
420
|
+
#### `describe(): AssemblyDefinition` — Return the serializable assembly definition used by solve/inspect pipelines.
|
|
548
421
|
|
|
549
422
|
**Compatibility Aliases**
|
|
550
423
|
|
|
551
|
-
- `usedPortRefs` -> `usedConnectorRefs`
|
|
552
424
|
- `withPorts()` -> `withConnectors()`
|
|
553
425
|
- `getPorts()` -> `getConnectors()`
|
|
554
|
-
- `getPort()` -> `getConnector()`
|
|
555
426
|
|
|
556
427
|
### `ImportedAssembly`
|
|
557
428
|
|
|
558
429
|
A wrapper around an imported `Assembly` that provides kinematic access and convenient transform helpers.
|
|
559
430
|
|
|
560
|
-
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()` and `mergeInto()` —
|
|
431
|
+
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()` and `mergeInto()` — and converts to a static [`ShapeGroup`](/docs/core#shapegroup) via the explicit `toGroup(state?)` boundary when group-style transforms are needed.
|
|
561
432
|
|
|
562
433
|
**Kinematic access**
|
|
563
434
|
|
|
@@ -565,14 +436,14 @@ When a `.forge.js` file returns an unsolved `Assembly`, [`require()`](/docs/core
|
|
|
565
436
|
const arm = require("./arm.forge.js");
|
|
566
437
|
|
|
567
438
|
const solved = arm.solve({ shoulder: 45 }); // full kinematic solve
|
|
568
|
-
const link = arm.
|
|
439
|
+
const link = arm.getPart("Link", { shoulder: 60 }); // single part at state
|
|
569
440
|
const group = arm.toGroup({ shoulder: 45 }); // only when ShapeGroup behavior is needed
|
|
570
441
|
```
|
|
571
442
|
|
|
572
|
-
**
|
|
443
|
+
**Static positioning** — convert explicitly, then transform the group (`toGroup()` solves at default joint values and discards kinematics):
|
|
573
444
|
|
|
574
445
|
```ts
|
|
575
|
-
const positioned = arm.rotateZ(-90).translate(0, -20, 50);
|
|
446
|
+
const positioned = arm.toGroup().rotateZ(-90).translate(0, -20, 50);
|
|
576
447
|
```
|
|
577
448
|
|
|
578
449
|
**Merging into a parent**
|
|
@@ -586,154 +457,43 @@ require("./arm.forge.js").mergeInto(robot, {
|
|
|
586
457
|
});
|
|
587
458
|
```
|
|
588
459
|
|
|
589
|
-
#### `assembly()` — The underlying Assembly, for advanced composition and inspection.
|
|
590
|
-
|
|
591
|
-
```ts
|
|
592
|
-
get assembly(): Assembly
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
#### `solve()` — Solve the assembly at the given joint state (defaults to each joint's default value).
|
|
596
|
-
|
|
597
|
-
```ts
|
|
598
|
-
solve(state?: JointState): SolvedAssembly
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
#### `part()` — Return a specific named part positioned at the given joint state, with any stored placement offset applied.
|
|
602
|
-
|
|
603
|
-
```ts
|
|
604
|
-
part(name: string, state?: JointState): AssemblyPart
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
#### `getPart()` — Return a specific named part positioned at the default solved pose.
|
|
460
|
+
#### `get assembly(): Assembly` — The underlying Assembly, for advanced composition and inspection.
|
|
608
461
|
|
|
609
|
-
|
|
462
|
+
#### `solve(state?: JointState): SolvedAssembly` — Solve the assembly at the given joint state (defaults to each joint's default value).
|
|
610
463
|
|
|
611
|
-
|
|
612
|
-
getPart(partName: string): AssemblyPart
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
#### `toGroup()` — Convert all assembly parts to a ShapeGroup with named children. Use this for composition, transforms, or child lookup — not as a required render step for assemblies. Child names match the part names used in the assembly. Any stored placement offset and placement references are forwarded to the group.
|
|
616
|
-
|
|
617
|
-
```ts
|
|
618
|
-
toGroup(state?: JointState): ShapeGroup
|
|
619
|
-
```
|
|
464
|
+
#### `getPart(partName: string, state?: JointState): AssemblyPart` — Return a specific named part positioned at the solved pose, with any stored placement offset applied.
|
|
620
465
|
|
|
621
|
-
|
|
466
|
+
This mirrors `SolvedAssembly.getPart()` for imported assemblies, with one addition: any offset stored by `placeReference()` is applied, so the part lands where the imported assembly was placed. (`solve(state).getPart(name)` returns the part in the assembly's own coordinates, without that offset.)
|
|
622
467
|
|
|
623
|
-
|
|
624
|
-
withReferences(refs: Pick<PlacementReferenceInput, "points">): ImportedAssembly
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
#### `referenceNames()` — List all attached placement reference names.
|
|
628
|
-
|
|
629
|
-
```ts
|
|
630
|
-
referenceNames(kind?: PlacementReferenceKind): string[]
|
|
631
|
-
```
|
|
468
|
+
#### `toGroup(state?: JointState): ShapeGroup` — Convert all assembly parts to a ShapeGroup with named children. Use this for composition, transforms, or child lookup — not as a required render step for assemblies. Child names match the part names used in the assembly. Any stored placement offset and placement references are forwarded to the group.
|
|
632
469
|
|
|
633
|
-
#### `
|
|
634
|
-
|
|
635
|
-
```ts
|
|
636
|
-
placeReference(ref: string, target: [ number, number, number ], offset?: [ number, number, number ]): ImportedAssembly
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
#### `translate()` — Solve at defaults and return a translated ShapeGroup.
|
|
640
|
-
|
|
641
|
-
```ts
|
|
642
|
-
translate(x: number, y: number, z: number): ShapeGroup
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
#### `rotate()` — Solve at defaults and return a rotated ShapeGroup.
|
|
646
|
-
|
|
647
|
-
```ts
|
|
648
|
-
rotate(axis: [ number, number, number ], angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
649
|
-
```
|
|
470
|
+
#### `withReferences(refs: Pick<PlacementReferenceInput, "points">): ImportedAssembly` — 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.
|
|
650
471
|
|
|
651
|
-
#### `
|
|
652
|
-
|
|
653
|
-
```ts
|
|
654
|
-
rotateX(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
655
|
-
```
|
|
656
|
-
|
|
657
|
-
#### `rotateY()` — Solve at defaults and return a ShapeGroup rotated around Y.
|
|
658
|
-
|
|
659
|
-
```ts
|
|
660
|
-
rotateY(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
#### `rotateZ()` — Solve at defaults and return a ShapeGroup rotated around Z.
|
|
664
|
-
|
|
665
|
-
```ts
|
|
666
|
-
rotateZ(angleDeg: number, options?: { pivot?: [ number, number, number ]; }): ShapeGroup
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
#### `scale()` — Solve at defaults and return a scaled ShapeGroup.
|
|
670
|
-
|
|
671
|
-
```ts
|
|
672
|
-
scale(v: number | [ number, number, number ]): ShapeGroup
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
#### `mirror()` — Solve at defaults and return a mirrored ShapeGroup.
|
|
676
|
-
|
|
677
|
-
```ts
|
|
678
|
-
mirror(normal: [ number, number, number ]): ShapeGroup
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
#### `color()` — Solve at defaults and return a colored ShapeGroup.
|
|
682
|
-
|
|
683
|
-
```ts
|
|
684
|
-
color(hex: string): ShapeGroup
|
|
685
|
-
```
|
|
472
|
+
#### `referenceNames(kind?: PlacementReferenceKind): string[]` — List all attached placement reference names.
|
|
686
473
|
|
|
687
|
-
#### `
|
|
474
|
+
#### `placeReference(ref: string, target: Vec3, offset?: Vec3): ImportedAssembly` — 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.
|
|
688
475
|
|
|
689
|
-
|
|
690
|
-
child(name: string): Shape | Sketch | ShapeGroup
|
|
691
|
-
```
|
|
476
|
+
#### `child(name: string): Shape | Sketch | ShapeGroup` — Solve at defaults, get a named child part from the resulting group.
|
|
692
477
|
|
|
693
|
-
#### `collisionReport()` — Detect overlapping part pairs at the default solved pose.
|
|
478
|
+
#### `collisionReport(options?: CollisionOptions): CollisionFinding[]` — Detect overlapping part pairs at the default solved pose.
|
|
694
479
|
|
|
695
480
|
This mirrors `SolvedAssembly.collisionReport()` for imported assemblies. Use `solve(state).collisionReport(options)` when inspecting a non-default joint state.
|
|
696
481
|
|
|
697
|
-
```ts
|
|
698
|
-
collisionReport(options?: CollisionOptions): CollisionFinding[]
|
|
699
|
-
```
|
|
700
|
-
|
|
701
482
|
`CollisionOptions`: `{ parts?: string[], ignorePairs?: Array<[ string, string ]>, minOverlapVolume?: number }`
|
|
702
483
|
|
|
703
|
-
#### `minClearance()` — Compute the minimum gap between two parts at the default solved pose.
|
|
484
|
+
#### `minClearance(partA: string, partB: string, searchLength?: number): number` — Compute the minimum gap between two parts at the default solved pose.
|
|
704
485
|
|
|
705
486
|
This mirrors `SolvedAssembly.minClearance()` for imported assemblies. Use `solve(state).minClearance(partA, partB, searchLength)` when inspecting a non-default joint state.
|
|
706
487
|
|
|
707
|
-
|
|
708
|
-
minClearance(partA: string, partB: string, searchLength?: number): number
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
#### `mergeInto()` — Flatten this sub-assembly's parts and relationships into `parent` and wire a mount relationship.
|
|
488
|
+
#### `mergeInto(parent: Assembly, options: MergeIntoOptions): Assembly` — Flatten this sub-assembly's parts and relationships into `parent` and wire a mount relationship.
|
|
712
489
|
|
|
713
|
-
All part, link, and legacy joint names from the sub-assembly are prefixed with `"${options.prefix}."` to avoid collisions. After the merge, controls
|
|
490
|
+
All part, link, and legacy joint names from the sub-assembly are prefixed with `"${options.prefix}."` to avoid collisions; connectors are forwarded with the same prefix. After the merge, drive controls from the parent using the prefixed names:
|
|
714
491
|
|
|
715
492
|
```ts
|
|
716
493
|
parent.solve({ "Left Arm.theta": 45, "Right Arm.theta": -20 })
|
|
717
494
|
```
|
|
718
495
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
The sub-assembly must have exactly one root part before it can be merged.
|
|
722
|
-
|
|
723
|
-
```ts
|
|
724
|
-
const robot = assembly("Robot").addPart("Chassis", chassis);
|
|
725
|
-
|
|
726
|
-
require("./arm.forge.js").mergeInto(robot, {
|
|
727
|
-
prefix: "Left Arm",
|
|
728
|
-
mountParent: "Chassis",
|
|
729
|
-
mountJoint: "leftMount",
|
|
730
|
-
mountOptions: { frame: Transform.identity().translate(-70, 0, 10) },
|
|
731
|
-
});
|
|
732
|
-
```
|
|
733
|
-
|
|
734
|
-
```ts
|
|
735
|
-
mergeInto(parent: Assembly, options: MergeIntoOptions): Assembly
|
|
736
|
-
```
|
|
496
|
+
The sub-assembly must have exactly one root part before it can be merged (collapse multiple roots with `addFixed()` first). See the `ImportedAssembly` class docs for a full merge example.
|
|
737
497
|
|
|
738
498
|
**`MergeIntoOptions`**
|
|
739
499
|
|
|
@@ -750,7 +510,9 @@ mergeInto(parent: Assembly, options: MergeIntoOptions): Assembly
|
|
|
750
510
|
| Option | Type | Description |
|
|
751
511
|
|--------|------|-------------|
|
|
752
512
|
| `connectorRefs?` | `JointConnectorRefs` | Connector refs that define this joint contract. Usually set by `connect()` / `match()`. |
|
|
753
|
-
| `
|
|
513
|
+
| `follows?` | `JointFollowOptions` | Slave this joint to another joint: `value = ratio × source + offset`. Use for mechanisms with one physical DOF expressed through several joints — a mirrored gripper jaw (`ratio: -1`), a gear pair, a drive crank turning with its servo. A followed joint stops being an independent control: the Motion view drives it from its source, `solve()` derives its value (a direct state override is ignored with a warning), and limits still clamp the derived value. |
|
|
514
|
+
|
|
515
|
+
Also: `frame?: TransformInput`, `origin?: Vec3`, `axis?: Vec3`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `drive?: SimDriveDef`.
|
|
754
516
|
|
|
755
517
|
`JointConnectorRefs`: `{ parent: string, child: string, parentAlign?: PortAlign, childAlign?: PortAlign }`
|
|
756
518
|
|
|
@@ -778,73 +540,23 @@ return solved;
|
|
|
778
540
|
|
|
779
541
|
**Methods:**
|
|
780
542
|
|
|
781
|
-
#### `warnings()` — Return any warnings generated during solve (clamped joints, unconverged mates, etc.).
|
|
782
|
-
|
|
783
|
-
```ts
|
|
784
|
-
warnings(): string[]
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
#### `getJointState()` — Return a snapshot of resolved joint values (after clamping and coupling).
|
|
788
|
-
|
|
789
|
-
```ts
|
|
790
|
-
getJointState(): JointState
|
|
791
|
-
```
|
|
792
|
-
|
|
793
|
-
#### `mateExplodeHints()` — Explode direction hints derived from mate constraints, or null if no mates.
|
|
794
|
-
|
|
795
|
-
```ts
|
|
796
|
-
get mateExplodeHints(): Record<string, { direction: Vec3; }> | null
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
#### `mateDof()` — Remaining degrees of freedom after mate constraints, or null if no mates.
|
|
543
|
+
#### `warnings(): string[]` — Return any warnings generated during solve (clamped joints, unconverged mates, etc.).
|
|
800
544
|
|
|
801
|
-
|
|
802
|
-
get mateDof(): number | null
|
|
803
|
-
```
|
|
545
|
+
#### `getJointState(): JointState` — Return a snapshot of resolved joint values (after clamping and coupling).
|
|
804
546
|
|
|
805
|
-
#### `
|
|
547
|
+
#### `get kinematics(): SolvedAssemblyKinematics | null` — Solved assembly-native kinematic or frame-edge overlay data, or null when no rig overlay data was declared.
|
|
806
548
|
|
|
807
|
-
|
|
808
|
-
get mateConverged(): boolean | null
|
|
809
|
-
```
|
|
549
|
+
#### `getLinkPosition(linkName: string): Vec3` — Return the solved world position of a kinematic link.
|
|
810
550
|
|
|
811
|
-
#### `
|
|
551
|
+
#### `getFrame(frameName: string): Transform` — Return the solved world transform for a named rig frame.
|
|
812
552
|
|
|
813
|
-
|
|
814
|
-
get kinematics(): SolvedAssemblyKinematics | null
|
|
815
|
-
```
|
|
553
|
+
#### `get frames(): SolvedAssemblyFrameDef[]` — Return solved rig frames, including origin, axis, up, and transform.
|
|
816
554
|
|
|
817
|
-
#### `
|
|
555
|
+
#### `getTransform(partName: string): Transform` — Return the world-space [`Transform`](/docs/core#transform) for the named part at the solved pose.
|
|
818
556
|
|
|
819
|
-
|
|
820
|
-
getLinkPosition(linkName: string): Vec3
|
|
821
|
-
```
|
|
557
|
+
#### `getPart(partName: string): AssemblyPart` — Return the named part already positioned at its solved world transform.
|
|
822
558
|
|
|
823
|
-
#### `
|
|
824
|
-
|
|
825
|
-
```ts
|
|
826
|
-
getFrame(frameName: string): Transform
|
|
827
|
-
```
|
|
828
|
-
|
|
829
|
-
#### `frames()` — Return solved rig frames, including origin, axis, up, and transform.
|
|
830
|
-
|
|
831
|
-
```ts
|
|
832
|
-
get frames(): SolvedAssemblyFrameDef[]
|
|
833
|
-
```
|
|
834
|
-
|
|
835
|
-
#### `getTransform()` — Return the world-space [`Transform`](/docs/core#transform) for the named part at the solved pose.
|
|
836
|
-
|
|
837
|
-
```ts
|
|
838
|
-
getTransform(partName: string): Transform
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
#### `getPart()` — Return the named part already positioned at its solved world transform.
|
|
842
|
-
|
|
843
|
-
```ts
|
|
844
|
-
getPart(partName: string): AssemblyPart
|
|
845
|
-
```
|
|
846
|
-
|
|
847
|
-
#### `toGroup()` — Convert all solved parts into a [`ShapeGroup`](/docs/core#shapegroup) with named children.
|
|
559
|
+
#### `toGroup(): ShapeGroup` — Convert all solved parts into a [`ShapeGroup`](/docs/core#shapegroup) with named children.
|
|
848
560
|
|
|
849
561
|
Each part becomes a named child in the group, already positioned at its solved world transform. Use this only when you specifically need a [`ShapeGroup`](/docs/core#shapegroup) for composition, [`ShapeGroup`](/docs/core#shapegroup) transforms, or named-child access. Top-level scripts can return the `SolvedAssembly` directly; do not call `toGroup()` just to make a solved assembly render.
|
|
850
562
|
|
|
@@ -853,37 +565,15 @@ const armGroup = mech.solve({ shoulder: 60 }).toGroup(); // only because we need
|
|
|
853
565
|
return armGroup.rotateZ(90);
|
|
854
566
|
```
|
|
855
567
|
|
|
856
|
-
|
|
857
|
-
toGroup(): ShapeGroup
|
|
858
|
-
```
|
|
859
|
-
|
|
860
|
-
#### `toSceneObjects()` — Return an array of named scene objects for the viewport renderer.
|
|
568
|
+
#### `toSceneObjects(): Array<{ ... }>` — Return an array of named scene objects for the viewport renderer.
|
|
861
569
|
|
|
862
570
|
Each part becomes `{ name, shape }` or `{ name, group: [...] }` if the part is a [`ShapeGroup`](/docs/core#shapegroup). Top-level scripts should normally return the `SolvedAssembly` directly. Use `toGroup()` when you need [`ShapeGroup`](/docs/core#shapegroup) behavior; use this method only for advanced scene-graph control where you need access to the flat per-part array with metadata.
|
|
863
571
|
|
|
864
|
-
|
|
865
|
-
toSceneObjects(): Array<{ name: string; shape?: Shape; group?: Array<{ name: string; shape: Shape; tags?: string[]; }>; metadata?: PartMetadata; }>
|
|
866
|
-
```
|
|
867
|
-
|
|
868
|
-
#### `toScene()` — Backward-compatible alias for `toSceneObjects()`.
|
|
572
|
+
#### `bom(): BomRow[]` — Generate a bill of materials for all parts in the solved assembly.
|
|
869
573
|
|
|
870
|
-
|
|
871
|
-
toScene(): Array<{ name: string; shape?: Shape; group?: Array<{ name: string; shape: Shape; tags?: string[]; }>; metadata?: PartMetadata; }>
|
|
872
|
-
```
|
|
574
|
+
#### `bomCsv(): string` — Generate a bill of materials as a CSV string.
|
|
873
575
|
|
|
874
|
-
####
|
|
875
|
-
|
|
876
|
-
```ts
|
|
877
|
-
bom(): BomRow[]
|
|
878
|
-
```
|
|
879
|
-
|
|
880
|
-
#### `bomCsv()` — Generate a bill of materials as a CSV string.
|
|
881
|
-
|
|
882
|
-
```ts
|
|
883
|
-
bomCsv(): string
|
|
884
|
-
```
|
|
885
|
-
|
|
886
|
-
#### `collisionReport()` — Detect overlapping (colliding) part pairs in this solved pose.
|
|
576
|
+
#### `collisionReport(options?: CollisionOptions): CollisionFinding[]` — Detect overlapping (colliding) part pairs in this solved pose.
|
|
887
577
|
|
|
888
578
|
Computes boolean intersections between all part pairs and returns findings where the overlap volume exceeds `minOverlapVolume` (default 0.1 mm³).
|
|
889
579
|
|
|
@@ -892,90 +582,6 @@ const solved = mech.solve({ shoulder: 35, elbow: 60 });
|
|
|
892
582
|
console.log("Collisions", solved.collisionReport());
|
|
893
583
|
```
|
|
894
584
|
|
|
895
|
-
|
|
896
|
-
collisionReport(options?: CollisionOptions): CollisionFinding[]
|
|
897
|
-
```
|
|
898
|
-
|
|
899
|
-
#### `minClearance()` — Compute the minimum gap (clearance) between two parts in this solved pose.
|
|
585
|
+
#### `minClearance(partA: string, partB: string, searchLength?: number): number` — Compute the minimum gap (clearance) between two parts in this solved pose.
|
|
900
586
|
|
|
901
587
|
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.
|
|
902
|
-
|
|
903
|
-
```ts
|
|
904
|
-
minClearance(partA: string, partB: string, searchLength?: number): number
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
### `MateBuilder`
|
|
908
|
-
|
|
909
|
-
**Properties:**
|
|
910
|
-
|
|
911
|
-
| Property | Type | Description |
|
|
912
|
-
|----------|------|-------------|
|
|
913
|
-
| `constraints` | `Constraint3D[]` | — |
|
|
914
|
-
|
|
915
|
-
**Methods:**
|
|
916
|
-
|
|
917
|
-
#### `flush()` — Constrain two faces so they stay flush.
|
|
918
|
-
|
|
919
|
-
```ts
|
|
920
|
-
flush(faceA: string, faceB: string): string
|
|
921
|
-
```
|
|
922
|
-
|
|
923
|
-
#### `align()` — Constrain two faces so their normals align.
|
|
924
|
-
|
|
925
|
-
```ts
|
|
926
|
-
align(faceA: string, faceB: string): string
|
|
927
|
-
```
|
|
928
|
-
|
|
929
|
-
#### `parallel()` — Constrain two faces so they remain parallel.
|
|
930
|
-
|
|
931
|
-
```ts
|
|
932
|
-
parallel(faceA: string, faceB: string): string
|
|
933
|
-
```
|
|
934
|
-
|
|
935
|
-
#### `faceDistance()` — Constrain the distance between two faces.
|
|
936
|
-
|
|
937
|
-
```ts
|
|
938
|
-
faceDistance(faceA: string, faceB: string, distance: number): string
|
|
939
|
-
```
|
|
940
|
-
|
|
941
|
-
#### `concentric()` — Constrain two axes to share the same center line.
|
|
942
|
-
|
|
943
|
-
```ts
|
|
944
|
-
concentric(axisA: string, axisB: string): string
|
|
945
|
-
```
|
|
946
|
-
|
|
947
|
-
#### `axisParallel()` — Constrain two axes to remain parallel.
|
|
948
|
-
|
|
949
|
-
```ts
|
|
950
|
-
axisParallel(axisA: string, axisB: string): string
|
|
951
|
-
```
|
|
952
|
-
|
|
953
|
-
#### `pointCoincident()` — Constrain two points to coincide.
|
|
954
|
-
|
|
955
|
-
```ts
|
|
956
|
-
pointCoincident(pointA: string, pointB: string): string
|
|
957
|
-
```
|
|
958
|
-
|
|
959
|
-
#### `pointOnFace()` — Constrain a point to lie on a face.
|
|
960
|
-
|
|
961
|
-
```ts
|
|
962
|
-
pointOnFace(point: string, face: string): string
|
|
963
|
-
```
|
|
964
|
-
|
|
965
|
-
#### `pointOnAxis()` — Constrain a point to lie on an axis.
|
|
966
|
-
|
|
967
|
-
```ts
|
|
968
|
-
pointOnAxis(point: string, axis: string): string
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
#### `angle()` — Constrain the angle between two faces.
|
|
972
|
-
|
|
973
|
-
```ts
|
|
974
|
-
angle(faceA: string, faceB: string, degrees: number): string
|
|
975
|
-
```
|
|
976
|
-
|
|
977
|
-
#### `totalEquations()` — Total constraint equations.
|
|
978
|
-
|
|
979
|
-
```ts
|
|
980
|
-
get totalEquations(): number
|
|
981
|
-
```
|