forgecad 0.10.0 → 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-DwYHz72L.js → AdminPage-DcCnj0qo.js} +1 -1
- package/dist/assets/{BenchmarkPage-a9_f-1US.js → BenchmarkPage-BVEpJSVk.js} +1 -1
- package/dist/assets/{BlogPage-DodHpvmf.js → BlogPage-DHaGP50_.js} +1 -1
- package/dist/assets/{DocsPage-B5LePEuj.js → DocsPage-CDoxHkz8.js} +33 -2
- package/dist/assets/{EditorApp-QXsAISLR.js → EditorApp-BJ0Dloyh.js} +174 -35
- package/dist/assets/{EmbedViewer-DdEHGUMU.js → EmbedViewer-CRKZbY0y.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-yhhOodbf.js → LandingPageProofDriven-BxHkYRE7.js} +1 -1
- package/dist/assets/{LegalPage-5RbKRGYK.js → LegalPage-B-u6FrVv.js} +1 -1
- package/dist/assets/{PricingPage-E3Rma7aV.js → PricingPage-CzpZ6-Ce.js} +1 -1
- package/dist/assets/{SettingsPage-BJZcM97j.js → SettingsPage-CIZSSAd0.js} +1 -1
- package/dist/assets/{app-CE3sYcV7.css → app-CjsbDlb7.css} +143 -0
- package/dist/assets/{app-DSYrDg0V.js → app-DaTMg3nH.js} +612 -120
- package/dist/assets/cli/{render-ZMHR9HkV.js → render-DPf4AYJK.js} +38 -16
- package/dist/assets/{evalWorker-DbNs7Dkp.js → evalWorker-CjZZWRWW.js} +1428 -1038
- package/dist/assets/{jointPose-DO6mnXn_.js → jointPose-DzQOViQH.js} +1 -1
- package/dist/assets/{manifold-BGlQBBH9.js → manifold-BYlzU521.js} +1 -1
- package/dist/assets/{manifold-fy2MV7K1.js → manifold-DgXo0T5P.js} +2 -2
- package/dist/assets/{manifold-BU-tJwQh.js → manifold-K1SkarlQ.js} +1 -1
- package/dist/assets/{reportWorker-DO6hcQbh.js → reportWorker-B9nWwSrB.js} +1402 -1012
- package/dist/assets/{scalar-sampling-budget-o90NSNmF.js → scalar-sampling-budget-prBw_s8t.js} +2139 -1749
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +18 -3
- package/dist/docs-raw/generated/assembly.md +70 -5
- package/dist/docs-raw/generated/concepts.md +16 -2
- package/dist/docs-raw/generated/core.md +9 -2
- package/dist/docs-raw/generated/lib.md +1 -1
- package/dist/docs-raw/generated/output.md +14 -43
- package/dist/docs-raw/generated/runtime-names.md +4 -4
- package/dist/docs-raw/guides/simready-quickstart.md +171 -0
- package/dist/docs-raw/simulation-workflow.md +273 -0
- package/dist/index.html +2 -2
- package/dist/sitemap.xml +25 -13
- package/dist-cli/{check-compiler-JTVBITCR.js → check-compiler-II7NLPAB.js} +1 -1
- package/dist-cli/{check-query-propagation-3FFLSMVN.js → check-query-propagation-7462TR3R.js} +1 -1
- package/dist-cli/{chunk-OAN5T4XD.js → chunk-UWTJCGXF.js} +1455 -722
- package/dist-cli/forgecad.js +2994 -529
- package/dist-skill/CONTEXT.md +94 -55
- package/dist-skill/docs/API/core/concepts.md +1 -1
- package/dist-skill/docs/CLI.md +18 -3
- package/dist-skill/docs/generated/assembly.md +66 -5
- package/dist-skill/docs/generated/core.md +9 -2
- package/dist-skill/docs/generated/lib.md +1 -1
- package/dist-skill/docs/generated/output.md +14 -43
- package/dist-skill/docs/generated/runtime-names.md +4 -4
- 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-skill/CONTEXT.md
CHANGED
|
@@ -89,7 +89,7 @@ A script must return one of three shapes:
|
|
|
89
89
|
];
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
3. **A metadata object** — a plain object whose renderable values are rendered and whose non-renderable values (numbers, hole tables, builder functions) are silently skipped at render but flow to importers via `require()`.
|
|
92
|
+
3. **A metadata object** — a plain object whose renderable values are rendered and whose non-renderable values (numbers, hole tables, builder functions) are silently skipped at render but flow to importers via `require()`. Each key becomes a named group, so don't pile independent parts into one array key (`{ parts: [a, b, c] }`) — the integrity gate reads that as a single fragmented part. Give each part its own key (`{ collar12, collar16, plug }`) or use named descriptors (form 2).
|
|
93
93
|
|
|
94
94
|
Return an unsolved `Assembly` directly — ForgeCAD solves it at default joint values for display. Use `assembly.solve(state)` for a specific pose. Never call `.toGroup()` just to make an assembly render; use it only when you need `ShapeGroup` composition or named-child lookup.
|
|
95
95
|
|
|
@@ -143,10 +143,10 @@ Point2D, Points, polygon, polygonVertices, port, Product, ProductPanelBuilder, P
|
|
|
143
143
|
ProductSkin, ProductSkinBuilder, ProductStationBuilder, ProductSurfaceBuilder, ProductSurfaceRef, projectToPlane, queueMicrotask, rect
|
|
144
144
|
Rectangle2D, robotExport, roundedRect, Route3D, scene, Sculpt, sdf, SdfShape
|
|
145
145
|
selectEdge, selectEdges, self, setActiveBackend, setImmediate, setInterval, setTimeout, Shape
|
|
146
|
-
ShapeGroup, sheetMetal, SheetMetalPart, sheetStock, Sketch, sketchToDxf, sketchToSvg
|
|
147
|
-
SolvedAssembly, spec, sphere, spline2d, stroke, Surface, SurfaceBody
|
|
148
|
-
sweep, text2d, textWidth, torus, toShape, Transform, union
|
|
149
|
-
variableSweep, verify, Viewport, window, Wood
|
|
146
|
+
ShapeGroup, sheetMetal, SheetMetalPart, sheetStock, Sim, Sketch, sketchToDxf, sketchToSvg
|
|
147
|
+
slot, SolvedAssembly, spec, sphere, spline2d, stroke, Surface, SurfaceBody
|
|
148
|
+
SurfaceMembers, sweep, text2d, textWidth, torus, toShape, Transform, union
|
|
149
|
+
union2d, variableSweep, verify, Viewport, window, Wood
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
`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.
|
|
@@ -263,6 +263,8 @@ The `edges` parameter is flexible:
|
|
|
263
263
|
|
|
264
264
|
Throws if no edges match the selection, or if `radius` is not a positive finite number.
|
|
265
265
|
|
|
266
|
+
Selectorless (all-edges) calls draw from a per-run broad edge-feature budget. Exceeding it throws — except in live preview, which skips the finish with a warning for responsiveness. Explicit edge selectors are never budgeted; `FORGECAD_BROAD_EDGE_FEATURE_BUDGET` / `FORGECAD_ALLOW_BROAD_EDGE_FEATURES=1` raise or lift the budget.
|
|
267
|
+
|
|
266
268
|
```ts
|
|
267
269
|
// Fillet all edges
|
|
268
270
|
fillet(myShape, 2)
|
|
@@ -285,6 +287,8 @@ fillet(base, 5, base.edge('vert-br'))
|
|
|
285
287
|
|
|
286
288
|
Produces a 45° bevel at the specified `size` (distance from edge). Edge selections compile into backend operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
|
|
287
289
|
|
|
290
|
+
Selectorless (all-edges) calls draw from a per-run broad edge-feature budget. Exceeding it throws — except in live preview, which skips the finish with a warning for responsiveness. Explicit edge selectors are never budgeted; `FORGECAD_BROAD_EDGE_FEATURE_BUDGET` / `FORGECAD_ALLOW_BROAD_EDGE_FEATURES=1` raise or lift the budget.
|
|
291
|
+
|
|
288
292
|
The `edges` parameter accepts the same options as `fillet()`: inline `EdgeQuery`, pre-selected `EdgeSegment`/`EdgeSegment[]`, a tracked `EdgeRef` from `shape.edge('vert-br')` (exact compiler-owned path), or `undefined` (all sharp edges).
|
|
289
293
|
|
|
290
294
|
```ts
|
|
@@ -1558,18 +1562,21 @@ Namespaced file-format import helpers — the single vocabulary for bringing ext
|
|
|
1558
1562
|
|
|
1559
1563
|
- `dxfSketch(fileName: string, options?: DxfImportOptions): Sketch` — Parse a DXF file and return closed 2D profile geometry as a Sketch. The result can be extruded directly.
|
|
1560
1564
|
- `svgSketch(fileName: string, options?: SvgImportOptions): Sketch` — Parse an SVG file and return it as a Sketch with options for region filtering, scaling, and simplification.
|
|
1561
|
-
- `mesh(fileName: string, options?:
|
|
1565
|
+
- `mesh(fileName: string, options?: MeshImportOptions): Shape | ShapeGroup` — Import an external mesh file (STL, OBJ, 3MF).
|
|
1562
1566
|
|
|
1563
1567
|
By default, 3MF build items are flattened into one Shape for compatibility. Use `separateObjects: true` to import 3MF build items/resource objects as a named ShapeGroup whose children are targetable by `forgecad ls`. Use `object` to import one item by the stable ref/name reported by `forgecad run`.
|
|
1564
1568
|
|
|
1565
1569
|
For 3MF sources, `forgecad run` prints a source-structure table with one line per build item: `[3mf:build:NNN:object:N] name type=... verts=... tris=... bbox=[min] → [max]`. Build items are numbered from `001`; files with no build items list resource objects as `3mf:object:N` instead. Per-item bboxes reveal multi-part structure — account for every substantial item before flattening. Pass any listed stable ref or name as `object` to import that item alone.
|
|
1566
1570
|
|
|
1571
|
+
Use `sourceFrame: { up: "+Y" }` when the file was authored in a non-Z-up coordinate system. ForgeCAD remains Z-up; the import is rotated so the named source axis becomes ForgeCAD +Z. Supported values: `"+X"`, `"-X"`, `"+Y"`, `"-Y"`, `"+Z"`, `"-Z"`.
|
|
1572
|
+
|
|
1567
1573
|
```js
|
|
1568
1574
|
const all = Import.mesh("./assembly.3mf", { separateObjects: true });
|
|
1569
1575
|
const pin = all.child("Pin #001");
|
|
1570
1576
|
const plate = Import.mesh("./assembly.3mf", { object: "3mf:build:001:object:7" });
|
|
1577
|
+
const yUpPart = Import.mesh("./part.obj", { sourceFrame: { up: "+Y" } });
|
|
1571
1578
|
```
|
|
1572
|
-
- `step(fileName: string): Shape` — Import a STEP file (.step, .stp) as an exact OCCT-backed Shape. Preserves NURBS curves, B-spline surfaces, and exact topology. Requires running with the OCCT backend.
|
|
1579
|
+
- `step(fileName: string, options?: StepImportOptions): Shape` — Import a STEP file (.step, .stp) as an exact OCCT-backed Shape. Preserves NURBS curves, B-spline surfaces, and exact topology. Requires running with the OCCT backend. Use `sourceFrame: { up: "+Y" }` to rotate Y-up source files into ForgeCAD's Z-up world.
|
|
1573
1580
|
|
|
1574
1581
|
---
|
|
1575
1582
|
|
|
@@ -3868,7 +3875,7 @@ const arm = bottle.path()
|
|
|
3868
3875
|
|
|
3869
3876
|
# Assembly API
|
|
3870
3877
|
|
|
3871
|
-
Assembly-owned links, constraints, connectors, solved poses, and
|
|
3878
|
+
Assembly-owned links, constraints, connectors, solved poses, and source-level simulation metadata.
|
|
3872
3879
|
|
|
3873
3880
|
## Contents
|
|
3874
3881
|
|
|
@@ -3881,6 +3888,59 @@ Assembly-owned links, constraints, connectors, solved poses, and robot export.
|
|
|
3881
3888
|
|
|
3882
3889
|
### Assembly & Joints
|
|
3883
3890
|
|
|
3891
|
+
#### `Sim.material(name: string, options?: SimMaterialOptions): SimMaterialDef` — Create a named physical material with density and contact coefficients for simulation export and checks.
|
|
3892
|
+
|
|
3893
|
+
`SimMaterialOptions`: `{ densityKgM3?: number, staticFriction?: number, dynamicFriction?: number, restitution?: number }`
|
|
3894
|
+
|
|
3895
|
+
`SimMaterialDef`: `{ kind: "material", name: string }`
|
|
3896
|
+
|
|
3897
|
+
#### `Sim.body(options: SimBodyOptions): SimBodyDef` — Describe one assembly part as a physical body with mass/density, material, collider intent, and optional contact surfaces.
|
|
3898
|
+
|
|
3899
|
+
**`SimBodyOptions`**: `massKg?: number`, `densityKgM3?: number`, `material?: SimMaterialDef`, `collider?: SimColliderDef`, `contacts?: Record<string, SimContactDef>`
|
|
3900
|
+
|
|
3901
|
+
`SimColliderDef`: `{ kind: "collider", mode: SimColliderMode, reason?: string }`
|
|
3902
|
+
|
|
3903
|
+
`SimContactDef`: `{ kind: "wheelSurface" | "gripperSurface", connectorName: string }`
|
|
3904
|
+
|
|
3905
|
+
`SimBodyDef`: `{ kind: "body" }`
|
|
3906
|
+
|
|
3907
|
+
#### `Sim.collider` — Collision-geometry intent constructors for physical parts.
|
|
3908
|
+
|
|
3909
|
+
- `Sim.collider.convexHull(): SimColliderDef` — Use a generated collision mesh for the part. This is the default fast rigid-body collider for irregular parts.
|
|
3910
|
+
- `Sim.collider.boundingBox(): SimColliderDef` — Use the part bounding box as the collision geometry. This is fastest and works well for chassis and simple blocks.
|
|
3911
|
+
- `Sim.collider.visualMesh(): SimColliderDef` — Use the visual mesh as collision geometry. This is exact but usually slower in physics engines.
|
|
3912
|
+
- `Sim.collider.none(reason: string): SimColliderDef` — Disable collision for a part with an explicit reason, such as a sensor-only or decorative object.
|
|
3913
|
+
|
|
3914
|
+
#### `Sim.drive` — Joint-drive intent constructors for passive or powered assembly joints.
|
|
3915
|
+
|
|
3916
|
+
- `Sim.drive.passive(options?: SimPassiveDriveOptions): SimDriveDef` — Mark a joint as passive while preserving damping and friction metadata for simulation export.
|
|
3917
|
+
- `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.
|
|
3918
|
+
|
|
3919
|
+
`SimPassiveDriveOptions`: `{ damping?: number, friction?: number }`
|
|
3920
|
+
|
|
3921
|
+
`SimVelocityDriveOptions`: `{ maxTorqueNm: number, maxSpeedRpm: number }`
|
|
3922
|
+
|
|
3923
|
+
#### `Sim.contact` — Contact-surface metadata over existing part connectors.
|
|
3924
|
+
|
|
3925
|
+
- `Sim.contact.wheelSurface(connectorName: string): SimContactDef` — Mark a connector as the wheel tread contact surface for offline checks and downstream simulation metadata.
|
|
3926
|
+
- `Sim.contact.gripperSurface(connectorName: string): SimContactDef` — Mark a connector as a gripper pad/contact surface for offline checks and downstream grasp-readiness metadata.
|
|
3927
|
+
|
|
3928
|
+
#### `Sim.profile` — Named validation/export profile constructors.
|
|
3929
|
+
|
|
3930
|
+
- `Sim.profile.robotBodyRunnable(): SimProfileDef` — SimReady-style profile for a robot body that should be runnable in a physics simulator.
|
|
3931
|
+
- `Sim.profile.robotBodyIsaac(): SimProfileDef` — SimReady-style profile for robot bodies targeting Isaac Sim readiness.
|
|
3932
|
+
- `Sim.profile.roboticsAssetPhysx(): SimProfileDef` — SimReady-style profile for robotics assets with PhysX-ready rigid bodies and colliders.
|
|
3933
|
+
|
|
3934
|
+
`SimProfileDef`: `{ kind: "profile", name: SimProfileName }`
|
|
3935
|
+
|
|
3936
|
+
#### `Sim.controller` — Standard controller metadata constructors for simulator package generation.
|
|
3937
|
+
|
|
3938
|
+
- `Sim.controller.diffDrive(options: SimDiffDriveControllerOptions): SimDiffDriveControllerDef` — Describe a differential-drive controller from left/right wheel joints and wheel dimensions.
|
|
3939
|
+
|
|
3940
|
+
**`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`
|
|
3941
|
+
|
|
3942
|
+
`SimDiffDriveControllerDef`: `{ kind: "diffDrive" }`
|
|
3943
|
+
|
|
3884
3944
|
#### `assembly(name?: string): Assembly` — Create an assembly container with named parts, connectors, and kinematic links.
|
|
3885
3945
|
|
|
3886
3946
|
**Use this from iteration 1 for any model with moving parts.** Do not build one static pose and retrofit motion later.
|
|
@@ -4014,7 +4074,7 @@ const housing = group(
|
|
|
4014
4074
|
assembly.addPart("Base Assembly", housing);
|
|
4015
4075
|
```
|
|
4016
4076
|
|
|
4017
|
-
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
4077
|
+
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `sim?: SimBodyDef`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
4018
4078
|
|
|
4019
4079
|
**`PartMetadata`**
|
|
4020
4080
|
|
|
@@ -4075,7 +4135,9 @@ Frame semantics: `origin` is the pivot/contact point, `axis` the hinge or slide
|
|
|
4075
4135
|
|
|
4076
4136
|
**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()`).
|
|
4077
4137
|
|
|
4078
|
-
**
|
|
4138
|
+
**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.
|
|
4139
|
+
|
|
4140
|
+
**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.
|
|
4079
4141
|
|
|
4080
4142
|
Joint type defaults to the connector's `kind`. For `start`/`end` connectors, `align` / `parentAlign` / `childAlign` (`'start' | 'middle' | 'end'`) choose which point meets.
|
|
4081
4143
|
|
|
@@ -4102,7 +4164,7 @@ assembly("Door").addPart("Frame", frame).addPart("Door", door)
|
|
|
4102
4164
|
| `align?` | `PortAlign` | Shorthand: set both parentAlign and childAlign at once. |
|
|
4103
4165
|
| `follows?` | `JointFollowOptions` | Slave this joint to another joint: `value = ratio × source + offset` (e.g. a mirrored jaw with `ratio: -1`). |
|
|
4104
4166
|
|
|
4105
|
-
Also: `as?: string`, `type?: JointType`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`.
|
|
4167
|
+
Also: `as?: string`, `type?: JointType`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `drive?: SimDriveDef`.
|
|
4106
4168
|
|
|
4107
4169
|
**`JointFollowOptions`**
|
|
4108
4170
|
- `joint: string` — Name of the source joint that drives this one.
|
|
@@ -4162,6 +4224,12 @@ return mech.solve({ theta: 45 });
|
|
|
4162
4224
|
|
|
4163
4225
|
**Other**
|
|
4164
4226
|
|
|
4227
|
+
#### `withSimulation(options: SimAssemblySimulationOptions): Assembly` — Attach the root simulation contract for this assembly.
|
|
4228
|
+
|
|
4229
|
+
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.
|
|
4230
|
+
|
|
4231
|
+
`SimAssemblySimulationOptions`: `{ profile: SimProfileDef, rootPart?: string, controllers?: SimControllerDef[] }`
|
|
4232
|
+
|
|
4165
4233
|
#### `edgeBetweenFrames(a: string, b: string, options?: AssemblyFrameEdgeOptions): Assembly` — Add a visual skeleton edge between two rig frame origins.
|
|
4166
4234
|
|
|
4167
4235
|
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.
|
|
@@ -4297,7 +4365,7 @@ The sub-assembly must have exactly one root part before it can be merged (collap
|
|
|
4297
4365
|
| `connectorRefs?` | `JointConnectorRefs` | Connector refs that define this joint contract. Usually set by `connect()` / `match()`. |
|
|
4298
4366
|
| `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. |
|
|
4299
4367
|
|
|
4300
|
-
Also: `frame?: TransformInput`, `origin?: Vec3`, `axis?: Vec3`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`.
|
|
4368
|
+
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`.
|
|
4301
4369
|
|
|
4302
4370
|
`JointConnectorRefs`: `{ parent: string, child: string, parentAlign?: PortAlign, childAlign?: PortAlign }`
|
|
4303
4371
|
|
|
@@ -4430,12 +4498,14 @@ bom(tubeLen, "rectangular steel tube", {
|
|
|
4430
4498
|
| `notes?` | `string` | Free-form notes |
|
|
4431
4499
|
| `grain?` | `string` | Wood grain direction, e.g. "long", "cross" |
|
|
4432
4500
|
|
|
4433
|
-
#### `robotExport(options: RobotExportOptions): CollectedRobotExport` —
|
|
4501
|
+
#### `robotExport(options: RobotExportOptions): CollectedRobotExport` — Compatibility shim for SDF/URDF robot package metadata.
|
|
4434
4502
|
|
|
4435
|
-
|
|
4503
|
+
Prefer returning `assembly(...).withSimulation(...)` with `Sim.body(...)`, `Sim.drive.*(...)`, and `Sim.controller.*(...)` metadata. The CLI commands `forgecad export sdf` and `forgecad export urdf` now read that assembly simulation contract directly.
|
|
4504
|
+
|
|
4505
|
+
`robotExport()` remains available for one compatibility window. It converts the legacy descriptor into the same internal simulation model used by source-authored `Sim` metadata and produces a robot package with:
|
|
4436
4506
|
|
|
4437
4507
|
- Mesh-based inertia tensors (full 6-component, not bounding-box approximations)
|
|
4438
|
-
- Separate collision meshes
|
|
4508
|
+
- Separate collision meshes
|
|
4439
4509
|
- Joint limits, effort/velocity/damping/friction metadata from assembly joints
|
|
4440
4510
|
|
|
4441
4511
|
**Collision mesh modes** (set per-link via `links["PartName"].collision`):
|
|
@@ -4454,6 +4524,8 @@ Call `robotExport()` alongside your assembly definition. `forgecad export sdf` /
|
|
|
4454
4524
|
- `massKg` is preferred; `densityKgM3` is used when mass is unknown.
|
|
4455
4525
|
- Compatibility coupling metadata, when present, maps only the primary term (largest ratio) to `<mimic>` — SDF/URDF support single-leader mimic only. Dropped terms emit a warning.
|
|
4456
4526
|
|
|
4527
|
+
**Legacy example**
|
|
4528
|
+
|
|
4457
4529
|
```ts
|
|
4458
4530
|
robotExport({
|
|
4459
4531
|
assembly: rover, // assembly() with parts + revolute wheel joints
|
|
@@ -4469,6 +4541,13 @@ robotExport({
|
|
|
4469
4541
|
});
|
|
4470
4542
|
```
|
|
4471
4543
|
|
|
4544
|
+
**Preferred CLI usage**
|
|
4545
|
+
|
|
4546
|
+
```bash
|
|
4547
|
+
forgecad export sdf model.forge.js # SDF package (Gazebo/Ignition)
|
|
4548
|
+
forgecad export urdf model.forge.js # URDF package (ROS/PyBullet/MuJoCo)
|
|
4549
|
+
```
|
|
4550
|
+
|
|
4472
4551
|
**`RobotExportOptions`**: `assembly: Assembly`, `modelName?: string`, `state?: JointState`, `static?: boolean`, `selfCollide?: boolean`, `allowAutoDisable?: boolean`, `links?: Record<string, RobotLinkExportOptions>`, `joints?: Record<string, RobotJointExportOptions>`, `plugins?: { diffDrive?: RobotDiffDrivePluginOptions; jointStatePublisher?: RobotJointStatePublisherOptions; }`, `world?: RobotWorldOptions`
|
|
4473
4552
|
|
|
4474
4553
|
`RobotLinkExportOptions`: `{ massKg?: number, densityKgM3?: number, collision?: "visual" | "convex" | "box" | "none" }`
|
|
@@ -4483,46 +4562,6 @@ robotExport({
|
|
|
4483
4562
|
|
|
4484
4563
|
`RobotWorldKeyboardTeleopOptions`: `{ enabled?: boolean, linearStep?: number, angularStep?: number }`
|
|
4485
4564
|
|
|
4486
|
-
**`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`
|
|
4487
|
-
|
|
4488
|
-
**`AssemblyDefinition`**: `name: string`, `parts: AssemblyPartDef[]`, `joints: AssemblyJointDef[]`, `jointCouplings: AssemblyJointCouplingDef[]`, `kinematics: AssemblyKinematicGraphDef`, `frames: AssemblyFrameDef[]`, `frameJoints: AssemblyFrameJointDef[]`, `frameEdges: AssemblyFrameEdgeDef[]`
|
|
4489
|
-
|
|
4490
|
-
**`AssemblyPartDef`**: `name: string`, `part: AssemblyPart`, `base: Transform`, `metadata?: PartMetadata`, `mates: AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
4491
|
-
|
|
4492
|
-
`PartMetadata` — defined in [assembly](/docs/assembly).
|
|
4493
|
-
|
|
4494
|
-
`AssemblyPartMateInput` — defined in [assembly](/docs/assembly).
|
|
4495
|
-
|
|
4496
|
-
**`AssemblyJointDef`**: `name: string`, `type: JointType`, `parent: string`, `child: string`, `frame: Transform`, `axis: Vec3`, `min?: number`, `max?: number`, `defaultValue: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `connectorRefs?: JointConnectorRefs`
|
|
4497
|
-
|
|
4498
|
-
`JointConnectorRefs` — defined in [assembly](/docs/assembly).
|
|
4499
|
-
|
|
4500
|
-
`AssemblyJointCouplingDef`: `{ joint: string, terms: JointCouplingTermRecord[], offset: number }`
|
|
4501
|
-
|
|
4502
|
-
`JointCouplingTermRecord`: `{ joint: string, ratio: number }`
|
|
4503
|
-
|
|
4504
|
-
**`AssemblyKinematicGraphDef`**: `links: AssemblyLinkDef[]`, `edges: AssemblyEdgeBetweenLinksDef[]`, `angles: AssemblyAngleBetweenLinksDef[]`, `derivedLinks: AssemblyDerivedLinkDef[]`
|
|
4505
|
-
|
|
4506
|
-
`AssemblyLinkDef`: `{ name: string, at: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
4507
|
-
|
|
4508
|
-
**`AssemblyEdgeBetweenLinksDef`**: `name: string`, `a: string`, `b: string`, `length: number | null`, `min?: number`, `max?: number`, `visualOnly: boolean`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
4509
|
-
|
|
4510
|
-
`AssemblyKinematicControlOptions` — defined in [assembly](/docs/assembly).
|
|
4511
|
-
|
|
4512
|
-
**`AssemblyAngleBetweenLinksDef`**: `name: string`, `a?: string`, `b: string`, `c: string`, `reference?: AssemblyAngleReferenceDef`, `target?: number`, `min?: number`, `max?: number`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
4513
|
-
|
|
4514
|
-
`AssemblyAngleReferenceDef`: `{ kind: "worldDirection", direction: Vec3 }`
|
|
4515
|
-
|
|
4516
|
-
**`AssemblyDerivedLinkDef`**
|
|
4517
|
-
- `distance: number` — Signed: positive moves from `fromLink` toward `towardLink`, negative moves away.
|
|
4518
|
-
- Also: `name: string`, `fromLink: string`, `towardLink: string`.
|
|
4519
|
-
|
|
4520
|
-
`AssemblyFrameDef`: `{ name: string, origin: Vec3, axis: Vec3, up: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
4521
|
-
|
|
4522
|
-
**`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>`
|
|
4523
|
-
|
|
4524
|
-
`AssemblyFrameEdgeDef`: `{ name: string, a: string, b: string, metadata?: Record<string, unknown> }`
|
|
4525
|
-
|
|
4526
4565
|
#### `dim()` — Add a dimension annotation between two points, or along an entity.
|
|
4527
4566
|
|
|
4528
4567
|
Overloads:
|
|
@@ -23,7 +23,7 @@ A script must return one of three shapes:
|
|
|
23
23
|
];
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
3. **A metadata object** — a plain object whose renderable values are rendered and whose non-renderable values (numbers, hole tables, builder functions) are silently skipped at render but flow to importers via `require()`.
|
|
26
|
+
3. **A metadata object** — a plain object whose renderable values are rendered and whose non-renderable values (numbers, hole tables, builder functions) are silently skipped at render but flow to importers via `require()`. Each key becomes a named group, so don't pile independent parts into one array key (`{ parts: [a, b, c] }`) — the integrity gate reads that as a single fragmented part. Give each part its own key (`{ collar12, collar16, plug }`) or use named descriptors (form 2).
|
|
27
27
|
|
|
28
28
|
Return an unsolved `Assembly` directly — ForgeCAD solves it at default joint values for display. Use `assembly.solve(state)` for a specific pose. Never call `.toGroup()` just to make an assembly render; use it only when you need `ShapeGroup` composition or named-child lookup.
|
|
29
29
|
|
package/dist-skill/docs/CLI.md
CHANGED
|
@@ -46,7 +46,9 @@ ForgeCAD includes a local editor. Open it around a dedicated project folder, edi
|
|
|
46
46
|
| `dev <project-path> [project-path ...]` | Start the Vite dev server for ForgeCAD source development. |
|
|
47
47
|
| `web` | Start a local dev server in web/playground mode (no filesystem, localStorage only). |
|
|
48
48
|
|
|
49
|
-
`forgecad studio <project-path>` is the normal installed-CLI command
|
|
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
|
+
|
|
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.
|
|
50
52
|
|
|
51
53
|
<details>
|
|
52
54
|
<summary>Common flags for studio / dev</summary>
|
|
@@ -291,6 +293,7 @@ Export to every format you need.
|
|
|
291
293
|
| `export stl` | STL | 3D printing |
|
|
292
294
|
| `export gcode` **\[Production\]** | G-code | Toolpath (scripted, not sliced) |
|
|
293
295
|
| `export sdf` **\[Production\]** | SDF package | Gazebo robot simulation |
|
|
296
|
+
| `export mjcf` **\[Production\]** | MJCF package | MuJoCo / MJX robot simulation |
|
|
294
297
|
| `export urdf` **\[Production\]** | URDF package | ROS / PyBullet / MuJoCo |
|
|
295
298
|
| `export report` **\[Production\]** | PDF report | Multi-view report with BOM and dimensions |
|
|
296
299
|
| `export cutting-layout` **\[Production\]** | PDF/DXF | Sheet cutting layout with cut sequence |
|
|
@@ -314,6 +317,7 @@ forgecad export report bracket.forge.js out/report.pdf
|
|
|
314
317
|
|
|
315
318
|
# Robot simulation
|
|
316
319
|
forgecad export sdf rover.forge.js --output out/forge_scout
|
|
320
|
+
forgecad export mjcf rover.forge.js --output out/forge_scout_mjcf
|
|
317
321
|
```
|
|
318
322
|
|
|
319
323
|
<details>
|
|
@@ -451,7 +455,7 @@ forgecad skill flattened-files ~/Desktop/forgecad-skills
|
|
|
451
455
|
|
|
452
456
|
## Validation
|
|
453
457
|
|
|
454
|
-
Check printability and
|
|
458
|
+
Check printability, simulation readiness, and focused model integrity.
|
|
455
459
|
|
|
456
460
|
### `forgecad compare 3d`
|
|
457
461
|
|
|
@@ -477,6 +481,17 @@ forgecad check print model.forge.js
|
|
|
477
481
|
forgecad check print model.forge.js --json
|
|
478
482
|
```
|
|
479
483
|
|
|
484
|
+
### `forgecad check simready`
|
|
485
|
+
|
|
486
|
+
Validate source-authored robot and physics metadata before simulation export.
|
|
487
|
+
|
|
488
|
+
Runs a Forge script and checks the returned `assembly(...).withSimulation(...)` contract without Isaac Sim, OpenUSD, or NVIDIA validators. The gate validates Sim.body metadata, explicit colliders, contact connectors, controller joints, numeric physics values, and the robot joint graph.
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
forgecad check simready model.forge.js
|
|
492
|
+
forgecad check simready robot.forge.js --json
|
|
493
|
+
```
|
|
494
|
+
|
|
480
495
|
### `forgecad inspect mechanical-integrity`
|
|
481
496
|
|
|
482
497
|
Inspect generated ForgeCAD models for mechanical integrity failures.
|
|
@@ -514,7 +529,7 @@ The CLI is free for personal non-commercial use. Pro covers human-operated comme
|
|
|
514
529
|
|
|
515
530
|
| Free | Production outputs | Pro | Enterprise |
|
|
516
531
|
|------|--------------------|-----|------------|
|
|
517
|
-
| `run`, `dev`, `studio`, `render 3d`, `export stl`, `export 3mf`, `export svg`, `compare 3d`, `check print`, `inspect fit interference`, `inspect mechanical-integrity` for personal non-commercial use | `cut-list`, `export sketch-pdf`, `export step`, `export brep`, `export gcode`, `export sdf`, `export urdf`, `export report`, `export cutting-layout` are free to run for personal non-commercial use; Pro covers human-operated commercial CAD work | `render hq`, `capture gif`, `capture mp4` plus commercial coverage for client/customer work | Backend, hosted, embedded, or application workflows that call ForgeCAD automatically |
|
|
532
|
+
| `run`, `dev`, `studio`, `render 3d`, `export stl`, `export 3mf`, `export svg`, `compare 3d`, `check print`, `inspect fit interference`, `inspect mechanical-integrity` for personal non-commercial use | `cut-list`, `export sketch-pdf`, `export step`, `export brep`, `export gcode`, `export sdf`, `export mjcf`, `export urdf`, `export report`, `export cutting-layout` are free to run for personal non-commercial use; Pro covers human-operated commercial CAD work | `render hq`, `capture gif`, `capture mp4` plus commercial coverage for client/customer work | Backend, hosted, embedded, or application workflows that call ForgeCAD automatically |
|
|
518
533
|
|
|
519
534
|
```bash
|
|
520
535
|
forgecad license # Check local license status
|
|
@@ -5,7 +5,7 @@ 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
|
|
|
@@ -18,6 +18,59 @@ Assembly-owned links, constraints, connectors, solved poses, and robot export.
|
|
|
18
18
|
|
|
19
19
|
### Assembly & Joints
|
|
20
20
|
|
|
21
|
+
#### `Sim.material(name: string, options?: SimMaterialOptions): SimMaterialDef` — Create a named physical material with density and contact coefficients for simulation export and checks.
|
|
22
|
+
|
|
23
|
+
`SimMaterialOptions`: `{ densityKgM3?: number, staticFriction?: number, dynamicFriction?: number, restitution?: number }`
|
|
24
|
+
|
|
25
|
+
`SimMaterialDef`: `{ kind: "material", name: string }`
|
|
26
|
+
|
|
27
|
+
#### `Sim.body(options: SimBodyOptions): SimBodyDef` — Describe one assembly part as a physical body with mass/density, material, collider intent, and optional contact surfaces.
|
|
28
|
+
|
|
29
|
+
**`SimBodyOptions`**: `massKg?: number`, `densityKgM3?: number`, `material?: SimMaterialDef`, `collider?: SimColliderDef`, `contacts?: Record<string, SimContactDef>`
|
|
30
|
+
|
|
31
|
+
`SimColliderDef`: `{ kind: "collider", mode: SimColliderMode, reason?: string }`
|
|
32
|
+
|
|
33
|
+
`SimContactDef`: `{ kind: "wheelSurface" | "gripperSurface", connectorName: string }`
|
|
34
|
+
|
|
35
|
+
`SimBodyDef`: `{ kind: "body" }`
|
|
36
|
+
|
|
37
|
+
#### `Sim.collider` — Collision-geometry intent constructors for physical parts.
|
|
38
|
+
|
|
39
|
+
- `Sim.collider.convexHull(): SimColliderDef` — Use a generated collision mesh for the part. This is the default fast rigid-body collider for irregular parts.
|
|
40
|
+
- `Sim.collider.boundingBox(): SimColliderDef` — Use the part bounding box as the collision geometry. This is fastest and works well for chassis and simple blocks.
|
|
41
|
+
- `Sim.collider.visualMesh(): SimColliderDef` — Use the visual mesh as collision geometry. This is exact but usually slower in physics engines.
|
|
42
|
+
- `Sim.collider.none(reason: string): SimColliderDef` — Disable collision for a part with an explicit reason, such as a sensor-only or decorative object.
|
|
43
|
+
|
|
44
|
+
#### `Sim.drive` — Joint-drive intent constructors for passive or powered assembly joints.
|
|
45
|
+
|
|
46
|
+
- `Sim.drive.passive(options?: SimPassiveDriveOptions): SimDriveDef` — Mark a joint as passive while preserving damping and friction metadata for simulation export.
|
|
47
|
+
- `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.
|
|
48
|
+
|
|
49
|
+
`SimPassiveDriveOptions`: `{ damping?: number, friction?: number }`
|
|
50
|
+
|
|
51
|
+
`SimVelocityDriveOptions`: `{ maxTorqueNm: number, maxSpeedRpm: number }`
|
|
52
|
+
|
|
53
|
+
#### `Sim.contact` — Contact-surface metadata over existing part connectors.
|
|
54
|
+
|
|
55
|
+
- `Sim.contact.wheelSurface(connectorName: string): SimContactDef` — Mark a connector as the wheel tread contact surface for offline checks and downstream simulation metadata.
|
|
56
|
+
- `Sim.contact.gripperSurface(connectorName: string): SimContactDef` — Mark a connector as a gripper pad/contact surface for offline checks and downstream grasp-readiness metadata.
|
|
57
|
+
|
|
58
|
+
#### `Sim.profile` — Named validation/export profile constructors.
|
|
59
|
+
|
|
60
|
+
- `Sim.profile.robotBodyRunnable(): SimProfileDef` — SimReady-style profile for a robot body that should be runnable in a physics simulator.
|
|
61
|
+
- `Sim.profile.robotBodyIsaac(): SimProfileDef` — SimReady-style profile for robot bodies targeting Isaac Sim readiness.
|
|
62
|
+
- `Sim.profile.roboticsAssetPhysx(): SimProfileDef` — SimReady-style profile for robotics assets with PhysX-ready rigid bodies and colliders.
|
|
63
|
+
|
|
64
|
+
`SimProfileDef`: `{ kind: "profile", name: SimProfileName }`
|
|
65
|
+
|
|
66
|
+
#### `Sim.controller` — Standard controller metadata constructors for simulator package generation.
|
|
67
|
+
|
|
68
|
+
- `Sim.controller.diffDrive(options: SimDiffDriveControllerOptions): SimDiffDriveControllerDef` — Describe a differential-drive controller from left/right wheel joints and wheel dimensions.
|
|
69
|
+
|
|
70
|
+
**`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`
|
|
71
|
+
|
|
72
|
+
`SimDiffDriveControllerDef`: `{ kind: "diffDrive" }`
|
|
73
|
+
|
|
21
74
|
#### `assembly(name?: string): Assembly` — Create an assembly container with named parts, connectors, and kinematic links.
|
|
22
75
|
|
|
23
76
|
**Use this from iteration 1 for any model with moving parts.** Do not build one static pose and retrofit motion later.
|
|
@@ -151,7 +204,7 @@ const housing = group(
|
|
|
151
204
|
assembly.addPart("Base Assembly", housing);
|
|
152
205
|
```
|
|
153
206
|
|
|
154
|
-
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
207
|
+
**`PartOptions`**: `transform?: TransformInput`, `metadata?: PartMetadata`, `sim?: SimBodyDef`, `mate?: AssemblyPartMateInput | AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
155
208
|
|
|
156
209
|
**`PartMetadata`**
|
|
157
210
|
|
|
@@ -212,7 +265,9 @@ Frame semantics: `origin` is the pivot/contact point, `axis` the hinge or slide
|
|
|
212
265
|
|
|
213
266
|
**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()`).
|
|
214
267
|
|
|
215
|
-
**
|
|
268
|
+
**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.
|
|
269
|
+
|
|
270
|
+
**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.
|
|
216
271
|
|
|
217
272
|
Joint type defaults to the connector's `kind`. For `start`/`end` connectors, `align` / `parentAlign` / `childAlign` (`'start' | 'middle' | 'end'`) choose which point meets.
|
|
218
273
|
|
|
@@ -239,7 +294,7 @@ assembly("Door").addPart("Frame", frame).addPart("Door", door)
|
|
|
239
294
|
| `align?` | `PortAlign` | Shorthand: set both parentAlign and childAlign at once. |
|
|
240
295
|
| `follows?` | `JointFollowOptions` | Slave this joint to another joint: `value = ratio × source + offset` (e.g. a mirrored jaw with `ratio: -1`). |
|
|
241
296
|
|
|
242
|
-
Also: `as?: string`, `type?: JointType`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`.
|
|
297
|
+
Also: `as?: string`, `type?: JointType`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `drive?: SimDriveDef`.
|
|
243
298
|
|
|
244
299
|
**`JointFollowOptions`**
|
|
245
300
|
- `joint: string` — Name of the source joint that drives this one.
|
|
@@ -299,6 +354,12 @@ return mech.solve({ theta: 45 });
|
|
|
299
354
|
|
|
300
355
|
**Other**
|
|
301
356
|
|
|
357
|
+
#### `withSimulation(options: SimAssemblySimulationOptions): Assembly` — Attach the root simulation contract for this assembly.
|
|
358
|
+
|
|
359
|
+
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.
|
|
360
|
+
|
|
361
|
+
`SimAssemblySimulationOptions`: `{ profile: SimProfileDef, rootPart?: string, controllers?: SimControllerDef[] }`
|
|
362
|
+
|
|
302
363
|
#### `edgeBetweenFrames(a: string, b: string, options?: AssemblyFrameEdgeOptions): Assembly` — Add a visual skeleton edge between two rig frame origins.
|
|
303
364
|
|
|
304
365
|
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.
|
|
@@ -434,7 +495,7 @@ The sub-assembly must have exactly one root part before it can be merged (collap
|
|
|
434
495
|
| `connectorRefs?` | `JointConnectorRefs` | Connector refs that define this joint contract. Usually set by `connect()` / `match()`. |
|
|
435
496
|
| `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. |
|
|
436
497
|
|
|
437
|
-
Also: `frame?: TransformInput`, `origin?: Vec3`, `axis?: Vec3`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`.
|
|
498
|
+
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`.
|
|
438
499
|
|
|
439
500
|
`JointConnectorRefs`: `{ parent: string, child: string, parentAlign?: PortAlign, childAlign?: PortAlign }`
|
|
440
501
|
|
|
@@ -111,6 +111,8 @@ The `edges` parameter is flexible:
|
|
|
111
111
|
|
|
112
112
|
Throws if no edges match the selection, or if `radius` is not a positive finite number.
|
|
113
113
|
|
|
114
|
+
Selectorless (all-edges) calls draw from a per-run broad edge-feature budget. Exceeding it throws — except in live preview, which skips the finish with a warning for responsiveness. Explicit edge selectors are never budgeted; `FORGECAD_BROAD_EDGE_FEATURE_BUDGET` / `FORGECAD_ALLOW_BROAD_EDGE_FEATURES=1` raise or lift the budget.
|
|
115
|
+
|
|
114
116
|
```ts
|
|
115
117
|
// Fillet all edges
|
|
116
118
|
fillet(myShape, 2)
|
|
@@ -133,6 +135,8 @@ fillet(base, 5, base.edge('vert-br'))
|
|
|
133
135
|
|
|
134
136
|
Produces a 45° bevel at the specified `size` (distance from edge). Edge selections compile into backend operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
|
|
135
137
|
|
|
138
|
+
Selectorless (all-edges) calls draw from a per-run broad edge-feature budget. Exceeding it throws — except in live preview, which skips the finish with a warning for responsiveness. Explicit edge selectors are never budgeted; `FORGECAD_BROAD_EDGE_FEATURE_BUDGET` / `FORGECAD_ALLOW_BROAD_EDGE_FEATURES=1` raise or lift the budget.
|
|
139
|
+
|
|
136
140
|
The `edges` parameter accepts the same options as `fillet()`: inline `EdgeQuery`, pre-selected `EdgeSegment`/`EdgeSegment[]`, a tracked `EdgeRef` from `shape.edge('vert-br')` (exact compiler-owned path), or `undefined` (all sharp edges).
|
|
137
141
|
|
|
138
142
|
```ts
|
|
@@ -1406,15 +1410,18 @@ Namespaced file-format import helpers — the single vocabulary for bringing ext
|
|
|
1406
1410
|
|
|
1407
1411
|
- `dxfSketch(fileName: string, options?: DxfImportOptions): Sketch` — Parse a DXF file and return closed 2D profile geometry as a Sketch. The result can be extruded directly.
|
|
1408
1412
|
- `svgSketch(fileName: string, options?: SvgImportOptions): Sketch` — Parse an SVG file and return it as a Sketch with options for region filtering, scaling, and simplification.
|
|
1409
|
-
- `mesh(fileName: string, options?:
|
|
1413
|
+
- `mesh(fileName: string, options?: MeshImportOptions): Shape | ShapeGroup` — Import an external mesh file (STL, OBJ, 3MF).
|
|
1410
1414
|
|
|
1411
1415
|
By default, 3MF build items are flattened into one Shape for compatibility. Use `separateObjects: true` to import 3MF build items/resource objects as a named ShapeGroup whose children are targetable by `forgecad ls`. Use `object` to import one item by the stable ref/name reported by `forgecad run`.
|
|
1412
1416
|
|
|
1413
1417
|
For 3MF sources, `forgecad run` prints a source-structure table with one line per build item: `[3mf:build:NNN:object:N] name type=... verts=... tris=... bbox=[min] → [max]`. Build items are numbered from `001`; files with no build items list resource objects as `3mf:object:N` instead. Per-item bboxes reveal multi-part structure — account for every substantial item before flattening. Pass any listed stable ref or name as `object` to import that item alone.
|
|
1414
1418
|
|
|
1419
|
+
Use `sourceFrame: { up: "+Y" }` when the file was authored in a non-Z-up coordinate system. ForgeCAD remains Z-up; the import is rotated so the named source axis becomes ForgeCAD +Z. Supported values: `"+X"`, `"-X"`, `"+Y"`, `"-Y"`, `"+Z"`, `"-Z"`.
|
|
1420
|
+
|
|
1415
1421
|
```js
|
|
1416
1422
|
const all = Import.mesh("./assembly.3mf", { separateObjects: true });
|
|
1417
1423
|
const pin = all.child("Pin #001");
|
|
1418
1424
|
const plate = Import.mesh("./assembly.3mf", { object: "3mf:build:001:object:7" });
|
|
1425
|
+
const yUpPart = Import.mesh("./part.obj", { sourceFrame: { up: "+Y" } });
|
|
1419
1426
|
```
|
|
1420
|
-
- `step(fileName: string): Shape` — Import a STEP file (.step, .stp) as an exact OCCT-backed Shape. Preserves NURBS curves, B-spline surfaces, and exact topology. Requires running with the OCCT backend.
|
|
1427
|
+
- `step(fileName: string, options?: StepImportOptions): Shape` — Import a STEP file (.step, .stp) as an exact OCCT-backed Shape. Preserves NURBS curves, B-spline surfaces, and exact topology. Requires running with the OCCT backend. Use `sourceFrame: { up: "+Y" }` to rotate Y-up source files into ForgeCAD's Z-up world.
|
|
@@ -63,7 +63,7 @@ Pre-built fasteners, gears, pipes, structural profiles, and utility shapes. Acce
|
|
|
63
63
|
|
|
64
64
|
Pre-built parametric parts available in user scripts as `lib.*`.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
exposed to `.forge.js` scripts — see the member list below for the catalog. Sizes outside the supported ranges throw at runtime with a descriptive error.
|
|
67
67
|
|
|
68
68
|
- `fastenerHole(opts: FastenerHoleOptions): Shape` — ISO metric fastener hole cutter with optional counterbore or countersink.
|
|
69
69
|
|
|
@@ -58,12 +58,14 @@ bom(tubeLen, "rectangular steel tube", {
|
|
|
58
58
|
| `notes?` | `string` | Free-form notes |
|
|
59
59
|
| `grain?` | `string` | Wood grain direction, e.g. "long", "cross" |
|
|
60
60
|
|
|
61
|
-
#### `robotExport(options: RobotExportOptions): CollectedRobotExport` —
|
|
61
|
+
#### `robotExport(options: RobotExportOptions): CollectedRobotExport` — Compatibility shim for SDF/URDF robot package metadata.
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Prefer returning `assembly(...).withSimulation(...)` with `Sim.body(...)`, `Sim.drive.*(...)`, and `Sim.controller.*(...)` metadata. The CLI commands `forgecad export sdf` and `forgecad export urdf` now read that assembly simulation contract directly.
|
|
64
|
+
|
|
65
|
+
`robotExport()` remains available for one compatibility window. It converts the legacy descriptor into the same internal simulation model used by source-authored `Sim` metadata and produces a robot package with:
|
|
64
66
|
|
|
65
67
|
- Mesh-based inertia tensors (full 6-component, not bounding-box approximations)
|
|
66
|
-
- Separate collision meshes
|
|
68
|
+
- Separate collision meshes
|
|
67
69
|
- Joint limits, effort/velocity/damping/friction metadata from assembly joints
|
|
68
70
|
|
|
69
71
|
**Collision mesh modes** (set per-link via `links["PartName"].collision`):
|
|
@@ -82,6 +84,8 @@ Call `robotExport()` alongside your assembly definition. `forgecad export sdf` /
|
|
|
82
84
|
- `massKg` is preferred; `densityKgM3` is used when mass is unknown.
|
|
83
85
|
- Compatibility coupling metadata, when present, maps only the primary term (largest ratio) to `<mimic>` — SDF/URDF support single-leader mimic only. Dropped terms emit a warning.
|
|
84
86
|
|
|
87
|
+
**Legacy example**
|
|
88
|
+
|
|
85
89
|
```ts
|
|
86
90
|
robotExport({
|
|
87
91
|
assembly: rover, // assembly() with parts + revolute wheel joints
|
|
@@ -97,6 +101,13 @@ robotExport({
|
|
|
97
101
|
});
|
|
98
102
|
```
|
|
99
103
|
|
|
104
|
+
**Preferred CLI usage**
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
forgecad export sdf model.forge.js # SDF package (Gazebo/Ignition)
|
|
108
|
+
forgecad export urdf model.forge.js # URDF package (ROS/PyBullet/MuJoCo)
|
|
109
|
+
```
|
|
110
|
+
|
|
100
111
|
**`RobotExportOptions`**: `assembly: Assembly`, `modelName?: string`, `state?: JointState`, `static?: boolean`, `selfCollide?: boolean`, `allowAutoDisable?: boolean`, `links?: Record<string, RobotLinkExportOptions>`, `joints?: Record<string, RobotJointExportOptions>`, `plugins?: { diffDrive?: RobotDiffDrivePluginOptions; jointStatePublisher?: RobotJointStatePublisherOptions; }`, `world?: RobotWorldOptions`
|
|
101
112
|
|
|
102
113
|
`RobotLinkExportOptions`: `{ massKg?: number, densityKgM3?: number, collision?: "visual" | "convex" | "box" | "none" }`
|
|
@@ -111,46 +122,6 @@ robotExport({
|
|
|
111
122
|
|
|
112
123
|
`RobotWorldKeyboardTeleopOptions`: `{ enabled?: boolean, linearStep?: number, angularStep?: number }`
|
|
113
124
|
|
|
114
|
-
**`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`
|
|
115
|
-
|
|
116
|
-
**`AssemblyDefinition`**: `name: string`, `parts: AssemblyPartDef[]`, `joints: AssemblyJointDef[]`, `jointCouplings: AssemblyJointCouplingDef[]`, `kinematics: AssemblyKinematicGraphDef`, `frames: AssemblyFrameDef[]`, `frameJoints: AssemblyFrameJointDef[]`, `frameEdges: AssemblyFrameEdgeDef[]`
|
|
117
|
-
|
|
118
|
-
**`AssemblyPartDef`**: `name: string`, `part: AssemblyPart`, `base: Transform`, `metadata?: PartMetadata`, `mates: AssemblyPartMateInput[]`, `bindToFrame?: string`
|
|
119
|
-
|
|
120
|
-
`PartMetadata` — defined in [assembly](/docs/assembly).
|
|
121
|
-
|
|
122
|
-
`AssemblyPartMateInput` — defined in [assembly](/docs/assembly).
|
|
123
|
-
|
|
124
|
-
**`AssemblyJointDef`**: `name: string`, `type: JointType`, `parent: string`, `child: string`, `frame: Transform`, `axis: Vec3`, `min?: number`, `max?: number`, `defaultValue: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `connectorRefs?: JointConnectorRefs`
|
|
125
|
-
|
|
126
|
-
`JointConnectorRefs` — defined in [assembly](/docs/assembly).
|
|
127
|
-
|
|
128
|
-
`AssemblyJointCouplingDef`: `{ joint: string, terms: JointCouplingTermRecord[], offset: number }`
|
|
129
|
-
|
|
130
|
-
`JointCouplingTermRecord`: `{ joint: string, ratio: number }`
|
|
131
|
-
|
|
132
|
-
**`AssemblyKinematicGraphDef`**: `links: AssemblyLinkDef[]`, `edges: AssemblyEdgeBetweenLinksDef[]`, `angles: AssemblyAngleBetweenLinksDef[]`, `derivedLinks: AssemblyDerivedLinkDef[]`
|
|
133
|
-
|
|
134
|
-
`AssemblyLinkDef`: `{ name: string, at: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
135
|
-
|
|
136
|
-
**`AssemblyEdgeBetweenLinksDef`**: `name: string`, `a: string`, `b: string`, `length: number | null`, `min?: number`, `max?: number`, `visualOnly: boolean`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
137
|
-
|
|
138
|
-
`AssemblyKinematicControlOptions` — defined in [assembly](/docs/assembly).
|
|
139
|
-
|
|
140
|
-
**`AssemblyAngleBetweenLinksDef`**: `name: string`, `a?: string`, `b: string`, `c: string`, `reference?: AssemblyAngleReferenceDef`, `target?: number`, `min?: number`, `max?: number`, `control?: AssemblyKinematicControlOptions`, `metadata?: Record<string, unknown>`
|
|
141
|
-
|
|
142
|
-
`AssemblyAngleReferenceDef`: `{ kind: "worldDirection", direction: Vec3 }`
|
|
143
|
-
|
|
144
|
-
**`AssemblyDerivedLinkDef`**
|
|
145
|
-
- `distance: number` — Signed: positive moves from `fromLink` toward `towardLink`, negative moves away.
|
|
146
|
-
- Also: `name: string`, `fromLink: string`, `towardLink: string`.
|
|
147
|
-
|
|
148
|
-
`AssemblyFrameDef`: `{ name: string, origin: Vec3, axis: Vec3, up: Vec3, fixed: boolean, metadata?: Record<string, unknown> }`
|
|
149
|
-
|
|
150
|
-
**`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>`
|
|
151
|
-
|
|
152
|
-
`AssemblyFrameEdgeDef`: `{ name: string, a: string, b: string, metadata?: Record<string, unknown> }`
|
|
153
|
-
|
|
154
125
|
#### `dim()` — Add a dimension annotation between two points, or along an entity.
|
|
155
126
|
|
|
156
127
|
Overloads:
|