forgecad 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +2 -11
  2. package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-DAu1C1ST.js} +250 -151
  3. package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
  4. package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-Gc_BCdqC.js} +269 -143
  5. package/dist/assets/EditorApp-D9bJvtf7.js +11338 -0
  6. package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-DG1-oUSV.css} +459 -87
  7. package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-CEO8XbV8.js} +2 -4
  8. package/dist/assets/LandingPage-CdCuEOdC.js +451 -0
  9. package/dist/assets/PricingPage-BSrxu6d7.js +232 -0
  10. package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-FUCSIRq6.js} +129 -5
  11. package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-KoR0SNKq.js} +6770 -2914
  12. package/dist/assets/{index-2hfs_ub0.css → index-CyVd1D4D.css} +227 -53
  13. package/dist/assets/{Viewport-CoB46f5R.js → index-wTEK39at.js} +31385 -6439
  14. package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
  15. package/dist/assets/{manifold-CqNMHHKO.js → manifold-B1sGWdYk.js} +4 -3
  16. package/dist/assets/{manifold-Cce9wRFz.js → manifold-D7o0N50J.js} +1 -1
  17. package/dist/assets/{manifold-D6BeHIOo.js → manifold-G5sBaXzi.js} +1 -1
  18. package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-DYcRHhv9.js} +6798 -3341
  19. package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
  20. package/dist/docs-raw/generated/assembly.md +691 -112
  21. package/dist/docs-raw/generated/concepts.md +1225 -1400
  22. package/dist/docs-raw/generated/core.md +464 -1412
  23. package/dist/docs-raw/generated/curves.md +593 -117
  24. package/dist/docs-raw/generated/lib.md +38 -748
  25. package/dist/docs-raw/generated/output.md +139 -245
  26. package/dist/docs-raw/generated/sheet-metal.md +473 -21
  27. package/dist/docs-raw/generated/sketch.md +553 -349
  28. package/dist/docs-raw/generated/viewport.md +345 -303
  29. package/dist/docs-raw/generated/wood.md +104 -0
  30. package/dist/index.html +2 -2
  31. package/dist/sitemap.xml +6 -6
  32. package/dist-cli/chunk-PZ5AY32C.js +10 -0
  33. package/dist-cli/chunk-PZ5AY32C.js.map +1 -0
  34. package/dist-cli/forgecad.js +9435 -5407
  35. package/dist-cli/forgecad.js.map +1 -0
  36. package/dist-cli/solver-FV7TJZGI.js +365 -0
  37. package/dist-cli/solver-FV7TJZGI.js.map +1 -0
  38. package/dist-skill/CONTEXT.md +3186 -7145
  39. package/dist-skill/SKILL-dev.md +21 -63
  40. package/dist-skill/SKILL.md +12 -56
  41. package/dist-skill/docs/API/core/concepts.md +16 -98
  42. package/dist-skill/docs/CLI/export.md +91 -0
  43. package/dist-skill/docs/CLI/projects.md +107 -0
  44. package/dist-skill/docs/CLI/studio_publishing.md +52 -0
  45. package/dist-skill/docs/CLI/validation.md +66 -0
  46. package/dist-skill/docs/generated/assembly.md +691 -112
  47. package/dist-skill/docs/generated/core.md +464 -1412
  48. package/dist-skill/docs/generated/curves.md +593 -117
  49. package/dist-skill/docs/generated/lib.md +38 -748
  50. package/dist-skill/docs/generated/output.md +139 -245
  51. package/dist-skill/docs/generated/sheet-metal.md +473 -21
  52. package/dist-skill/docs/generated/sketch.md +553 -349
  53. package/dist-skill/docs/generated/viewport.md +345 -303
  54. package/dist-skill/docs/generated/wood.md +104 -0
  55. package/dist-skill/docs/guides/coordinate-system.md +11 -17
  56. package/dist-skill/docs/guides/geometry-conventions.md +13 -70
  57. package/dist-skill/docs/guides/modeling-recipes.md +22 -195
  58. package/dist-skill/docs/guides/positioning.md +88 -147
  59. package/dist-skill/docs-dev/API/core/concepts.md +51 -0
  60. package/dist-skill/docs-dev/API/core/sdf-advanced.md +92 -0
  61. package/dist-skill/docs-dev/API/core/sdf-primitives.md +58 -0
  62. package/dist-skill/docs-dev/API/core/sdf-workflow.md +42 -0
  63. package/dist-skill/docs-dev/CLI/export.md +91 -0
  64. package/dist-skill/docs-dev/CLI/projects.md +107 -0
  65. package/dist-skill/docs-dev/CLI/studio_publishing.md +52 -0
  66. package/dist-skill/docs-dev/CLI/validation.md +66 -0
  67. package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
  68. package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
  69. package/dist-skill/{docs → docs-dev}/coding.md +1 -3
  70. package/dist-skill/docs-dev/generated/assembly.md +771 -0
  71. package/dist-skill/docs-dev/generated/core.md +775 -0
  72. package/dist-skill/docs-dev/generated/curves.md +688 -0
  73. package/dist-skill/docs-dev/generated/lib.md +50 -0
  74. package/dist-skill/docs-dev/generated/output.md +234 -0
  75. package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
  76. package/dist-skill/docs-dev/generated/sketch.md +801 -0
  77. package/dist-skill/docs-dev/generated/viewport.md +486 -0
  78. package/dist-skill/docs-dev/generated/wood.md +104 -0
  79. package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
  80. package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
  81. package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
  82. package/dist-skill/docs-dev/guides/positioning.md +151 -0
  83. package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
  84. package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
  85. package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
  86. package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
  87. package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
  88. package/examples/api/attachTo-basics.forge.js +5 -5
  89. package/examples/api/boolean-operations.forge.js +3 -3
  90. package/examples/api/bounding-box-visualizer.forge.js +2 -2
  91. package/examples/api/clone-duplicate.forge.js +1 -1
  92. package/examples/api/colors-union-vs-array.forge.js +6 -6
  93. package/examples/api/connector-assembly.forge.js +4 -4
  94. package/examples/api/connector-basics.forge.js +2 -2
  95. package/examples/api/extrude-options.forge.js +4 -10
  96. package/examples/api/feature-created-faces.forge.js +6 -10
  97. package/examples/api/fillet-showcase.forge.js +1 -1
  98. package/examples/api/folded-service-panel-cover.forge.js +2 -2
  99. package/examples/api/group-test.forge.js +1 -1
  100. package/examples/api/group-vs-union.forge.js +1 -1
  101. package/examples/api/highlight-debug.forge.js +4 -0
  102. package/examples/api/js-module-pillars.js +1 -1
  103. package/examples/api/js-module-scene.js +2 -2
  104. package/examples/api/mesh-import-slats.forge.js +1 -1
  105. package/examples/api/pointAlong-orientation.forge.js +1 -1
  106. package/examples/api/profile-2020-b-slot6.forge.js +0 -1
  107. package/examples/api/route-perimeter-flange.forge.js +1 -1
  108. package/examples/api/sdf-rover-demo.forge.js +10 -10
  109. package/examples/api/sketch-on-face-demo.forge.js +2 -2
  110. package/examples/api/sketch-regions.forge.js +4 -4
  111. package/examples/api/transition-curves.forge.js +1 -1
  112. package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
  113. package/examples/api/variable-sweep-test.forge.js +2 -2
  114. package/examples/api/wood-joinery.forge.js +60 -0
  115. package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
  116. package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
  117. package/examples/experiments/drone-arm.forge.js +53 -0
  118. package/examples/furniture/adjustable-table.forge.js +2 -2
  119. package/examples/furniture/bathroom.forge.js +11 -11
  120. package/examples/furniture/chair.forge.js +1 -1
  121. package/examples/generative/crystal-growth.forge.js +2 -2
  122. package/examples/generative/frost-spires.forge.js +3 -3
  123. package/examples/generative/golden-spiral-tower.forge.js +3 -3
  124. package/examples/mechanical/3d-printer.forge.js +28 -28
  125. package/examples/mechanical/5-finger-robot-hand.forge.js +15 -15
  126. package/examples/mechanical/airplane-propeller.forge.js +2 -2
  127. package/examples/mechanical/fillet-enclosure.forge.js +1 -1
  128. package/examples/mechanical/headphone-hanger-v2.forge.js +2 -2
  129. package/examples/mechanical/robot_hand.forge.js +15 -15
  130. package/examples/mechanical/robot_hand_2.forge.js +9 -9
  131. package/examples/products/bottle.forge.js +1 -1
  132. package/examples/products/chess-set.forge.js +19 -19
  133. package/examples/products/classical-piano.forge.js +11 -11
  134. package/examples/products/clock.forge.js +12 -12
  135. package/examples/products/iphone.forge.js +8 -8
  136. package/examples/products/laptop.forge.js +15 -15
  137. package/examples/products/liquid-soap-dispenser.forge.js +18 -18
  138. package/examples/products/origami-fish.forge.js +8 -6
  139. package/examples/products/spiderman-cake.forge.js +4 -4
  140. package/examples/toolbox/bolted-joint.forge.js +2 -2
  141. package/package.json +7 -4
  142. package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
  143. package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
  144. package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
  145. package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
  146. package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
  147. package/dist/assets/index-1CYp3zUp.js +0 -1455
  148. package/dist/docs-raw/CLI.md +0 -865
  149. package/dist-skill/docs/API/API.md +0 -1666
  150. package/dist-skill/docs/API/README.md +0 -37
  151. package/dist-skill/docs/API/assembly/assembly.md +0 -617
  152. package/dist-skill/docs/API/core/edge-queries.md +0 -130
  153. package/dist-skill/docs/API/core/parameters.md +0 -122
  154. package/dist-skill/docs/API/core/reserved-terms.md +0 -137
  155. package/dist-skill/docs/API/core/sdf.md +0 -326
  156. package/dist-skill/docs/API/core/skill-cli.md +0 -194
  157. package/dist-skill/docs/API/core/skill-guide.md +0 -205
  158. package/dist-skill/docs/API/core/specs.md +0 -186
  159. package/dist-skill/docs/API/core/topology.md +0 -372
  160. package/dist-skill/docs/API/entities.md +0 -268
  161. package/dist-skill/docs/API/output/bom.md +0 -58
  162. package/dist-skill/docs/API/output/brep-export.md +0 -87
  163. package/dist-skill/docs/API/output/dimensions.md +0 -67
  164. package/dist-skill/docs/API/output/export.md +0 -110
  165. package/dist-skill/docs/API/output/gcode.md +0 -195
  166. package/dist-skill/docs/API/runtime/viewport.md +0 -420
  167. package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
  168. package/dist-skill/docs/API/sketch/anchor.md +0 -37
  169. package/dist-skill/docs/API/sketch/booleans.md +0 -91
  170. package/dist-skill/docs/API/sketch/core.md +0 -73
  171. package/dist-skill/docs/API/sketch/extrude.md +0 -62
  172. package/dist-skill/docs/API/sketch/on-face.md +0 -104
  173. package/dist-skill/docs/API/sketch/operations.md +0 -78
  174. package/dist-skill/docs/API/sketch/path.md +0 -75
  175. package/dist-skill/docs/API/sketch/primitives.md +0 -146
  176. package/dist-skill/docs/API/sketch/regions.md +0 -80
  177. package/dist-skill/docs/API/sketch/text.md +0 -108
  178. package/dist-skill/docs/API/sketch/transforms.md +0 -65
  179. package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
  180. package/dist-skill/docs/CLI.md +0 -865
  181. package/dist-skill/docs/INDEX.md +0 -94
  182. package/dist-skill/docs/RELEASING.md +0 -55
  183. package/dist-skill/docs/cli-monetization.md +0 -111
  184. package/dist-skill/docs/deployment.md +0 -281
  185. package/dist-skill/docs/generated/concepts.md +0 -2112
  186. package/dist-skill/docs/internals/shape-from-slices.md +0 -152
  187. package/dist-skill/docs/platform/admin.md +0 -45
  188. package/dist-skill/docs/platform/architecture.md +0 -79
  189. package/dist-skill/docs/platform/auth.md +0 -110
  190. package/dist-skill/docs/platform/email.md +0 -67
  191. package/dist-skill/docs/platform/projects.md +0 -111
  192. package/dist-skill/docs/platform/sharing.md +0 -90
  193. package/dist-skill/docs/runbook.md +0 -345
