forgecad 0.9.15 → 0.9.16
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-CDyGUinA.js → AdminPage-CXvls4-J.js} +1 -1
- package/dist/assets/{BenchmarkPage-DfPMY_-d.js → BenchmarkPage-B27zk8xL.js} +1 -1
- package/dist/assets/{BlogPage-kF0fkdJT.js → BlogPage-CMAVvgQL.js} +1 -1
- package/dist/assets/{DocsPage-B954L3YN.js → DocsPage-knf4I4h7.js} +1 -1
- package/dist/assets/EditorApp-BHMQlJ-D.js +14686 -0
- package/dist/assets/{EditorApp-CuDLxKqL.css → EditorApp-BpjZgzk0.css} +148 -0
- package/dist/assets/{EmbedViewer-C77B-TrF.js → EmbedViewer-D7ZGlFjx.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-Cr6fXMDj.js → LandingPageProofDriven-CnevhTE8.js} +2 -2
- package/dist/assets/{LegalPage-Dzklqmmg.js → LegalPage-BPTUmqeg.js} +1 -1
- package/dist/assets/{PricingPage-zWXkvlwl.js → PricingPage-B0D4goG_.js} +1 -1
- package/dist/assets/{SettingsPage-Bz0of4KQ.js → SettingsPage-CFF-UgjI.js} +1 -1
- package/dist/assets/{app-D3kDkggg.js → app-T0pDcSX4.js} +1184 -218
- package/dist/assets/cli/{render-DSY3mMQa.js → render-C5pcIISc.js} +144 -26
- package/dist/assets/{constructionHistoryWorker-gpDo-uH2.js → constructionHistoryWorker-Ba2Hm58b.js} +1 -0
- package/dist/assets/{evalWorker-CU0Ke6DP.js → evalWorker-vkx310U2.js} +1380 -2173
- package/dist/assets/{inspectWorker-COyp8XXA.js → inspectWorker-BuTJDVX6.js} +252 -30
- package/dist/assets/{targets-B9sGB5nB.js → jointPose-B_Cgedn9.js} +71 -3
- package/dist/assets/{manifold-DNkrUWpA.js → manifold-BWgsjmAM.js} +1 -1
- package/dist/assets/{manifold-C-3h2M7p.js → manifold-D6IFSkhH.js} +2 -2
- package/dist/assets/{manifold-BRI5prcH.js → manifold-rZexZI0G.js} +1 -1
- package/dist/assets/{reportWorker-CdBz5bNg.js → reportWorker-0AGij1Ru.js} +1373 -2166
- package/dist/assets/{scalar-sampling-budget-wJF98aY9.js → scalar-sampling-budget-J5cuzxT1.js} +1494 -2251
- package/dist/assets/{scanProxyWorker-B-9VbLIs.js → scanProxyWorker-Vl4Wxa1y.js} +18 -5
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +1 -1
- package/dist/docs-raw/AI/usage.md +2 -0
- package/dist/docs-raw/CLI.md +4 -0
- package/dist/docs-raw/generated/assembly.md +104 -6
- package/dist/docs-raw/generated/concepts.md +14 -4
- package/dist/docs-raw/generated/lib.md +2 -18
- package/dist/docs-raw/generated/output.md +14 -4
- package/dist/docs-raw/generated/runtime-names.md +27 -19
- package/dist/docs-raw/skills/forgecad-make-a-model.md +39 -38
- package/dist/docs-raw/skills/forgecad-project.md +2 -0
- package/dist/docs-raw/welcome.md +2 -0
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +13 -13
- package/dist-cli/{check-compiler-SDX5QIXI.js → check-compiler-SYQ2PWOB.js} +1 -1
- package/dist-cli/{check-query-propagation-EAYEFT77.js → check-query-propagation-HIAGV62W.js} +1 -1
- package/dist-cli/{chunk-N4O47JLF.js → chunk-SPZE3DUY.js} +1591 -2356
- package/dist-cli/forgecad.js +1698 -487
- package/dist-skill/CONTEXT.md +117 -46
- package/dist-skill/docs/CLI.md +4 -0
- package/dist-skill/docs/generated/assembly.md +83 -5
- package/dist-skill/docs/generated/lib.md +2 -18
- package/dist-skill/docs/generated/output.md +14 -4
- package/dist-skill/docs/generated/runtime-names.md +18 -19
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +39 -38
- package/dist-skill/library/forgecad-project/SKILL.md +2 -0
- package/examples/api/helix-basics.forge.js +2 -2
- package/examples/api/route3d-elbow.forge.js +3 -0
- package/examples/api/variable-sweep-test.forge.js +3 -1
- package/package.json +4 -1
- package/dist/assets/EditorApp-Beb-IZ0y.js +0 -14014
- package/examples/api/bolted-service-cover.forge.js +0 -17
- package/examples/api/cable-gland-anchor.forge.js +0 -14
- package/examples/api/captured-cartridge-guide.forge.js +0 -14
- package/examples/api/captured-linear-slide.forge.js +0 -13
- package/examples/api/clevis-pin-joint.forge.js +0 -13
- package/examples/api/datum-enclosure.forge.js +0 -16
- package/examples/api/hose-barb-port.forge.js +0 -14
- package/examples/api/knuckled-hinge-assembly.forge.js +0 -15
- package/examples/api/living-hinge-cover.forge.js +0 -14
- package/examples/api/pcb-terminal-block.forge.js +0 -22
- package/examples/api/pinned-lever-pivot-stack.forge.js +0 -14
- package/examples/api/retained-shaft-knob-stack.forge.js +0 -15
- package/examples/api/routed-tube-clip.forge.js +0 -15
- package/examples/api/seated-bearing-stack.forge.js +0 -30
- package/examples/api/snap-latch-cover.forge.js +0 -14
- package/examples/api/thumb-screw-clamp.forge.js +0 -15
package/dist-skill/CONTEXT.md
CHANGED
|
@@ -293,25 +293,24 @@ These collision-reserved names are case-sensitive:
|
|
|
293
293
|
activateBackend, Analysis, arcSlot, assembly, Assembly, assemblyInstructions, assemblyPreview, Blend
|
|
294
294
|
bom, bomToCsv, boolParam, box, cameraTrajectory, Carrier, chamfer, chamferTrackedEdge
|
|
295
295
|
choiceParam, circle, circle2d, Circle2D, circularLayout, circularPattern, circularPattern2d, coalesceEdges
|
|
296
|
-
combine, COMMON_KERFS, compareWith, composeChain,
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
variableSweep, verify, viewConfig, Viewport, window, Wood
|
|
296
|
+
combine, COMMON_KERFS, compareWith, composeChain, connector, console, constrainedSketch, Constraint
|
|
297
|
+
Counterbore, Curve, Curve3D, cutPlane, cylinder, degrees, difference, difference2d
|
|
298
|
+
dim, dimLine, draft, ellipse, explodeView, faceProfile, fillet, filletCorners
|
|
299
|
+
filletTrackedEdge, fingerJoint, flatPanel, flatPart, formatInstructions, Function, gcode, GCodeBuilder
|
|
300
|
+
getActiveBackend, global, globalThis, group, highlight, Import, ImportedAssembly, importMesh
|
|
301
|
+
importStep, importSvgSketch, initKernel, intersection, intersection2d, intersectWithPlane, joint, jointsView
|
|
302
|
+
laserKit, lib, line, Line2D, linearPattern, linearPattern2d, listParam, loadFont
|
|
303
|
+
loft, Loft, lookupKerf, mirrorCopy, mock, ngon, NurbsCurve3D, nurbsSurface
|
|
304
|
+
NurbsSurface, offsetSolid, param, Param, path, point, Point2D, Points
|
|
305
|
+
polygon, polygonVertices, port, Product, ProductHandleBuilder, ProductHandleFeature, ProductPanelBuilder, ProductRibbonBuilder
|
|
306
|
+
ProductSkin, ProductSkinBuilder, ProductSpoutBuilder, ProductStationBuilder, ProductSurfaceBuilder, ProductSurfaceRef, projectToPlane, queueMicrotask
|
|
307
|
+
radians, rect, Rectangle2D, Ribs, robotExport, roundedRect, Route3D, scene
|
|
308
|
+
Sculpt, sdf, SdfShape, selectEdge, selectEdges, self, setActiveBackend, setImmediate
|
|
309
|
+
setInterval, setTimeout, Shape, ShapeGroup, sheetMetal, SheetMetalPart, sheetStock, Sketch
|
|
310
|
+
sketchToDxf, sketchToSvg, slot, Slot, SolvedAssembly, spec, sphere, spline2d
|
|
311
|
+
star, stroke, Surface, SurfaceBody, SurfaceMembers, surfacePatch, sweep, tabSlot
|
|
312
|
+
text2d, textWidth, torus, toShape, Transform, union, union2d, variableSweep
|
|
313
|
+
verify, viewConfig, Viewport, window, Wood
|
|
315
314
|
```
|
|
316
315
|
|
|
317
316
|
`showLabels` is also a runtime global, but it is not part of the top-level collision check. Avoid reusing it unless you intentionally want a local value with that name.
|
|
@@ -7537,6 +7536,16 @@ addAngleBetweenLinks(a: string, b: string, c: string, options?: AssemblyAngleBet
|
|
|
7537
7536
|
|
|
7538
7537
|
`AssemblyKinematicLimitOptions`: `{ min?: number, max?: number }`
|
|
7539
7538
|
|
|
7539
|
+
#### `addAngleBetweenLinkSegmentAndWorldDirection()` — Add an absolute angle relationship from a world direction to a link segment.
|
|
7540
|
+
|
|
7541
|
+
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.
|
|
7542
|
+
|
|
7543
|
+
Use `Points.polar(1, angleDeg)` when the reference direction is planar and angle-based instead of axis-aligned.
|
|
7544
|
+
|
|
7545
|
+
```ts
|
|
7546
|
+
addAngleBetweenLinkSegmentAndWorldDirection(fromLink: string, toLink: string, direction: Vec3, options?: AssemblyAngleBetweenLinksOptions): Assembly
|
|
7547
|
+
```
|
|
7548
|
+
|
|
7540
7549
|
#### `describeKinematics()` — Return the assembly-native kinematic graph definition.
|
|
7541
7550
|
|
|
7542
7551
|
```ts
|
|
@@ -7565,19 +7574,49 @@ assembly.addPart("Base Assembly", housing);
|
|
|
7565
7574
|
addPart(name: string, part: AssemblyPart, options?: PartOptions): Assembly
|
|
7566
7575
|
```
|
|
7567
7576
|
|
|
7568
|
-
|
|
7577
|
+
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
7569
7578
|
|
|
7570
7579
|
**`AssemblyPartMateInput`**
|
|
7571
7580
|
- `connector: string` — Name of a connector declared on the part (via `withConnectors()`).
|
|
7572
7581
|
- `toLink: string` — Name of the link this connector's origin is pinned to.
|
|
7573
7582
|
- `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).
|
|
7574
7583
|
|
|
7575
|
-
#### `
|
|
7584
|
+
#### `frame()` — Add a named rig frame to the assembly.
|
|
7585
|
+
|
|
7586
|
+
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.
|
|
7576
7587
|
|
|
7577
|
-
|
|
7588
|
+
```ts
|
|
7589
|
+
frame(name: string, options: AssemblyFrameOptions): Assembly
|
|
7590
|
+
```
|
|
7591
|
+
|
|
7592
|
+
**`AssemblyFrameOptions`**: `origin: [ number, number, number ]`, `axis: [ number, number, number ]`, `up: [ number, number, number ]`, `fixed?: boolean`, `metadata?: Record<string, unknown>`
|
|
7593
|
+
|
|
7594
|
+
#### `fixedJoint()` — Rigidly attach a child rig frame to a parent rig frame.
|
|
7595
|
+
|
|
7596
|
+
Fixed joints carry frame hierarchy but do not expose a Motion control.
|
|
7578
7597
|
|
|
7579
7598
|
```ts
|
|
7580
|
-
|
|
7599
|
+
fixedJoint(name: string, options: AssemblyFixedFrameJointOptions): Assembly
|
|
7600
|
+
```
|
|
7601
|
+
|
|
7602
|
+
`AssemblyFixedFrameJointOptions`: `{ parent: string, child: string, metadata?: Record<string, unknown> }`
|
|
7603
|
+
|
|
7604
|
+
#### `revoluteJoint()` — Add a revolute rig-frame joint.
|
|
7605
|
+
|
|
7606
|
+
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.
|
|
7607
|
+
|
|
7608
|
+
```ts
|
|
7609
|
+
revoluteJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly
|
|
7610
|
+
```
|
|
7611
|
+
|
|
7612
|
+
**`AssemblyMovingFrameJointOptions`**: `parent: string`, `child: string`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `control?: boolean`, `metadata?: Record<string, unknown>`
|
|
7613
|
+
|
|
7614
|
+
#### `prismaticJoint()` — Add a prismatic rig-frame joint.
|
|
7615
|
+
|
|
7616
|
+
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.
|
|
7617
|
+
|
|
7618
|
+
```ts
|
|
7619
|
+
prismaticJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly
|
|
7581
7620
|
```
|
|
7582
7621
|
|
|
7583
7622
|
**Connectors**
|
|
@@ -7743,6 +7782,32 @@ solve(state?: JointState): SolvedAssembly
|
|
|
7743
7782
|
mate(fn: (m: MateBuilder) => void): Assembly
|
|
7744
7783
|
```
|
|
7745
7784
|
|
|
7785
|
+
#### `edgeBetweenFrames()` — Add a visual skeleton edge between two rig frame origins.
|
|
7786
|
+
|
|
7787
|
+
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.
|
|
7788
|
+
|
|
7789
|
+
```ts
|
|
7790
|
+
edgeBetweenFrames(a: string, b: string, options?: AssemblyFrameEdgeOptions): Assembly
|
|
7791
|
+
```
|
|
7792
|
+
|
|
7793
|
+
`AssemblyFrameEdgeOptions`: `{ name?: string, metadata?: Record<string, unknown> }`
|
|
7794
|
+
|
|
7795
|
+
#### `linkToward()` — Create a derived link at a fixed distance from `fromLink` toward `towardLink`.
|
|
7796
|
+
|
|
7797
|
+
Derived links are trace/reference points. They are recomputed after the primary link solve and cannot participate in structural edges or angle constraints.
|
|
7798
|
+
|
|
7799
|
+
```ts
|
|
7800
|
+
linkToward(name: string, fromLink: string, towardLink: string, distance: number): Assembly
|
|
7801
|
+
```
|
|
7802
|
+
|
|
7803
|
+
#### `linkAwayFrom()` — Create a derived link at a fixed distance from `fromLink` away from `awayFromLink`.
|
|
7804
|
+
|
|
7805
|
+
Use this for coupler trace/extension points such as the Chebyshev lambda linkage's point beyond the rocker joint.
|
|
7806
|
+
|
|
7807
|
+
```ts
|
|
7808
|
+
linkAwayFrom(name: string, fromLink: string, awayFromLink: string, distance: number): Assembly
|
|
7809
|
+
```
|
|
7810
|
+
|
|
7746
7811
|
#### `describe()` — Return the serializable assembly definition used by solve/inspect pipelines.
|
|
7747
7812
|
|
|
7748
7813
|
```ts
|
|
@@ -8011,7 +8076,7 @@ get mateDof(): number | null
|
|
|
8011
8076
|
get mateConverged(): boolean | null
|
|
8012
8077
|
```
|
|
8013
8078
|
|
|
8014
|
-
#### `kinematics()` — Solved assembly-native kinematic
|
|
8079
|
+
#### `kinematics()` — Solved assembly-native kinematic or frame-edge overlay data, or null when no rig overlay data was declared.
|
|
8015
8080
|
|
|
8016
8081
|
```ts
|
|
8017
8082
|
get kinematics(): SolvedAssemblyKinematics | null
|
|
@@ -8023,6 +8088,18 @@ get kinematics(): SolvedAssemblyKinematics | null
|
|
|
8023
8088
|
getLinkPosition(linkName: string): Vec3
|
|
8024
8089
|
```
|
|
8025
8090
|
|
|
8091
|
+
#### `getFrame()` — Return the solved world transform for a named rig frame.
|
|
8092
|
+
|
|
8093
|
+
```ts
|
|
8094
|
+
getFrame(frameName: string): Transform
|
|
8095
|
+
```
|
|
8096
|
+
|
|
8097
|
+
#### `frames()` — Return solved rig frames, including origin, axis, up, and transform.
|
|
8098
|
+
|
|
8099
|
+
```ts
|
|
8100
|
+
get frames(): SolvedAssemblyFrameDef[]
|
|
8101
|
+
```
|
|
8102
|
+
|
|
8026
8103
|
#### `getTransform()` — Return the world-space [`Transform`](/docs/core#transform) for the named part at the solved pose.
|
|
8027
8104
|
|
|
8028
8105
|
```ts
|
|
@@ -8825,9 +8902,9 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
8825
8902
|
|
|
8826
8903
|
**`CollectedRobotExport`**: `modelName: string`, `assembly: AssemblyDefinition`, `state: JointState`, `static: boolean`, `selfCollide: boolean`, `allowAutoDisable: boolean`, `links: Record<string, RobotLinkExportOptions>`, `joints: Record<string, RobotJointExportOptions>`, `plugins: { diffDrive?: RobotDiffDrivePluginOptions; jointStatePublisher?: RobotJointStatePublisherOptions; }`, `world: RobotWorldOptions | null`
|
|
8827
8904
|
|
|
8828
|
-
**`AssemblyDefinition`**: `name: string`, `parts: AssemblyPartDef[]`, `joints: AssemblyJointDef[]`, `jointCouplings: AssemblyJointCouplingDef[]`, `kinematics: AssemblyKinematicGraphDef`
|
|
8905
|
+
**`AssemblyDefinition`**: `name: string`, `parts: AssemblyPartDef[]`, `joints: AssemblyJointDef[]`, `jointCouplings: AssemblyJointCouplingDef[]`, `kinematics: AssemblyKinematicGraphDef`, `frames: AssemblyFrameDef[]`, `frameJoints: AssemblyFrameJointDef[]`, `frameEdges: AssemblyFrameEdgeDef[]`
|
|
8829
8906
|
|
|
8830
|
-
|
|
8907
|
+
**`AssemblyPartDef`**: `name: string`, `part: AssemblyPart`, `base: Transform`, `metadata?: PartMetadata`, `mates: AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
8831
8908
|
|
|
8832
8909
|
**`PartMetadata`**
|
|
8833
8910
|
|
|
@@ -8849,7 +8926,7 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
8849
8926
|
|
|
8850
8927
|
`JointCouplingTermRecord`: `{ joint: string, ratio: number }`
|
|
8851
8928
|
|
|
8852
|
-
|
|
8929
|
+
**`AssemblyKinematicGraphDef`**: `links: AssemblyLinkDef[]`, `edges: AssemblyEdgeBetweenLinksDef[]`, `angles: AssemblyAngleBetweenLinksDef[]`, `derivedLinks: AssemblyDerivedLinkDef[]`
|
|
8853
8930
|
|
|
8854
8931
|
`AssemblyLinkDef`: `{ name: string, at: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
8855
8932
|
|
|
@@ -8857,7 +8934,17 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
8857
8934
|
|
|
8858
8935
|
`AssemblyKinematicControlOptions`: `{ min?: number, max?: number, default?: number, unit?: string }`
|
|
8859
8936
|
|
|
8860
|
-
**`AssemblyAngleBetweenLinksDef`**: `name: string`, `a
|
|
8937
|
+
**`AssemblyAngleBetweenLinksDef`**: `name: string`, `a?: string`, `b: string`, `c: string`, `reference?: AssemblyAngleReferenceDef`, `target?: number`, `min?: number`, `max?: number`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
8938
|
+
|
|
8939
|
+
`AssemblyAngleReferenceDef`: `{ kind: "worldDirection", direction: Vec3 }`
|
|
8940
|
+
|
|
8941
|
+
`AssemblyDerivedLinkDef`: `{ name: string, fromLink: string, referenceLink: string, distance: number, direction: AssemblyDerivedLinkDirection }`
|
|
8942
|
+
|
|
8943
|
+
`AssemblyFrameDef`: `{ name: string, origin: Vec3, axis: Vec3, up: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
8944
|
+
|
|
8945
|
+
**`AssemblyFrameJointDef`**: `name: string`, `type: AssemblyFrameJointType`, `parent: string`, `child: string`, `rest: Transform`, `min?: number`, `max?: number`, `defaultValue: number`, `unit?: string`, `control: boolean`, `metadata?: Record<string, unknown>`
|
|
8946
|
+
|
|
8947
|
+
`AssemblyFrameEdgeDef`: `{ name: string, a: string, b: string, metadata?: Record<string, unknown> }`
|
|
8861
8948
|
|
|
8862
8949
|
#### `dim()` — Add a dimension annotation between two points.
|
|
8863
8950
|
|
|
@@ -9040,7 +9127,7 @@ Pre-built parametric parts available in user scripts as `lib.*`.
|
|
|
9040
9127
|
|
|
9041
9128
|
Every key in this object becomes a method or namespace on the `lib` object exposed to `.forge.js` scripts. The catalog includes:
|
|
9042
9129
|
|
|
9043
|
-
**Fasteners and hardware patterns:** `bolt`, `nut`, `washer`, `fastenerSet`, `
|
|
9130
|
+
**Fasteners and hardware patterns:** `bolt`, `nut`, `washer`, `fastenerSet`, `fastenerHole`, `boltHole`, `counterbore`, `hexNut`, `holePattern`
|
|
9044
9131
|
|
|
9045
9132
|
**Structure:** `tube`, `pipe`, `bracket`, `pipeRoute`, `elbow`, `tSlotProfile`, `tSlotExtrusion`, `profile2020BSlot6Profile`, `profile2020BSlot6`
|
|
9046
9133
|
|
|
@@ -9074,24 +9161,8 @@ Sizes outside the supported ranges will throw at runtime with a descriptive erro
|
|
|
9074
9161
|
- `nut(diameter: number, options?: { pitch?: number; height?: number; acrossFlats?: number; segments?: number; }): Shape` — ISO-style hex nut with a threaded bore. **Details** Constructed from the intersection of three rotated slabs with a cylindrical bore subtracted. The nut is centered at the origin, height along Z. Default proportions follow ISO 4032 loosely: height ≈ 0.8×diameter, across-flats ≈ 1.6×diameter. The bore is a clearance bore (not modelled with helical threads) for rendering efficiency. For standard M-size nuts pre-configured for a complete joint, use { **Example** ```ts const n = lib.nut(5); // M5 nut ```
|
|
9075
9162
|
- `washer(size: MetricSize, options?: { standard?: WasherStandard; segments?: number; }): Shape` — ISO metric flat washer (DIN 125-A). **Details** Returns a flat ring centered at the origin, thickness along Z. Dimensions are taken from { **Example** ```ts const w = lib.washer('M5'); // DIN 125-A M5 washer ```
|
|
9076
9163
|
- `fastenerSet(size: MetricSize, boltLength: number, options?: FastenerSetOptions): FastenerSetResult` — Complete ISO metric fastener set — bolt, nut, optional washers, and matching hole cutters. **Details** Returns all geometry for one bolted joint: the bolt, nut, up to two washers, a clearance-hole cutter, and a tap-drill cutter. All shapes are returned **un-positioned** (each on the Z-axis). Place them with `.translate()`. Sizes outside M4–M10 are supported for the washer (M2–M10); unsupported combinations will throw. **Example** ```ts const hw = lib.fastenerSet('M5', 20); const topPlate = box(60, 40, 8).translate(0, 0, 12) .subtract(hw.clearanceHole.translate(15, 10, 12)); const botPlate = box(60, 40, 8) .subtract(hw.clearanceHole.translate(15, 10, 0)); return [ { name: 'Top Plate', shape: topPlate }, { name: 'Bot Plate', shape: botPlate }, { name: 'Bolt', shape: hw.bolt.translate(15, 10, 20) }, { name: 'Nut', shape: hw.nut.translate(15, 10, -4) }, ]; ```
|
|
9077
|
-
- `boltedServiceCover(options: BoltedServiceCoverOptions): BoltedServiceCoverResult` — Bolted service-cover interface with real seats, aligned holes, gasket, fused pull tabs, and installed screws. **Details** This is a higher-level mechanical pattern for the common "removable service cover" failure mode. It creates the parent ledge, cover, gasket, and screws from one shared bolt pattern so agents do not place decorative screw heads or floating pull tabs by eye. Coordinate convention: the parent frame sits from `z=0` to `parentThickness`, the gasket sits on the ledge, the cover sits above the gasket, and screw shafts run downward through the cover into the parent. All parts are centered on the XY origin. **Example** ```ts const cover = lib.boltedServiceCover({ width: 90, depth: 56, screwSize: 'M4', ledgeWidth: 10, boltInset: [6, 6], }); verify.equal('four retained cover screws', cover.screws.length, 4); return cover.parts; ```
|
|
9078
|
-
- `datumEnclosureAssembly(options: DatumEnclosureAssemblyOptions): DatumEnclosureAssemblyResult` — Datum-driven enclosure tray with shared wall, ledge, standoff, cover, gasket, port, and screw geometry. **Details** This pattern is for electronics boxes, thermostat backplates, service-stack housings, camera housings, and small fixtures where generated models often place panels, ribs, bosses, ports, and covers by eye. The tray, internal ledges, standoffs, ribs, service port, gasket, cover holes, and installed screws all come from one datum system. This keeps screw axes, boss locations, wall thickness, and service openings aligned instead of relying on independent magic numbers. Coordinate convention: X/Y are the enclosure footprint, Z is up. The base tray starts at `z=0` and rises to `height`; the gasket and cover sit above the top ledge with small explicit face clearances. **Example** ```ts const enclosure = lib.datumEnclosureAssembly({ width: 96, depth: 64, height: 18, }); verify.notColliding('cover clears enclosure gasket', enclosure.cover, enclosure.gasket); verify.inRange('cover stack has small seating clearance', enclosure.dims.faceClearance, 0.01, 0.08); return enclosure.parts; ```
|
|
9079
|
-
- `snapLatchCoverAssembly(options: SnapLatchCoverAssemblyOptions): SnapLatchCoverAssemblyResult` — Snap-retained cover with a receiver frame, latch windows, underside catch lands, and fused snap hooks. **Details** This pattern is for covers, cartridges, clasps, and small housings where agents often add decorative tabs without a catch. The receiver has a real service opening plus two clearance latch windows. The cover is one fused part with two flexible-looking snap fingers that pass through the windows and barb under the receiver underside. Nothing intersects in the final assembly; the hook geometry sits close enough to the catch lands to prove retention intent. Coordinate convention: the receiver frame sits from `z=0` to `parentThickness`; the cover is seated just above the receiver on +Z. Two snap hooks sit on the +/-Y ledges and tuck under the receiver. **Example** ```ts const snapCover = lib.snapLatchCoverAssembly({ width: 72, depth: 44, }); verify.notColliding('snap hooks clear receiver windows', snapCover.cover, snapCover.parent); verify.inRange('snap cover has small seating clearance', snapCover.dims.faceClearance, 0.01, 0.08); return snapCover.parts; ```
|
|
9080
|
-
- `pinnedLeverAssembly(options: PinnedLeverAssemblyOptions): PinnedLeverAssemblyResult` — Retained pinned lever stack with a fused hub/arm/grip, low stop land, pivot pin, bore cutters, and thrust washers. **Details** This pattern is for the common handle/lever failure mode where a visual arm, hub, washer, and pin are placed near each other but never form a credible mechanism. The lever body is one fused part, the pin runs through aligned bores, washers sit on both sides of the lever, and the support includes a bearing land plus an optional low stop land beside the lever path. Coordinate convention: pivot axis is +Z at the XY origin. The support starts at `z=0`, the lower washer sits on top of the support, the lever sits on the lower washer, the upper washer sits on the lever, and the retained pin spans the full stack. **Example** ```ts const lever = lib.pinnedLeverAssembly({ armLength: 54, armWidth: 10, pinDiameter: 5, }); verify.equal('lever stack has five retained parts', lever.parts.length, 5); return lever.parts; ```
|
|
9081
|
-
- `retainedShaftAssembly(options: RetainedShaftAssemblyOptions): RetainedShaftAssemblyResult` — Retained shaft, washer, knob, and support-cheek stack for trunnions, pivots, and adjustable clamps. **Details** This pattern replaces the common "pin, washers, and knob are near each other" visual shortcut with a mechanically accountable shaft stack. The two support cheeks get matching clearance bores, the through shaft spans the whole stack, washers and knobs share the same axis, and retaining heads keep the knobs from reading as loose floating cylinders. Coordinate convention: the shaft axis is +X through the world origin. Support cheeks are centered at `x = +/- supportSpacing / 2`. The supports are bored for clearance, so collision inspection should report no support/shaft overlap while the connectivity audit still sees one retained stack. **Example** ```ts const trunnion = lib.retainedShaftAssembly({ supportSpacing: 96, shaftDiameter: 8, supportHeight: 42, }); verify.equal('retained shaft stack has seven parts', trunnion.parts.length, 7); return trunnion.parts; ```
|
|
9082
|
-
- `capturedLinearSlide(options: CapturedLinearSlideOptions): CapturedLinearSlideResult` — Captured linear slide with a U-channel rail, return lips, end stops, and a carriage posed inside the guide. **Details** This pattern is for drawer-slide, quick-release plate, and guided-carriage models where agents often place rail details and a moving block near each other without a capture relationship. The rail is one fused part with side walls, inward lips, and end stops; the carriage is wider than the lip throat but narrower than the inner rail width, so it is mechanically captured while retaining explicit clearance. Coordinate convention: rail length is along X, width is along Y, and Z is up. The rail base starts at `z=0`; the carriage sits above the base and below the return lips. `travel=0` places the carriage at the negative-X end of travel, and `travel=maxTravel` places it at the positive-X end. **Example** ```ts const slide = lib.capturedLinearSlide({ length: 160, carriageLength: 52, travel: 42, }); verify.greaterThan('carriage is captured by return lips', slide.dims.carriageWidth, slide.dims.throatWidth); return slide.parts; ```
|
|
9083
|
-
- `capturedCartridgeGuideAssembly(options: CapturedCartridgeGuideAssemblyOptions): CapturedCartridgeGuideAssemblyResult` — Captured removable cartridge guide with return lips, rear stop, wide cartridge flange, and pull tab. **Details** This pattern is for pump cartridges, filter cassettes, skeg cassettes, battery cartridges, and slide-in service modules where generated models often place a tray and a loose block near each other. The guide is one fused part with side walls, inward return lips, and a rear stop. The cartridge has a wide lower flange captured under the lips and a narrower body that passes through the throat, so the model has a real retention contract without manual coordinate tuning. Coordinate convention: insertion travel is along +X. The open entry is at −X, the rear stop is at +X, the guide base starts at `z=0`, and `insertion=0` places the cartridge at the front travel limit. **Example** ```ts const cassette = lib.capturedCartridgeGuideAssembly({ length: 150, cartridgeLength: 72, }); verify.notColliding('cartridge clears guide rails', cassette.cartridge, cassette.guide); verify.greaterThan('cartridge flange is captured by lips', cassette.dims.cartridgeWidth, cassette.dims.throatWidth); return cassette.parts; ```
|
|
9084
|
-
- `livingHingeCoverAssembly(options: LivingHingeCoverAssemblyOptions): LivingHingeCoverAssemblyResult` — One-piece molded living-hinge cover strip with a fixed leaf, thin flexible web, cover leaf, pull lip, snap barb, and catch land. **Details** This pattern is for small polypropylene-style lids, battery doors, sample covers, blister latches, and molded service flaps where generated models often draw a decorative hinge strip between two disconnected plates. It returns one fused molded part in its as-molded flat state: fixed mounting leaf, thin hinge web, moving cover leaf, pull lip, raised snap barb, and catch land. The flexible web is intentionally much thinner than the rigid leaves and shares material with both leaves. Coordinate convention: X is hinge length/part width, Y runs from fixed leaf through hinge web to cover leaf, and Z is thickness. The hinge web is centered on `y=0`; the fixed leaf lies at −Y and the cover leaf at +Y. **Example** ```ts const livingCover = lib.livingHingeCoverAssembly({ width: 64, coverDepth: 42, }); verify.greaterThan('living hinge is much thinner than rigid leaves', livingCover.dims.flexRatio, 3); return livingCover.parts; ```
|
|
9085
|
-
- `knuckledHingeAssembly(options: KnuckledHingeAssemblyOptions): KnuckledHingeAssemblyResult` — Alternating knuckle hinge with two fused leaves and a retained pin. **Details** This pattern replaces hand-placed hinge barrels and pin ghosts with a mechanically accountable hinge. The fixed leaf owns every other knuckle, the moving leaf owns the alternating knuckles, all knuckles share one bore size, and the retained pin spans the full stack with heads outside the barrels. Coordinate convention: the hinge pin axis is +X through the world origin. The fixed leaf extends toward +Y. The moving leaf extends toward -Y and rotates about +X by `openAngleDeg`. **Example** ```ts const hinge = lib.knuckledHingeAssembly({ length: 70, leafLength: 28, openAngleDeg: 45, }); verify.equal('hinge has two leaves and one retained pin', hinge.parts.length, 3); return hinge.parts; ```
|
|
9086
|
-
- `clevisPinJointAssembly(options?: ClevisPinJointAssemblyOptions): ClevisPinJointAssemblyResult` — Clevis-style pin joint with bored yoke ears, a center link eye, and a retained pin. **Details** This pattern is for crank links, damper rod ends, pump crossheads, capo/cam pivots, and small mechanism joints where agents often place an eyelet and a pin near a bracket without modeling the captured load path. The clevis is one fused part with two bored ears and a rear bridge, the center link has a real eye and arm, and the retained pin spans the full stack with heads outside the ears. Coordinate convention: the pin axis is +Y through the world origin. The center link arm extends toward +X. The clevis bridge sits behind the eye on -X, leaving the link eye clear inside the yoke. **Example** ```ts const clevis = lib.clevisPinJointAssembly({ pinDiameter: 4, linkArmLength: 38, }); verify.equal('clevis joint has three retained parts', clevis.parts.length, 3); return clevis.parts; ```
|
|
9087
|
-
- `seatedBearingAssembly(options: SeatedBearingAssemblyOptions): SeatedBearingAssemblyResult` — Seated radial-bearing support with a real counterbore, shoulder, through shaft, and retaining collars. **Details** This pattern is for purchased bearings, rollers, burr-cartridge shafts, and small spindle supports where agents often place a ring and a shaft near a block without modelling the pocket that locates the bearing. The housing includes a through-bore and a larger counterbore that leaves a shoulder for the bearing outer race. The shaft is smaller than the bearing bore and carries collars outside the housing, so collision checks can distinguish intended clearance from impossible overlap. Coordinate convention: the shaft axis is +Z through the world origin. The housing block starts at `z=0`, the raised boss is on top of the block, the bearing is seated from the top counterbore, and the shaft extends above and below the housing. **Example** ```ts const bearingStack = lib.seatedBearingAssembly({ bearingOuterDiameter: 22, bearingInnerDiameter: 8, bearingWidth: 7, }); verify.greaterThan('housing has wall around bearing pocket', bearingStack.dims.bossOuterDiameter - bearingStack.dims.pocketDiameter, 4); return bearingStack.parts; ```
|
|
9088
|
-
- `cableGlandAnchorAssembly(options: CableGlandAnchorAssemblyOptions): CableGlandAnchorAssemblyResult` — Cable, wire, or tube gland anchor with a real panel hole, hollow gland body, compression nut, and routed cable. **Details** This pattern is for pumps, filters, electronics boxes, vents, monitors, and fixtures where generated models often leave hoses or cables terminating in space. It creates the receiving panel hole, a hollow gland body with a panel-side flange seated in a shallow pocket, a hollow compression nut, and a cable/tube that runs through the gland bore with explicit clearance. Coordinate convention: the cable axis is +X through the world origin. The panel is centered around `x=0` with thickness along X; the flange sits on the +X side of the panel and the compression nut sits on the −X side. The cable spans the full anchor. **Example** ```ts const anchor = lib.cableGlandAnchorAssembly({ cableDiameter: 6, panelThickness: 3, }); verify.notColliding('cable clears gland bore', anchor.cable, anchor.gland); verify.clearanceBetween('gland flange is seated at panel pocket', anchor.gland, anchor.panel, 0.01, 0.2); return anchor.parts; ```
|
|
9089
|
-
- `hoseBarbPortAssembly(options: HoseBarbPortAssemblyOptions): HoseBarbPortAssemblyResult` — Hose-barb pump/filter port with a bored receiver, shoulder, barb ridges, installed hose, and clamp band. **Details** This pattern is for pump heads, filters, vents, lab cartridges, and fluid fittings where generated models often leave tubes ending near a block. The receiver has a real through-port and raised boss, the fitting is hollow with a shoulder and multiple barb ridges, and the hose is modeled as an installed tube over the barb envelope with a clamp band. The hose bore is sized for the deformed installed hose, so collision checks distinguish the retained interface from impossible solid overlap. Coordinate convention: the fluid axis is +X through the world origin. The receiver block is centered around `x=0`; the raised boss and hose are on the +X side. **Example** ```ts const hosePort = lib.hoseBarbPortAssembly({ hoseInnerDiameter: 6, hoseOuterDiameter: 10, }); verify.notColliding('hose clears barb peaks', hosePort.hose, hosePort.fitting); verify.inRange('fitting shoulder seats near boss face', hosePort.dims.faceClearance, 0.01, 0.08); return hosePort.parts; ```
|
|
9090
|
-
- `routedTubeClipAssembly(options: RoutedTubeClipAssemblyOptions): RoutedTubeClipAssemblyResult` — Routed tube or cable retained by saddle clips with real bores, screw holes, and installed screws. **Details** This pattern is for hoses, wires, pump tubes, sensor leads, and appliance cable runs where generated models often draw a cylinder near a wall without clips or strain relief. The base panel has receiving screw envelopes, each saddle clip has a real through-bore around the tube and vertical screw clearances, and the installed screws share those positions. Coordinate convention: the routed tube runs along +X through the world origin. The base panel starts at `z=0`; clips sit on top of the panel, and the tube passes through their bores. **Example** ```ts const route = lib.routedTubeClipAssembly({ tubeDiameter: 6, clipCount: 3, }); verify.notColliding('tube clears clip bores', route.tube, union(...route.clips)); verify.notColliding('clip screws clear retained stack', union(...route.screws), union(route.panel, ...route.clips)); return route.parts; ```
|
|
9091
|
-
- `pcbTerminalBlockAssembly(options?: PcbTerminalBlockAssemblyOptions): PcbTerminalBlockAssemblyResult` — PCB terminal-block stack with a backplate, standoffs, mounting screws, pin holes, and a seated terminal block. **Details** This pattern is for thermostat backplates, appliance control panels, sensor boards, and small electronics where generated models often place a terminal block, screw heads, and holes as independent decorations. The PCB mounting holes, fused standoffs, installed screws, terminal pins, and PCB pin clearances all come from one shared datum system so the purchased block is mechanically seated and the board is actually mounted. Coordinate convention: X/Y are the board footprint, Z is up. The backplate starts at `z=0`, standoffs rise from the plate, the PCB rests on the standoffs, and the terminal block sits on top of the PCB near the front edge. **Example** ```ts const terminalStack = lib.pcbTerminalBlockAssembly({ terminalCount: 5, screwSize: 'M3', }); verify.notColliding('terminal pins clear PCB holes', terminalStack.terminalBlock, terminalStack.pcb); verify.notColliding('mounting screws clear PCB and standoff holes', union(...terminalStack.screws), union(terminalStack.pcb, terminalStack.backplate)); return terminalStack.parts; ```
|
|
9092
|
-
- `thumbScrewClampAssembly(options?: ThumbScrewClampAssemblyOptions): ThumbScrewClampAssemblyResult` — Thumb-screw clamp with a C-frame, threaded boss, captive pressure pad, knob, and clamped workpiece. **Details** This pattern is for bench clamps, monitor-arm desk clamps, small vise screws, capo pressure screws, fixture hold-downs, and service brackets where generated models often place a loose screw, knob, or pressure pad near a bracket. The helper creates a one-piece clamp frame with a fixed anvil pad, a bored threaded support and boss, an installed screw with a captive pressure pad and hand knob, and a representative clamped workpiece seated between the pads. Coordinate convention: the clamp screw runs along +X. The fixed anvil is on the -X side, the threaded support and knob are on the +X side, and Z is up from the base bridge. **Example** ```ts const clamp = lib.thumbScrewClampAssembly({ screwSize: 'M6', workpieceThickness: 20, }); verify.notColliding('thumb screw clears threaded boss', clamp.clampScrew, clamp.frame); verify.clearanceBetween('pressure pad is seated on workpiece', clamp.clampScrew, clamp.workpiece, -0.01, 0.05); return clamp.parts; ```
|
|
9093
9164
|
- `pipeRoute(points: [ number, number, number ][], radius: number, options?: { bendRadius?: number; wall?: number; segments?: number; }): Shape` — Route a pipe (solid or hollow) through 3D waypoints with smooth bends. This is a convenience recipe over `Curve.Route.fromPolyline()` and [`sweep()`](/docs/curves#sweep). Use `Curve.Route` directly when you need route metadata, named ports, or custom swept profiles.
|
|
9094
|
-
- `elbow(pipeRadius: number, bendRadius: number, angle?: number | { ... }, options?: { ... }): Shape` — Pipe elbow — a curved pipe section
|
|
9165
|
+
- `elbow(pipeRadius: number, bendRadius: number, angle?: number | { ... }, options?: { ... }): Shape` — Pipe elbow — a curved pipe section for connecting two pipe directions. This is a convenience recipe over `Curve.Arc()` and [`sweep()`](/docs/curves#sweep). Use `Curve.Route.fromPolyline()` directly when you need named route ports, segment metadata, or multi-bend pipe runs.
|
|
9095
9166
|
- `beltDrive(options: BeltDriveOptions): BeltDriveResult` — Create a flat open-belt body around two pulley pitch circles. The belt is generated as a tangent loop in the XY plane and extruded along +Z by `beltWidth`. The result includes the solid belt, the 2D belt profile, a thin pitch-path sketch for visualization, total belt length, tangent spans, and wrap metadata for each pulley. For more than two pulleys, the API intentionally asks for route intent before geometry is created. Use `route: "outer"` for the future outside-envelope mode, or an ordered route for future serpentine/idler layouts. ```ts const drive = lib.beltDrive({ pulleys: [ { name: "motor", center: [0, 0], pitchRadius: 12 }, { name: "output", center: [80, 0], pitchRadius: 28 }, ], beltWidth: 8, beltThickness: 2, }); return drive.belt; ```
|
|
9096
9167
|
- `tangentLoop2d(circles: TangentCircle2D[], options?: TangentLoop2DOptions): TangentLoop2D` — Build a closed 2D route made from common tangent spans and pulley wrap arcs. Use this when you need reusable belt/chain route geometry before creating a solid body. The first implementation supports two circles. `mode: "open"` uses external tangents; `mode: "crossed"` uses internal tangents. ```ts const route = lib.tangentLoop2d([ { center: [0, 0], radius: 12 }, { center: [80, 0], radius: 28 }, ]); const belt = route.offsetBand(2).extrude(8); ```
|
|
9097
9168
|
- `tSlotProfile(options?: TSlotProfileOptions): Sketch` — Build a 2D T-slot cross-section sketch. Default parameters describe a 20x20 B-type profile with slot 6. Use this when you want a drawing-ready profile sketch before extrusion.
|
package/dist-skill/docs/CLI.md
CHANGED
|
@@ -48,6 +48,8 @@ ForgeCAD includes a local editor. Open it around a dedicated project folder, edi
|
|
|
48
48
|
|
|
49
49
|
`forgecad studio <project-path>` is the normal installed-CLI command for users. `forgecad dev <project-path>` starts the Vite dev server and is mainly for ForgeCAD source development.
|
|
50
50
|
|
|
51
|
+
Keep one long-running `forgecad studio <project-path> [project-path ...]` process open with every active project folder listed in its arguments; the user opens the single printed localhost port once, and AI agents should only create or edit files under those folders so the browser updates live without starting more servers.
|
|
52
|
+
|
|
51
53
|
<details>
|
|
52
54
|
<summary>Common flags for studio / dev</summary>
|
|
53
55
|
|
|
@@ -366,6 +368,7 @@ forgecad render section examples/furniture/01-table.forge.js out/bold.svg --edge
|
|
|
366
368
|
|--------|-------------|
|
|
367
369
|
| `--param <Key=Value>` | Override a parameter value (Key=Value). Repeatable. |
|
|
368
370
|
| `-p <Key=Value>` | Shorthand for --param |
|
|
371
|
+
| `--joint <JointName=Value>` | Override a Motion tab joint value (JointName=Value). Repeatable. |
|
|
369
372
|
| `--focus <names>` | Focus: no arg hides mocks; comma-separated names/globs show only those |
|
|
370
373
|
| `--hide <names>` | Hide comma-separated object names/globs |
|
|
371
374
|
| `--camera <front\|back\|side\|right\|top\|iso\|az:el\|az:el:dist\|spec>` | Camera preset, spherical (az:el), or full spec such as `proj=perspective;pos=x,y,z;target=x,y,z;up=x,y,z;fov=45`. Repeatable. |
|
|
@@ -468,6 +471,7 @@ forgecad export sdf rover.forge.js --output out/forge_scout
|
|
|
468
471
|
|
|
469
472
|
| Option | Description |
|
|
470
473
|
|--------|-------------|
|
|
474
|
+
| `--joint <JointName=Value>` | Override a Motion tab joint value (JointName=Value). Repeatable. |
|
|
471
475
|
| `--output <path>` | Output STEP path |
|
|
472
476
|
| `--backend <occt\|truck>` | Exact BREP exporter: occt (default) or truck (native analytic kernel) |
|
|
473
477
|
| `--quality <default\|live\|high>` | Forge quality preset |
|
|
@@ -207,6 +207,16 @@ addAngleBetweenLinks(a: string, b: string, c: string, options?: AssemblyAngleBet
|
|
|
207
207
|
|
|
208
208
|
`AssemblyKinematicLimitOptions`: `{ min?: number, max?: number }`
|
|
209
209
|
|
|
210
|
+
#### `addAngleBetweenLinkSegmentAndWorldDirection()` — Add an absolute angle relationship from a world direction to a link segment.
|
|
211
|
+
|
|
212
|
+
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
|
+
|
|
214
|
+
Use `Points.polar(1, angleDeg)` when the reference direction is planar and angle-based instead of axis-aligned.
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
addAngleBetweenLinkSegmentAndWorldDirection(fromLink: string, toLink: string, direction: Vec3, options?: AssemblyAngleBetweenLinksOptions): Assembly
|
|
218
|
+
```
|
|
219
|
+
|
|
210
220
|
#### `describeKinematics()` — Return the assembly-native kinematic graph definition.
|
|
211
221
|
|
|
212
222
|
```ts
|
|
@@ -235,19 +245,49 @@ assembly.addPart("Base Assembly", housing);
|
|
|
235
245
|
addPart(name: string, part: AssemblyPart, options?: PartOptions): Assembly
|
|
236
246
|
```
|
|
237
247
|
|
|
238
|
-
|
|
248
|
+
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
239
249
|
|
|
240
250
|
**`AssemblyPartMateInput`**
|
|
241
251
|
- `connector: string` — Name of a connector declared on the part (via `withConnectors()`).
|
|
242
252
|
- `toLink: string` — Name of the link this connector's origin is pinned to.
|
|
243
253
|
- `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).
|
|
244
254
|
|
|
245
|
-
#### `
|
|
255
|
+
#### `frame()` — Add a named rig frame to the assembly.
|
|
256
|
+
|
|
257
|
+
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
|
+
|
|
259
|
+
```ts
|
|
260
|
+
frame(name: string, options: AssemblyFrameOptions): Assembly
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**`AssemblyFrameOptions`**: `origin: [ number, number, number ]`, `axis: [ number, number, number ]`, `up: [ number, number, number ]`, `fixed?: boolean`, `metadata?: Record<string, unknown>`
|
|
264
|
+
|
|
265
|
+
#### `fixedJoint()` — Rigidly attach a child rig frame to a parent rig frame.
|
|
266
|
+
|
|
267
|
+
Fixed joints carry frame hierarchy but do not expose a Motion control.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
fixedJoint(name: string, options: AssemblyFixedFrameJointOptions): Assembly
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`AssemblyFixedFrameJointOptions`: `{ parent: string, child: string, metadata?: Record<string, unknown> }`
|
|
274
|
+
|
|
275
|
+
#### `revoluteJoint()` — Add a revolute rig-frame joint.
|
|
276
|
+
|
|
277
|
+
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
|
+
|
|
279
|
+
```ts
|
|
280
|
+
revoluteJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**`AssemblyMovingFrameJointOptions`**: `parent: string`, `child: string`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `control?: boolean`, `metadata?: Record<string, unknown>`
|
|
284
|
+
|
|
285
|
+
#### `prismaticJoint()` — Add a prismatic rig-frame joint.
|
|
246
286
|
|
|
247
|
-
|
|
287
|
+
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.
|
|
248
288
|
|
|
249
289
|
```ts
|
|
250
|
-
|
|
290
|
+
prismaticJoint(name: string, options: AssemblyMovingFrameJointOptions): Assembly
|
|
251
291
|
```
|
|
252
292
|
|
|
253
293
|
**Connectors**
|
|
@@ -413,6 +453,32 @@ solve(state?: JointState): SolvedAssembly
|
|
|
413
453
|
mate(fn: (m: MateBuilder) => void): Assembly
|
|
414
454
|
```
|
|
415
455
|
|
|
456
|
+
#### `edgeBetweenFrames()` — Add a visual skeleton edge between two rig frame origins.
|
|
457
|
+
|
|
458
|
+
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.
|
|
459
|
+
|
|
460
|
+
```ts
|
|
461
|
+
edgeBetweenFrames(a: string, b: string, options?: AssemblyFrameEdgeOptions): Assembly
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
`AssemblyFrameEdgeOptions`: `{ name?: string, metadata?: Record<string, unknown> }`
|
|
465
|
+
|
|
466
|
+
#### `linkToward()` — Create a derived link at a fixed distance from `fromLink` toward `towardLink`.
|
|
467
|
+
|
|
468
|
+
Derived links are trace/reference points. They are recomputed after the primary link solve and cannot participate in structural edges or angle constraints.
|
|
469
|
+
|
|
470
|
+
```ts
|
|
471
|
+
linkToward(name: string, fromLink: string, towardLink: string, distance: number): Assembly
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
#### `linkAwayFrom()` — Create a derived link at a fixed distance from `fromLink` away from `awayFromLink`.
|
|
475
|
+
|
|
476
|
+
Use this for coupler trace/extension points such as the Chebyshev lambda linkage's point beyond the rocker joint.
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
linkAwayFrom(name: string, fromLink: string, awayFromLink: string, distance: number): Assembly
|
|
480
|
+
```
|
|
481
|
+
|
|
416
482
|
#### `describe()` — Return the serializable assembly definition used by solve/inspect pipelines.
|
|
417
483
|
|
|
418
484
|
```ts
|
|
@@ -681,7 +747,7 @@ get mateDof(): number | null
|
|
|
681
747
|
get mateConverged(): boolean | null
|
|
682
748
|
```
|
|
683
749
|
|
|
684
|
-
#### `kinematics()` — Solved assembly-native kinematic
|
|
750
|
+
#### `kinematics()` — Solved assembly-native kinematic or frame-edge overlay data, or null when no rig overlay data was declared.
|
|
685
751
|
|
|
686
752
|
```ts
|
|
687
753
|
get kinematics(): SolvedAssemblyKinematics | null
|
|
@@ -693,6 +759,18 @@ get kinematics(): SolvedAssemblyKinematics | null
|
|
|
693
759
|
getLinkPosition(linkName: string): Vec3
|
|
694
760
|
```
|
|
695
761
|
|
|
762
|
+
#### `getFrame()` — Return the solved world transform for a named rig frame.
|
|
763
|
+
|
|
764
|
+
```ts
|
|
765
|
+
getFrame(frameName: string): Transform
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
#### `frames()` — Return solved rig frames, including origin, axis, up, and transform.
|
|
769
|
+
|
|
770
|
+
```ts
|
|
771
|
+
get frames(): SolvedAssemblyFrameDef[]
|
|
772
|
+
```
|
|
773
|
+
|
|
696
774
|
#### `getTransform()` — Return the world-space [`Transform`](/docs/core#transform) for the named part at the solved pose.
|
|
697
775
|
|
|
698
776
|
```ts
|
|
@@ -93,7 +93,7 @@ Pre-built parametric parts available in user scripts as `lib.*`.
|
|
|
93
93
|
|
|
94
94
|
Every key in this object becomes a method or namespace on the `lib` object exposed to `.forge.js` scripts. The catalog includes:
|
|
95
95
|
|
|
96
|
-
**Fasteners and hardware patterns:** `bolt`, `nut`, `washer`, `fastenerSet`, `
|
|
96
|
+
**Fasteners and hardware patterns:** `bolt`, `nut`, `washer`, `fastenerSet`, `fastenerHole`, `boltHole`, `counterbore`, `hexNut`, `holePattern`
|
|
97
97
|
|
|
98
98
|
**Structure:** `tube`, `pipe`, `bracket`, `pipeRoute`, `elbow`, `tSlotProfile`, `tSlotExtrusion`, `profile2020BSlot6Profile`, `profile2020BSlot6`
|
|
99
99
|
|
|
@@ -127,24 +127,8 @@ Sizes outside the supported ranges will throw at runtime with a descriptive erro
|
|
|
127
127
|
- `nut(diameter: number, options?: { pitch?: number; height?: number; acrossFlats?: number; segments?: number; }): Shape` — ISO-style hex nut with a threaded bore. **Details** Constructed from the intersection of three rotated slabs with a cylindrical bore subtracted. The nut is centered at the origin, height along Z. Default proportions follow ISO 4032 loosely: height ≈ 0.8×diameter, across-flats ≈ 1.6×diameter. The bore is a clearance bore (not modelled with helical threads) for rendering efficiency. For standard M-size nuts pre-configured for a complete joint, use { **Example** ```ts const n = lib.nut(5); // M5 nut ```
|
|
128
128
|
- `washer(size: MetricSize, options?: { standard?: WasherStandard; segments?: number; }): Shape` — ISO metric flat washer (DIN 125-A). **Details** Returns a flat ring centered at the origin, thickness along Z. Dimensions are taken from { **Example** ```ts const w = lib.washer('M5'); // DIN 125-A M5 washer ```
|
|
129
129
|
- `fastenerSet(size: MetricSize, boltLength: number, options?: FastenerSetOptions): FastenerSetResult` — Complete ISO metric fastener set — bolt, nut, optional washers, and matching hole cutters. **Details** Returns all geometry for one bolted joint: the bolt, nut, up to two washers, a clearance-hole cutter, and a tap-drill cutter. All shapes are returned **un-positioned** (each on the Z-axis). Place them with `.translate()`. Sizes outside M4–M10 are supported for the washer (M2–M10); unsupported combinations will throw. **Example** ```ts const hw = lib.fastenerSet('M5', 20); const topPlate = box(60, 40, 8).translate(0, 0, 12) .subtract(hw.clearanceHole.translate(15, 10, 12)); const botPlate = box(60, 40, 8) .subtract(hw.clearanceHole.translate(15, 10, 0)); return [ { name: 'Top Plate', shape: topPlate }, { name: 'Bot Plate', shape: botPlate }, { name: 'Bolt', shape: hw.bolt.translate(15, 10, 20) }, { name: 'Nut', shape: hw.nut.translate(15, 10, -4) }, ]; ```
|
|
130
|
-
- `boltedServiceCover(options: BoltedServiceCoverOptions): BoltedServiceCoverResult` — Bolted service-cover interface with real seats, aligned holes, gasket, fused pull tabs, and installed screws. **Details** This is a higher-level mechanical pattern for the common "removable service cover" failure mode. It creates the parent ledge, cover, gasket, and screws from one shared bolt pattern so agents do not place decorative screw heads or floating pull tabs by eye. Coordinate convention: the parent frame sits from `z=0` to `parentThickness`, the gasket sits on the ledge, the cover sits above the gasket, and screw shafts run downward through the cover into the parent. All parts are centered on the XY origin. **Example** ```ts const cover = lib.boltedServiceCover({ width: 90, depth: 56, screwSize: 'M4', ledgeWidth: 10, boltInset: [6, 6], }); verify.equal('four retained cover screws', cover.screws.length, 4); return cover.parts; ```
|
|
131
|
-
- `datumEnclosureAssembly(options: DatumEnclosureAssemblyOptions): DatumEnclosureAssemblyResult` — Datum-driven enclosure tray with shared wall, ledge, standoff, cover, gasket, port, and screw geometry. **Details** This pattern is for electronics boxes, thermostat backplates, service-stack housings, camera housings, and small fixtures where generated models often place panels, ribs, bosses, ports, and covers by eye. The tray, internal ledges, standoffs, ribs, service port, gasket, cover holes, and installed screws all come from one datum system. This keeps screw axes, boss locations, wall thickness, and service openings aligned instead of relying on independent magic numbers. Coordinate convention: X/Y are the enclosure footprint, Z is up. The base tray starts at `z=0` and rises to `height`; the gasket and cover sit above the top ledge with small explicit face clearances. **Example** ```ts const enclosure = lib.datumEnclosureAssembly({ width: 96, depth: 64, height: 18, }); verify.notColliding('cover clears enclosure gasket', enclosure.cover, enclosure.gasket); verify.inRange('cover stack has small seating clearance', enclosure.dims.faceClearance, 0.01, 0.08); return enclosure.parts; ```
|
|
132
|
-
- `snapLatchCoverAssembly(options: SnapLatchCoverAssemblyOptions): SnapLatchCoverAssemblyResult` — Snap-retained cover with a receiver frame, latch windows, underside catch lands, and fused snap hooks. **Details** This pattern is for covers, cartridges, clasps, and small housings where agents often add decorative tabs without a catch. The receiver has a real service opening plus two clearance latch windows. The cover is one fused part with two flexible-looking snap fingers that pass through the windows and barb under the receiver underside. Nothing intersects in the final assembly; the hook geometry sits close enough to the catch lands to prove retention intent. Coordinate convention: the receiver frame sits from `z=0` to `parentThickness`; the cover is seated just above the receiver on +Z. Two snap hooks sit on the +/-Y ledges and tuck under the receiver. **Example** ```ts const snapCover = lib.snapLatchCoverAssembly({ width: 72, depth: 44, }); verify.notColliding('snap hooks clear receiver windows', snapCover.cover, snapCover.parent); verify.inRange('snap cover has small seating clearance', snapCover.dims.faceClearance, 0.01, 0.08); return snapCover.parts; ```
|
|
133
|
-
- `pinnedLeverAssembly(options: PinnedLeverAssemblyOptions): PinnedLeverAssemblyResult` — Retained pinned lever stack with a fused hub/arm/grip, low stop land, pivot pin, bore cutters, and thrust washers. **Details** This pattern is for the common handle/lever failure mode where a visual arm, hub, washer, and pin are placed near each other but never form a credible mechanism. The lever body is one fused part, the pin runs through aligned bores, washers sit on both sides of the lever, and the support includes a bearing land plus an optional low stop land beside the lever path. Coordinate convention: pivot axis is +Z at the XY origin. The support starts at `z=0`, the lower washer sits on top of the support, the lever sits on the lower washer, the upper washer sits on the lever, and the retained pin spans the full stack. **Example** ```ts const lever = lib.pinnedLeverAssembly({ armLength: 54, armWidth: 10, pinDiameter: 5, }); verify.equal('lever stack has five retained parts', lever.parts.length, 5); return lever.parts; ```
|
|
134
|
-
- `retainedShaftAssembly(options: RetainedShaftAssemblyOptions): RetainedShaftAssemblyResult` — Retained shaft, washer, knob, and support-cheek stack for trunnions, pivots, and adjustable clamps. **Details** This pattern replaces the common "pin, washers, and knob are near each other" visual shortcut with a mechanically accountable shaft stack. The two support cheeks get matching clearance bores, the through shaft spans the whole stack, washers and knobs share the same axis, and retaining heads keep the knobs from reading as loose floating cylinders. Coordinate convention: the shaft axis is +X through the world origin. Support cheeks are centered at `x = +/- supportSpacing / 2`. The supports are bored for clearance, so collision inspection should report no support/shaft overlap while the connectivity audit still sees one retained stack. **Example** ```ts const trunnion = lib.retainedShaftAssembly({ supportSpacing: 96, shaftDiameter: 8, supportHeight: 42, }); verify.equal('retained shaft stack has seven parts', trunnion.parts.length, 7); return trunnion.parts; ```
|
|
135
|
-
- `capturedLinearSlide(options: CapturedLinearSlideOptions): CapturedLinearSlideResult` — Captured linear slide with a U-channel rail, return lips, end stops, and a carriage posed inside the guide. **Details** This pattern is for drawer-slide, quick-release plate, and guided-carriage models where agents often place rail details and a moving block near each other without a capture relationship. The rail is one fused part with side walls, inward lips, and end stops; the carriage is wider than the lip throat but narrower than the inner rail width, so it is mechanically captured while retaining explicit clearance. Coordinate convention: rail length is along X, width is along Y, and Z is up. The rail base starts at `z=0`; the carriage sits above the base and below the return lips. `travel=0` places the carriage at the negative-X end of travel, and `travel=maxTravel` places it at the positive-X end. **Example** ```ts const slide = lib.capturedLinearSlide({ length: 160, carriageLength: 52, travel: 42, }); verify.greaterThan('carriage is captured by return lips', slide.dims.carriageWidth, slide.dims.throatWidth); return slide.parts; ```
|
|
136
|
-
- `capturedCartridgeGuideAssembly(options: CapturedCartridgeGuideAssemblyOptions): CapturedCartridgeGuideAssemblyResult` — Captured removable cartridge guide with return lips, rear stop, wide cartridge flange, and pull tab. **Details** This pattern is for pump cartridges, filter cassettes, skeg cassettes, battery cartridges, and slide-in service modules where generated models often place a tray and a loose block near each other. The guide is one fused part with side walls, inward return lips, and a rear stop. The cartridge has a wide lower flange captured under the lips and a narrower body that passes through the throat, so the model has a real retention contract without manual coordinate tuning. Coordinate convention: insertion travel is along +X. The open entry is at −X, the rear stop is at +X, the guide base starts at `z=0`, and `insertion=0` places the cartridge at the front travel limit. **Example** ```ts const cassette = lib.capturedCartridgeGuideAssembly({ length: 150, cartridgeLength: 72, }); verify.notColliding('cartridge clears guide rails', cassette.cartridge, cassette.guide); verify.greaterThan('cartridge flange is captured by lips', cassette.dims.cartridgeWidth, cassette.dims.throatWidth); return cassette.parts; ```
|
|
137
|
-
- `livingHingeCoverAssembly(options: LivingHingeCoverAssemblyOptions): LivingHingeCoverAssemblyResult` — One-piece molded living-hinge cover strip with a fixed leaf, thin flexible web, cover leaf, pull lip, snap barb, and catch land. **Details** This pattern is for small polypropylene-style lids, battery doors, sample covers, blister latches, and molded service flaps where generated models often draw a decorative hinge strip between two disconnected plates. It returns one fused molded part in its as-molded flat state: fixed mounting leaf, thin hinge web, moving cover leaf, pull lip, raised snap barb, and catch land. The flexible web is intentionally much thinner than the rigid leaves and shares material with both leaves. Coordinate convention: X is hinge length/part width, Y runs from fixed leaf through hinge web to cover leaf, and Z is thickness. The hinge web is centered on `y=0`; the fixed leaf lies at −Y and the cover leaf at +Y. **Example** ```ts const livingCover = lib.livingHingeCoverAssembly({ width: 64, coverDepth: 42, }); verify.greaterThan('living hinge is much thinner than rigid leaves', livingCover.dims.flexRatio, 3); return livingCover.parts; ```
|
|
138
|
-
- `knuckledHingeAssembly(options: KnuckledHingeAssemblyOptions): KnuckledHingeAssemblyResult` — Alternating knuckle hinge with two fused leaves and a retained pin. **Details** This pattern replaces hand-placed hinge barrels and pin ghosts with a mechanically accountable hinge. The fixed leaf owns every other knuckle, the moving leaf owns the alternating knuckles, all knuckles share one bore size, and the retained pin spans the full stack with heads outside the barrels. Coordinate convention: the hinge pin axis is +X through the world origin. The fixed leaf extends toward +Y. The moving leaf extends toward -Y and rotates about +X by `openAngleDeg`. **Example** ```ts const hinge = lib.knuckledHingeAssembly({ length: 70, leafLength: 28, openAngleDeg: 45, }); verify.equal('hinge has two leaves and one retained pin', hinge.parts.length, 3); return hinge.parts; ```
|
|
139
|
-
- `clevisPinJointAssembly(options?: ClevisPinJointAssemblyOptions): ClevisPinJointAssemblyResult` — Clevis-style pin joint with bored yoke ears, a center link eye, and a retained pin. **Details** This pattern is for crank links, damper rod ends, pump crossheads, capo/cam pivots, and small mechanism joints where agents often place an eyelet and a pin near a bracket without modeling the captured load path. The clevis is one fused part with two bored ears and a rear bridge, the center link has a real eye and arm, and the retained pin spans the full stack with heads outside the ears. Coordinate convention: the pin axis is +Y through the world origin. The center link arm extends toward +X. The clevis bridge sits behind the eye on -X, leaving the link eye clear inside the yoke. **Example** ```ts const clevis = lib.clevisPinJointAssembly({ pinDiameter: 4, linkArmLength: 38, }); verify.equal('clevis joint has three retained parts', clevis.parts.length, 3); return clevis.parts; ```
|
|
140
|
-
- `seatedBearingAssembly(options: SeatedBearingAssemblyOptions): SeatedBearingAssemblyResult` — Seated radial-bearing support with a real counterbore, shoulder, through shaft, and retaining collars. **Details** This pattern is for purchased bearings, rollers, burr-cartridge shafts, and small spindle supports where agents often place a ring and a shaft near a block without modelling the pocket that locates the bearing. The housing includes a through-bore and a larger counterbore that leaves a shoulder for the bearing outer race. The shaft is smaller than the bearing bore and carries collars outside the housing, so collision checks can distinguish intended clearance from impossible overlap. Coordinate convention: the shaft axis is +Z through the world origin. The housing block starts at `z=0`, the raised boss is on top of the block, the bearing is seated from the top counterbore, and the shaft extends above and below the housing. **Example** ```ts const bearingStack = lib.seatedBearingAssembly({ bearingOuterDiameter: 22, bearingInnerDiameter: 8, bearingWidth: 7, }); verify.greaterThan('housing has wall around bearing pocket', bearingStack.dims.bossOuterDiameter - bearingStack.dims.pocketDiameter, 4); return bearingStack.parts; ```
|
|
141
|
-
- `cableGlandAnchorAssembly(options: CableGlandAnchorAssemblyOptions): CableGlandAnchorAssemblyResult` — Cable, wire, or tube gland anchor with a real panel hole, hollow gland body, compression nut, and routed cable. **Details** This pattern is for pumps, filters, electronics boxes, vents, monitors, and fixtures where generated models often leave hoses or cables terminating in space. It creates the receiving panel hole, a hollow gland body with a panel-side flange seated in a shallow pocket, a hollow compression nut, and a cable/tube that runs through the gland bore with explicit clearance. Coordinate convention: the cable axis is +X through the world origin. The panel is centered around `x=0` with thickness along X; the flange sits on the +X side of the panel and the compression nut sits on the −X side. The cable spans the full anchor. **Example** ```ts const anchor = lib.cableGlandAnchorAssembly({ cableDiameter: 6, panelThickness: 3, }); verify.notColliding('cable clears gland bore', anchor.cable, anchor.gland); verify.clearanceBetween('gland flange is seated at panel pocket', anchor.gland, anchor.panel, 0.01, 0.2); return anchor.parts; ```
|
|
142
|
-
- `hoseBarbPortAssembly(options: HoseBarbPortAssemblyOptions): HoseBarbPortAssemblyResult` — Hose-barb pump/filter port with a bored receiver, shoulder, barb ridges, installed hose, and clamp band. **Details** This pattern is for pump heads, filters, vents, lab cartridges, and fluid fittings where generated models often leave tubes ending near a block. The receiver has a real through-port and raised boss, the fitting is hollow with a shoulder and multiple barb ridges, and the hose is modeled as an installed tube over the barb envelope with a clamp band. The hose bore is sized for the deformed installed hose, so collision checks distinguish the retained interface from impossible solid overlap. Coordinate convention: the fluid axis is +X through the world origin. The receiver block is centered around `x=0`; the raised boss and hose are on the +X side. **Example** ```ts const hosePort = lib.hoseBarbPortAssembly({ hoseInnerDiameter: 6, hoseOuterDiameter: 10, }); verify.notColliding('hose clears barb peaks', hosePort.hose, hosePort.fitting); verify.inRange('fitting shoulder seats near boss face', hosePort.dims.faceClearance, 0.01, 0.08); return hosePort.parts; ```
|
|
143
|
-
- `routedTubeClipAssembly(options: RoutedTubeClipAssemblyOptions): RoutedTubeClipAssemblyResult` — Routed tube or cable retained by saddle clips with real bores, screw holes, and installed screws. **Details** This pattern is for hoses, wires, pump tubes, sensor leads, and appliance cable runs where generated models often draw a cylinder near a wall without clips or strain relief. The base panel has receiving screw envelopes, each saddle clip has a real through-bore around the tube and vertical screw clearances, and the installed screws share those positions. Coordinate convention: the routed tube runs along +X through the world origin. The base panel starts at `z=0`; clips sit on top of the panel, and the tube passes through their bores. **Example** ```ts const route = lib.routedTubeClipAssembly({ tubeDiameter: 6, clipCount: 3, }); verify.notColliding('tube clears clip bores', route.tube, union(...route.clips)); verify.notColliding('clip screws clear retained stack', union(...route.screws), union(route.panel, ...route.clips)); return route.parts; ```
|
|
144
|
-
- `pcbTerminalBlockAssembly(options?: PcbTerminalBlockAssemblyOptions): PcbTerminalBlockAssemblyResult` — PCB terminal-block stack with a backplate, standoffs, mounting screws, pin holes, and a seated terminal block. **Details** This pattern is for thermostat backplates, appliance control panels, sensor boards, and small electronics where generated models often place a terminal block, screw heads, and holes as independent decorations. The PCB mounting holes, fused standoffs, installed screws, terminal pins, and PCB pin clearances all come from one shared datum system so the purchased block is mechanically seated and the board is actually mounted. Coordinate convention: X/Y are the board footprint, Z is up. The backplate starts at `z=0`, standoffs rise from the plate, the PCB rests on the standoffs, and the terminal block sits on top of the PCB near the front edge. **Example** ```ts const terminalStack = lib.pcbTerminalBlockAssembly({ terminalCount: 5, screwSize: 'M3', }); verify.notColliding('terminal pins clear PCB holes', terminalStack.terminalBlock, terminalStack.pcb); verify.notColliding('mounting screws clear PCB and standoff holes', union(...terminalStack.screws), union(terminalStack.pcb, terminalStack.backplate)); return terminalStack.parts; ```
|
|
145
|
-
- `thumbScrewClampAssembly(options?: ThumbScrewClampAssemblyOptions): ThumbScrewClampAssemblyResult` — Thumb-screw clamp with a C-frame, threaded boss, captive pressure pad, knob, and clamped workpiece. **Details** This pattern is for bench clamps, monitor-arm desk clamps, small vise screws, capo pressure screws, fixture hold-downs, and service brackets where generated models often place a loose screw, knob, or pressure pad near a bracket. The helper creates a one-piece clamp frame with a fixed anvil pad, a bored threaded support and boss, an installed screw with a captive pressure pad and hand knob, and a representative clamped workpiece seated between the pads. Coordinate convention: the clamp screw runs along +X. The fixed anvil is on the -X side, the threaded support and knob are on the +X side, and Z is up from the base bridge. **Example** ```ts const clamp = lib.thumbScrewClampAssembly({ screwSize: 'M6', workpieceThickness: 20, }); verify.notColliding('thumb screw clears threaded boss', clamp.clampScrew, clamp.frame); verify.clearanceBetween('pressure pad is seated on workpiece', clamp.clampScrew, clamp.workpiece, -0.01, 0.05); return clamp.parts; ```
|
|
146
130
|
- `pipeRoute(points: [ number, number, number ][], radius: number, options?: { bendRadius?: number; wall?: number; segments?: number; }): Shape` — Route a pipe (solid or hollow) through 3D waypoints with smooth bends. This is a convenience recipe over `Curve.Route.fromPolyline()` and [`sweep()`](/docs/curves#sweep). Use `Curve.Route` directly when you need route metadata, named ports, or custom swept profiles.
|
|
147
|
-
- `elbow(pipeRadius: number, bendRadius: number, angle?: number | { ... }, options?: { ... }): Shape` — Pipe elbow — a curved pipe section
|
|
131
|
+
- `elbow(pipeRadius: number, bendRadius: number, angle?: number | { ... }, options?: { ... }): Shape` — Pipe elbow — a curved pipe section for connecting two pipe directions. This is a convenience recipe over `Curve.Arc()` and [`sweep()`](/docs/curves#sweep). Use `Curve.Route.fromPolyline()` directly when you need named route ports, segment metadata, or multi-bend pipe runs.
|
|
148
132
|
- `beltDrive(options: BeltDriveOptions): BeltDriveResult` — Create a flat open-belt body around two pulley pitch circles. The belt is generated as a tangent loop in the XY plane and extruded along +Z by `beltWidth`. The result includes the solid belt, the 2D belt profile, a thin pitch-path sketch for visualization, total belt length, tangent spans, and wrap metadata for each pulley. For more than two pulleys, the API intentionally asks for route intent before geometry is created. Use `route: "outer"` for the future outside-envelope mode, or an ordered route for future serpentine/idler layouts. ```ts const drive = lib.beltDrive({ pulleys: [ { name: "motor", center: [0, 0], pitchRadius: 12 }, { name: "output", center: [80, 0], pitchRadius: 28 }, ], beltWidth: 8, beltThickness: 2, }); return drive.belt; ```
|
|
149
133
|
- `tangentLoop2d(circles: TangentCircle2D[], options?: TangentLoop2DOptions): TangentLoop2D` — Build a closed 2D route made from common tangent spans and pulley wrap arcs. Use this when you need reusable belt/chain route geometry before creating a solid body. The first implementation supports two circles. `mode: "open"` uses external tangents; `mode: "crossed"` uses internal tangents. ```ts const route = lib.tangentLoop2d([ { center: [0, 0], radius: 12 }, { center: [80, 0], radius: 28 }, ]); const belt = route.offsetBand(2).extrude(8); ```
|
|
150
134
|
- `tSlotProfile(options?: TSlotProfileOptions): Sketch` — Build a 2D T-slot cross-section sketch. Default parameters describe a 20x20 B-type profile with slot 6. Use this when you want a drawing-ready profile sketch before extrusion.
|
|
@@ -140,9 +140,9 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
140
140
|
|
|
141
141
|
**`CollectedRobotExport`**: `modelName: string`, `assembly: AssemblyDefinition`, `state: JointState`, `static: boolean`, `selfCollide: boolean`, `allowAutoDisable: boolean`, `links: Record<string, RobotLinkExportOptions>`, `joints: Record<string, RobotJointExportOptions>`, `plugins: { diffDrive?: RobotDiffDrivePluginOptions; jointStatePublisher?: RobotJointStatePublisherOptions; }`, `world: RobotWorldOptions | null`
|
|
142
142
|
|
|
143
|
-
**`AssemblyDefinition`**: `name: string`, `parts: AssemblyPartDef[]`, `joints: AssemblyJointDef[]`, `jointCouplings: AssemblyJointCouplingDef[]`, `kinematics: AssemblyKinematicGraphDef`
|
|
143
|
+
**`AssemblyDefinition`**: `name: string`, `parts: AssemblyPartDef[]`, `joints: AssemblyJointDef[]`, `jointCouplings: AssemblyJointCouplingDef[]`, `kinematics: AssemblyKinematicGraphDef`, `frames: AssemblyFrameDef[]`, `frameJoints: AssemblyFrameJointDef[]`, `frameEdges: AssemblyFrameEdgeDef[]`
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
**`AssemblyPartDef`**: `name: string`, `part: AssemblyPart`, `base: Transform`, `metadata?: PartMetadata`, `mates: AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
146
146
|
|
|
147
147
|
**`PartMetadata`**
|
|
148
148
|
|
|
@@ -164,7 +164,7 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
164
164
|
|
|
165
165
|
`JointCouplingTermRecord`: `{ joint: string, ratio: number }`
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
**`AssemblyKinematicGraphDef`**: `links: AssemblyLinkDef[]`, `edges: AssemblyEdgeBetweenLinksDef[]`, `angles: AssemblyAngleBetweenLinksDef[]`, `derivedLinks: AssemblyDerivedLinkDef[]`
|
|
168
168
|
|
|
169
169
|
`AssemblyLinkDef`: `{ name: string, at: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
170
170
|
|
|
@@ -172,7 +172,17 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
172
172
|
|
|
173
173
|
`AssemblyKinematicControlOptions`: `{ min?: number, max?: number, default?: number, unit?: string }`
|
|
174
174
|
|
|
175
|
-
**`AssemblyAngleBetweenLinksDef`**: `name: string`, `a
|
|
175
|
+
**`AssemblyAngleBetweenLinksDef`**: `name: string`, `a?: string`, `b: string`, `c: string`, `reference?: AssemblyAngleReferenceDef`, `target?: number`, `min?: number`, `max?: number`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
176
|
+
|
|
177
|
+
`AssemblyAngleReferenceDef`: `{ kind: "worldDirection", direction: Vec3 }`
|
|
178
|
+
|
|
179
|
+
`AssemblyDerivedLinkDef`: `{ name: string, fromLink: string, referenceLink: string, distance: number, direction: AssemblyDerivedLinkDirection }`
|
|
180
|
+
|
|
181
|
+
`AssemblyFrameDef`: `{ name: string, origin: Vec3, axis: Vec3, up: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
182
|
+
|
|
183
|
+
**`AssemblyFrameJointDef`**: `name: string`, `type: AssemblyFrameJointType`, `parent: string`, `child: string`, `rest: Transform`, `min?: number`, `max?: number`, `defaultValue: number`, `unit?: string`, `control: boolean`, `metadata?: Record<string, unknown>`
|
|
184
|
+
|
|
185
|
+
`AssemblyFrameEdgeDef`: `{ name: string, a: string, b: string, metadata?: Record<string, unknown> }`
|
|
176
186
|
|
|
177
187
|
#### `dim()` — Add a dimension annotation between two points.
|
|
178
188
|
|