@@ -0,0 +1,50 @@
1
+ ---
2
+ skill-group: toolbox
3
+ skill-order: 100
4
+ ---
5
+
6
+ # Part Library
7
+
8
+ Pre-built fasteners, gears, pipes, structural profiles, and utility shapes. Access via `lib.*`.
9
+
10
+ ## Contents
11
+
12
+ - [lib](#lib)
13
+
14
+ ---
15
+
16
+ ## Constants
17
+
18
+ ### `lib`
19
+
20
+ Pre-built parametric parts available in user scripts as `lib.*`. **Details** Every key in this object becomes a method on the `lib` namespace exposed to `.forge.js` scripts. The catalog includes: **Fasteners:** `bolt`, `nut`, `washer`, `fastenerSet`, `fastenerHole`, `boltHole`, `counterbore`, `hexNut`, `holePattern` **Structure:** `tube`, `pipe`, `bracket`, `pipeRoute`, `elbow`, `tSlotProfile`, `tSlotExtrusion`, `profile2020BSlot6Profile`, `profile2020BSlot6` **Threads:** `thread` **Gears:** `spurGear`, `bevelGear`, `faceGear`, `sideGear`, `ringGear`, `rackGear`, `gearPair`, `bevelGearPair`, `faceGearPair`, `sideGearPair` **Utilities:** `explode` Extend this by adding new entries here and registering the corresponding runner binding in `runner.ts`. Sizes outside the supported ranges will throw at runtime with a descriptive error.
21
+
22
+ - `boltHole(diameter: number, depth: number): Shape` — Simple cylindrical through-hole cutter centered on Z=0. Subtract the result from a part to produce a plain cylindrical clearance hole. For ISO metric sizes with fit classes and counterbore/countersink, use {
23
+ - `fastenerHole(opts: FastenerHoleOptions): Shape` — ISO metric fastener hole cutter with optional counterbore or countersink. **Details** Returns a cutter shape (subtract from a solid to produce the hole). Sizes outside M2–M10 will throw. Extend `METRIC_HOLE_TABLE` in this file to add new sizes. **Example** ```ts const plate = box(60, 40, 8, true) .subtract(lib.fastenerHole({ size: 'M5', fit: 'normal', depth: 8 }) .translate(15, 10, 4)); ```
24
+ - `counterbore(holeDia: number, boreDia: number, boreDepth: number, totalDepth: number): Shape` — Counterbore hole cutter — through-hole with a wider cylindrical recess at the top. Use for socket-head cap screws that must sit flush. Subtract from a solid. For ISO metric sizing and fit classes, prefer {
25
+ - `tube(outerX: number, outerY: number, outerZ: number, wall: number): Shape` — Rectangular hollow tube (thin-wall box section). Both the outer and inner boxes are centered on the XY plane with their base at Z=0.
26
+ - `pipe(height: number, outerRadius: number, wall: number, segments?: number): Shape` — Hollow cylindrical pipe. Centered on the XY plane, extending upward along +Z from z=0 to z=height. For complex routed pipe geometry, see `lib.pipeRoute`.
27
+ - `hexNut(acrossFlats: number, height: number, holeDia: number): Shape` — Generic hex nut with a cylindrical bore. Constructed via intersection of three rotated rectangular slabs, then a bore is subtracted. Centered at origin, height along Z. For standard ISO metric nuts by thread size, use `lib.nut` instead.
28
+ - `bracket(width: number, height: number, depth: number, thick: number, holeDia?: number): Shape` — L-shaped mounting bracket with optional through-holes. Produces a right-angle bracket: a horizontal base plate and a vertical wall. Both legs share `width`. Optional holes are drilled through the base (along Z) and the wall (along Y).
29
+ - `holePattern(rows: number, cols: number, spacingX: number, spacingY: number, holeDia: number, depth: number): Shape` — Rectangular grid of cylindrical hole cutters. Returns the union of `rows × cols` cylinders laid out on a regular grid. Subtract from a solid to produce the full pattern. **Example** ```ts const pattern = lib.holePattern(3, 4, 20, 20, 4, 10); const panel = box(80, 70, 10, true).subtract(pattern.translate(-30, -30, 5)); ```
30
+ - `thread(diameter: number, pitch: number, length: number, options?: { depth?: number; segments?: number; }): Shape` — External helical thread — clean mesh, no SDF grid artifacts. **Details** Builds a cross-section with a single trapezoidal tooth from the root radius out to the crest radius, then twist-extrudes it so the tooth traces a helix. Manifold's extrude+twist produces structured quad-based geometry that follows the thread profile cleanly. Returns a threaded cylinder along +Z from z=0 to z=length. **Example** ```ts const t = lib.thread(5, 0.8, 12); // M5 × 0.8 pitch, 12 mm long ```
31
+ - `bolt(diameter: number, length: number, options?: { ... }): Shape` — ISO-style hex bolt with real helical threads. **Details** The hex head sits from z=0 up to z=headHeight. The shaft extends downward along −Z by `length` mm. An unthreaded shank section is included when `threadLength < length`. Default proportions follow ISO 4762 loosely: pitch ≈ 0.15×diameter, head height ≈ 0.65×diameter, across-flats ≈ 1.6×diameter. For standard M-size bolts pre-configured for a complete joint, use { **Example** ```ts const b = lib.bolt(5, 20); // M5 × 20 mm ```
32
+ - `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 ```
33
+ - `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 ```
34
+ - `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, true) .subtract(hw.clearanceHole.translate(15, 10, 0)); const botPlate = box(60, 40, 8, true).translate(0, 0, -16) .subtract(hw.tappedHole.translate(15, 10, -8)); return [ { name: 'Top Plate', shape: topPlate }, { name: 'Bot Plate', shape: botPlate }, { name: 'Bolt', shape: hw.bolt.translate(15, 10, 4) }, { name: 'Nut', shape: hw.nut.translate(15, 10, -19) }, ]; ```
35
+ - `pipeRoute(points: [ number` — Route a pipe (solid or hollow) through 3D waypoints with smooth bends. Each interior waypoint gets a torus-section bend. Straight segments connect them. Returns a single unioned Shape.
36
+ - `elbow(pipeRadius: number, bendRadius: number, angle?: number | { ... }, options?: { ... }): Shape` — Pipe elbow — a curved pipe section (torus arc) for connecting two pipe directions. By default creates a bend in the XZ plane: incoming along +Z, outgoing rotated by `angle`. The bend starts at the origin, curving away from it.
37
+ - `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.
38
+ - `tSlotExtrusion(length: number, options?: TSlotExtrusionOptions): Shape` — Build a T-slot extrusion from the generated 2D profile. Extrudes along +Z by default.
39
+ - `profile2020BSlot6Profile(options?: Profile2020BSlot6ProfileOptions): Sketch` — Accurate-ish 2D profile for 20x20 B-type slot 6. Returns a drawing-ready Sketch centered at origin.
40
+ - `profile2020BSlot6(length: number, options?: Profile2020BSlot6Options): Shape` — 20x20 B-type slot 6 extrusion with profile-accurate defaults. Pass option overrides if your supplier's profile differs slightly.
41
+ - `spurGear(options: SpurGearOptions): Shape` — Involute external spur gear with optional center bore. Specify module, teeth, faceWidth as required parameters. Optional tuning includes pressureAngleDeg (default 20), backlash, clearance, addendum, dedendum, boreDiameter, and segmentsPerTooth (default 10).
42
+ - `bevelGear(options: BevelGearOptions): Shape` — Conical bevel gear generated from a tapered involute extrusion. Specify pitchAngleDeg directly or derive it from mateTeeth + shaftAngleDeg.
43
+ - `faceGear(options: FaceGearOptions): Shape` — Face gear (crown style) where teeth are on one face (top or bottom) instead of the outer rim. Uses the same involute tooth sizing as spurGear, then projects the tooth band axially from one side. Alias for sideGear (which is kept for backward compatibility).
44
+ - `sideGear(options: SideGearOptions): Shape` — Crown/face style gear where the teeth project from one side of the disk instead of the outer cylindrical rim.
45
+ - `ringGear(options: RingGearOptions): Shape` — Internal ring gear with involute-derived tooth spaces. Specify rimWidth or outerDiameter for the annular body.
46
+ - `rackGear(options: RackGearOptions): Shape` — Linear rack gear with pressure-angle flanks. Use with spurGear for rack-and-pinion mechanisms.
47
+ - `gearPair(options: GearPairOptions): GearPairResult` — Build or validate a spur-gear pair and return ratio, backlash, and mesh diagnostics. Accepts either shapes from spurGear() or analytical specs for each member. When place is true (default), the gear is auto-positioned at the correct center distance.
48
+ - `bevelGearPair(options: BevelGearPairOptions): BevelGearPairResult` — Build or validate a bevel-gear pair and return ratio diagnostics plus recommended joint placement vectors.
49
+ - `faceGearPair(options: FaceGearPairOptions): FaceGearPairResult` — Build or validate a perpendicular pair between a face gear and a vertical spur gear.
50
+ - `sideGearPair(options: SideGearPairOptions): SideGearPairResult` — Pair helper for side (crown/face) gear + perpendicular "vertical" spur gear. Auto-placement rotates the spur around +Y and positions it to mesh at the side tooth band.
@@ -0,0 +1,234 @@
1
+ ---
2
+ skill-group: output
3
+ skill-order: 100
4
+ ---
5
+
6
+ # Output & Annotations
7
+
8
+ Dimensions, BOM entries, verification checks, and sketch export.
9
+
10
+ ## Contents
11
+
12
+ - [Annotations & Output](#annotations-output) — `bom`, `robotExport`, `dim`, `dimLine`
13
+ - [Sketch Export](#sketch-export) — `sketchToDxf`, `sketchToSvg`
14
+
15
+ ## Functions
16
+
17
+ ### Annotations & Output
18
+
19
+ #### `bom()` — Register a Bill of Materials entry for report export.
20
+
21
+ BOM entries are accumulated during script execution and exported alongside the model in report views. Rows are grouped by normalized `description + unit`. Pass an explicit `key` to force multiple descriptions to collapse into a single line item.
22
+
23
+ - `quantity` must be a finite number `>= 0`. A quantity of `0` is silently ignored (useful for conditional scripting with [`param()`](/docs/core#param)-driven counts).
24
+ - `unit` defaults to `"pieces"` when omitted or empty.
25
+ - The assembly `solved.bom()` / `solved.bomCsv()` API is separate and covers per-part assembly metadata; this function is for free-form purchased-item annotation.
26
+
27
+ ```ts
28
+ const tubeLen = param("Tube Length", 1200, { min: 300, max: 4000, unit: "mm" });
29
+ const boltCount = param("Bolt Count", 16, { min: 0, max: 200, integer: true });
30
+
31
+ bom(tubeLen, "iron tube 30 x 20", { unit: "mm" });
32
+ bom(boltCount, "M4 bolt, 16 mm length");
33
+ bom(4, "rubber foot", { key: "foot-rubber" }); // explicit aggregation key
34
+
35
+ // Structured metadata for richer reports:
36
+ bom(tubeLen, "rectangular steel tube", {
37
+ unit: "mm",
38
+ material: "steel",
39
+ section: [30, 20],
40
+ wall: 3,
41
+ });
42
+ ```
43
+
44
+ ```ts
45
+ bom(quantity: number, description: string, opts?: BomOpts): void
46
+ ```
47
+
48
+ **`BomOpts`**
49
+
50
+ | Option | Type | Description |
51
+ |--------|------|-------------|
52
+ | `unit?` | `string` | Quantity unit label, e.g. "mm", "pieces", "kg". Default: "pieces" |
53
+ | `key?` | `string` | Optional explicit grouping key used during report aggregation. |
54
+ | `material?` | `string` | Material name, e.g. "steel", "birch plywood", "nylon" |
55
+ | `dimensions?` | `number[]` | Overall dimensions `[width, height]` or `[width, height, thickness]` in the entry's unit |
56
+ | `section?` | `number[]` | Cross-section dimensions `[w, h]` for tubes and profiles |
57
+ | `wall?` | `number` | Wall thickness for hollow sections (mm) |
58
+ | `diameter?` | `number` | Diameter for round stock, bolts, dowels (mm) |
59
+ | `length?` | `number` | Length for fasteners (mm) |
60
+ | `process?` | `string` | Manufacturing process, e.g. "laser cut", "CNC", "welded" |
61
+ | `notes?` | `string` | Free-form notes |
62
+ | `grain?` | `string` | Wood grain direction, e.g. "long", "cross" |
63
+
64
+ #### `robotExport()` — Declare that this script should export the assembly as a SDF/URDF robot package.
65
+
66
+ Call `robotExport()` alongside your assembly definition. The CLI commands `forgecad export sdf` and `forgecad export urdf` pick up the declaration and produce a robot package with:
67
+
68
+ - Mesh-based inertia tensors (full 6-component, not bounding-box approximations)
69
+ - Separate collision meshes (convex hull by default — ~50–80% smaller)
70
+ - Joint mimic elements derived from `addJointCoupling` / `addGearCoupling`
71
+
72
+ **Collision mesh modes** (set per-link via `links["PartName"].collision`):
73
+
74
+ | Mode | Description | Default | |------|-------------|---------| | `'convex'` | Convex hull (separate `_collision.stl`) | Yes | | `'box'` | AABB primitive — fastest physics | | | `'visual'` | Same mesh as visual — exact but slow | | | `'none'` | No collision geometry | |
75
+
76
+ **Unit conventions:**
77
+
78
+ - Revolute `velocity` is in degrees/second in Forge; exporters convert to rad/s.
79
+ - Prismatic distances are in mm in Forge; exported in meters.
80
+ - `massKg` is preferred; `densityKgM3` is used when mass is unknown.
81
+ - Couplings with multiple terms: only the primary term (largest ratio) maps to `<mimic>` — SDF/URDF support single-leader mimic only. Dropped terms emit a warning.
82
+
83
+ ```ts
84
+ const rover = assembly("Scout")
85
+ .addPart("Chassis", box(300, 220, 50, true))
86
+ .addPart("Left Wheel", cylinder(30, 60, undefined, 48, true))
87
+ .addRevolute("leftWheel", "Chassis", "Left Wheel", {
88
+ axis: [0, 1, 0],
89
+ frame: Transform.identity().translate(90, 140, 60),
90
+ effort: 20, velocity: 1080,
91
+ });
92
+
93
+ robotExport({
94
+ assembly: rover,
95
+ modelName: "Scout",
96
+ links: {
97
+ Chassis: { massKg: 10 },
98
+ "Left Wheel": { massKg: 0.8 },
99
+ },
100
+ plugins: {
101
+ diffDrive: {
102
+ leftJoints: ["leftWheel"], rightJoints: ["rightWheel"],
103
+ wheelSeparationMm: 280, wheelRadiusMm: 60,
104
+ },
105
+ },
106
+ world: { generateDemoWorld: true },
107
+ });
108
+ ```
109
+
110
+ **CLI usage**
111
+
112
+ ```bash
113
+ forgecad export sdf model.forge.js # SDF package (Gazebo/Ignition)
114
+ forgecad export urdf model.forge.js # URDF package (ROS/PyBullet/MuJoCo)
115
+ ```
116
+
117
+ ```ts
118
+ robotExport(options: RobotExportOptions): CollectedRobotExport
119
+ ```
120
+
121
+ **`RobotExportOptions`**: `assembly: Assembly`, `modelName?: string`, `state?: JointState`, `static?: boolean`, `selfCollide?: boolean`, `allowAutoDisable?: boolean`, `links?: Record<string, RobotLinkExportOptions>`, `joints?: Record<string, RobotJointExportOptions>`, `diffDrive?: RobotDiffDrivePluginOptions`, `jointStatePublisher?: RobotJointStatePublisherOptions`, `world?: RobotWorldOptions`
122
+
123
+ `RobotLinkExportOptions`: `{ massKg?: number, densityKgM3?: number, collision?: "visual" | "convex" | "box" | "none" }`
124
+
125
+ `RobotJointExportOptions`: `{ effort?: number, velocity?: number, damping?: number, friction?: number }`
126
+
127
+ **`RobotDiffDrivePluginOptions`**: `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`
128
+
129
+ `RobotJointStatePublisherOptions`: `{ enabled?: boolean, joints?: string[], topic?: string, updateRate?: number }`
130
+
131
+ `RobotWorldOptions`: `{ name?: string, generateDemoWorld?: boolean, spawnPose?: RobotPose6, keyboardTeleop?: RobotWorldKeyboardTeleopOptions }`
132
+
133
+ `RobotWorldKeyboardTeleopOptions`: `{ enabled?: boolean, linearStep?: number, angularStep?: number }`
134
+
135
+ **`CollectedRobotExport`**: `modelName: string`, `assembly: AssemblyDefinition`, `state: JointState`, `static: boolean`, `selfCollide: boolean`, `allowAutoDisable: boolean`, `links: Record<string, RobotLinkExportOptions>`, `joints: Record<string, RobotJointExportOptions>`, `diffDrive?: RobotDiffDrivePluginOptions`, `jointStatePublisher?: RobotJointStatePublisherOptions`, `world: RobotWorldOptions | null`
136
+
137
+ `AssemblyDefinition`: `{ name: string, parts: AssemblyPartDef[], joints: AssemblyJointDef[], jointCouplings: AssemblyJointCouplingDef[] }`
138
+
139
+ `AssemblyPartDef`: `{ name: string, part: AssemblyPart, base: Transform, metadata?: PartMetadata }`
140
+
141
+ **`PartMetadata`**: `material?: string`, `process?: string`, `tolerance?: string`, `qty?: number`, `notes?: string`, `densityKgM3?: number`, `massKg?: number`
142
+
143
+ **`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`
144
+
145
+ `AssemblyJointCouplingDef`: `{ joint: string, terms: JointCouplingTermRecord[], offset: number }`
146
+
147
+ `JointCouplingTermRecord`: `{ joint: string, ratio: number }`
148
+
149
+ #### `dim()` — Add a dimension annotation between two points.
150
+
151
+ Dimension annotations are purely visual callouts rendered in the viewport and report export. They do not affect geometry or constrain the model.
152
+
153
+ Point arguments accept 2D tuples `[x, y]`, 3D tuples `[x, y, z]`, or [`Point2D`](/docs/sketch#point2d) objects (Z is treated as 0 for 2D inputs).
154
+
155
+ **Ownership Rules (Report Pages)**
156
+
157
+ - `currentComponent: true` — deterministic ownership by the calling import instance. Use when authoring reusable imported parts.
158
+ - `component: "Part Name"` — route dimension to another named returned object.
159
+ - Multiple owners: dimension is shared and appears on the assembly overview page.
160
+ - No ownership set: report export infers ownership via endpoint-in-bbox.
161
+
162
+ ```ts
163
+ dim([-w / 2, 0, 0], [w / 2, 0, 0], { label: "Width" });
164
+ dim([0, 0, -h / 2], [0, 0, h / 2], { label: "Height", offset: 14 });
165
+ dim([0, 0, 0], [100, 0, 0], { component: "Base", color: "#00AAFF" });
166
+ ```
167
+
168
+ `component` (string or string[] — report ownership), `currentComponent` (boolean)
169
+
170
+ ```ts
171
+ dim(from: PointArg, to: PointArg, opts?: DimOpts): void
172
+ ```
173
+
174
+ `DimOpts`: `{ offset?: number, label?: string, color?: string, component?: string | string[], currentComponent?: boolean }`
175
+
176
+ #### `dimLine()` — Add a dimension annotation along a [`Line2D`](/docs/sketch#line2d).
177
+
178
+ Convenience wrapper around { points from a constrained-sketch [`Line2D`](/docs/sketch#line2d) entity. All `opts` are forwarded unchanged.
179
+
180
+ ```ts
181
+ const a = point(0, 0);
182
+ const b = point(100, 0);
183
+ dimLine(line(a, b), { label: "Span", offset: -8 });
184
+ ```
185
+
186
+ ```ts
187
+ dimLine(l: Line2D, opts?: DimOpts): void
188
+ ```
189
+
190
+ ### Sketch Export
191
+
192
+ #### `sketchToDxf()` — Export a 2D sketch as a DXF string (R12/AC1009 — maximally compatible).
193
+
194
+ For regular sketches, each polygon loop becomes a closed `LWPOLYLINE`. For constrained sketches, exports raw `LINE`, `CIRCLE`, and `ARC` entities from the constraint edge geometry, which preserves internal/shared edges that `toPolygons()` would merge away.
195
+
196
+ The R12 format is chosen for maximum compatibility with CAM tools, laser-cutter software, and older CAD readers.
197
+
198
+ ```ts
199
+ const s = rect(100, 60);
200
+ const dxf = sketchToDxf(s, { layer: 'cut' });
201
+ ```
202
+
203
+ ```ts
204
+ sketchToDxf(sketch: Sketch, options?: SketchDxfOptions): string
205
+ ```
206
+
207
+ **`SketchDxfOptions`**
208
+ - `layer?: string` — DXF layer name. Default: "0"
209
+ - `colorIndex?: number` — DXF color index (1–255, AutoCAD ACI). Default: 7 (white/black)
210
+
211
+ #### `sketchToSvg()` — Export a 2D sketch as an SVG string.
212
+
213
+ For regular sketches, exports filled polygon regions. For constrained sketches, exports raw edge geometry (LINE, ARC, CIRCLE) which preserves internal/shared edges that `toPolygons()` would merge away.
214
+
215
+ The SVG uses the sketch's native coordinate system (Y-up) with a CSS transform that flips Y so the output renders correctly in SVG's Y-down space. Coordinates are in sketch units (typically mm).
216
+
217
+ ```ts
218
+ const s = rect(100, 60);
219
+ const svg = sketchToSvg(s, { stroke: '#333', strokeWidth: 0.8 });
220
+ ```
221
+
222
+ ```ts
223
+ sketchToSvg(sketch: Sketch, options?: SketchSvgOptions): string
224
+ ```
225
+
226
+ **`SketchSvgOptions`**
227
+
228
+ | Option | Type | Description |
229
+ |--------|------|-------------|
230
+ | `stroke?` | `string` | Stroke color. Default: "black" |
231
+ | `strokeWidth?` | `number` | Stroke width in sketch units. Default: 0.5 |
232
+ | `fill?` | `string` | Fill color. Default: "none" |
233
+ | `padding?` | `number` | Padding around the sketch bounding box in sketch units. Default: 2 |
234
+ | `pixelsPerUnit?` | `number` | If set, scale so 1 sketch-unit = this many px. Otherwise auto-fit. |