forgecad 0.9.4 → 0.9.6

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 (90) hide show
  1. package/dist/assets/{AdminPage-jwoEgwE_.js → AdminPage-Da6hhpJx.js} +1 -1
  2. package/dist/assets/{BlogPage-Ck7g3ue2.js → BlogPage-Bl_sKeWb.js} +1 -1
  3. package/dist/assets/{DocsPage-9WaRC14b.js → DocsPage-Blz3Tp4j.js} +1 -6
  4. package/dist/assets/EditorApp-CuiPbtn5.js +12754 -0
  5. package/dist/assets/{EmbedViewer-37_PfMwv.js → EmbedViewer-BFG6-Ufm.js} +2 -2
  6. package/dist/assets/{LandingPageProofDriven-CO8WL0CY.js → LandingPageProofDriven-DB9fQd5P.js} +1 -1
  7. package/dist/assets/{PricingPage-DADKGuOa.js → PricingPage-BMxYT_F0.js} +1 -1
  8. package/dist/assets/{SettingsPage-DKKI4W49.js → SettingsPage-VVQNrCAg.js} +1 -1
  9. package/dist/assets/{app-CwI02pTA.js → app-Dl9ymBWC.js} +355 -36
  10. package/dist/assets/cli/{render-Kw5hLEcL.js → render-CFtwKCCY.js} +203 -862
  11. package/dist/assets/{sectionPlaneMath-C8N0w8o3.js → distance-BEC2RjJi.js} +4150 -801
  12. package/dist/assets/{evalWorker-D6ub3kfS.js → evalWorker-CRvbzTXm.js} +2611 -528
  13. package/dist/assets/{manifold-CwDdMKyc.js → manifold-B9QSr-qP.js} +1 -1
  14. package/dist/assets/{manifold-DTvmxSDf.js → manifold-DpBXFS2K.js} +1 -1
  15. package/dist/assets/{manifold-lru0jwVw.js → manifold-DzZ4VRPs.js} +2 -2
  16. package/dist/assets/{renderSceneState-tvtNKNRi.js → renderSceneState-BuAXF2jh.js} +1 -1
  17. package/dist/assets/{reportWorker-DeqktDGt.js → reportWorker-BNWEnRg1.js} +2606 -525
  18. package/dist/cli/render.html +1 -1
  19. package/dist/docs/index.html +2 -2
  20. package/dist/docs-raw/AI/usage.md +0 -1
  21. package/dist/docs-raw/API/core/concepts.md +11 -1
  22. package/dist/docs-raw/CLI.md +64 -13
  23. package/dist/docs-raw/beta-operations.md +4 -0
  24. package/dist/docs-raw/deployment.md +38 -23
  25. package/dist/docs-raw/generated/assembly.md +8 -3
  26. package/dist/docs-raw/generated/concepts.md +126 -46
  27. package/dist/docs-raw/generated/core.md +97 -47
  28. package/dist/docs-raw/generated/curves.md +113 -595
  29. package/dist/docs-raw/generated/lib.md +40 -3
  30. package/dist/docs-raw/generated/output.md +6 -1
  31. package/dist/docs-raw/generated/sdf.md +50 -4
  32. package/dist/docs-raw/generated/sketch.md +9 -1
  33. package/dist/docs-raw/generated/viewport.md +1 -9
  34. package/dist/docs-raw/guides/inspection-bundles.md +40 -9
  35. package/dist/docs-raw/runbook.md +3 -3
  36. package/dist/docs-raw/skills/forgecad-blockout-model.md +1 -0
  37. package/dist/docs-raw/skills/forgecad-image-replicator.md +3 -1
  38. package/dist/docs-raw/skills/forgecad-make-a-model.md +48 -4
  39. package/dist/docs-raw/skills/forgecad-render-inspect.md +3 -1
  40. package/dist/docs-raw/skills/forgecad-visual-spec.md +2 -0
  41. package/dist/docs-raw/skills/forgecad.md +2 -1
  42. package/dist/docs-raw/skills/index.md +0 -1
  43. package/dist/index.html +1 -1
  44. package/dist/sitemap.xml +6 -6
  45. package/dist-cli/blender/render.py +43 -8
  46. package/dist-cli/forgecad.js +5729 -2015
  47. package/dist-cli/forgecad.js.map +1 -1
  48. package/dist-skill/CONTEXT.md +372 -667
  49. package/dist-skill/SKILL-dev.md +2 -1
  50. package/dist-skill/SKILL.md +2 -1
  51. package/dist-skill/docs/API/core/concepts.md +11 -1
  52. package/dist-skill/docs/CLI.md +64 -13
  53. package/dist-skill/docs/generated/assembly.md +8 -3
  54. package/dist-skill/docs/generated/core.md +97 -47
  55. package/dist-skill/docs/generated/curves.md +113 -595
  56. package/dist-skill/docs/generated/lib.md +40 -3
  57. package/dist-skill/docs/generated/output.md +6 -1
  58. package/dist-skill/docs/generated/sdf.md +50 -4
  59. package/dist-skill/docs/generated/sketch.md +9 -1
  60. package/dist-skill/docs/generated/viewport.md +1 -9
  61. package/dist-skill/docs/guides/inspection-bundles.md +40 -9
  62. package/dist-skill/docs-dev/API/core/concepts.md +11 -1
  63. package/dist-skill/docs-dev/CLI.md +64 -13
  64. package/dist-skill/docs-dev/generated/assembly.md +8 -3
  65. package/dist-skill/docs-dev/generated/core.md +97 -47
  66. package/dist-skill/docs-dev/generated/curves.md +113 -595
  67. package/dist-skill/docs-dev/generated/lib.md +40 -3
  68. package/dist-skill/docs-dev/generated/output.md +6 -1
  69. package/dist-skill/docs-dev/generated/sdf.md +50 -4
  70. package/dist-skill/docs-dev/generated/sketch.md +9 -1
  71. package/dist-skill/docs-dev/generated/viewport.md +1 -9
  72. package/dist-skill/docs-dev/guides/inspection-bundles.md +40 -9
  73. package/dist-skill/library/README.md +0 -1
  74. package/dist-skill/library/forgecad-blockout-model/SKILL.md +1 -0
  75. package/dist-skill/library/forgecad-image-replicator/SKILL.md +3 -1
  76. package/dist-skill/library/forgecad-make-a-model/SKILL.md +48 -4
  77. package/dist-skill/library/forgecad-render-inspect/SKILL.md +3 -1
  78. package/dist-skill/library/forgecad-visual-spec/SKILL.md +2 -0
  79. package/examples/api/drive-wheel-regions.forge.js +43 -0
  80. package/examples/api/guided-loft-olive-oil-bottle.forge.js +135 -0
  81. package/examples/api/sdf-circular-array-knurling.forge.js +19 -0
  82. package/examples/api/sdf-pattern2d-ceramic-ripple-set.forge.js +83 -0
  83. package/examples/api/sdf-pattern2d-grip-tread.forge.js +72 -0
  84. package/examples/api/sdf-pattern2d-orbital-jewelry.forge.js +62 -0
  85. package/examples/api/sdf-surface-basket-weave.forge.js +67 -0
  86. package/examples/api/sector-gear-body.forge.js +34 -0
  87. package/package.json +20 -2
  88. package/dist/assets/EditorApp-Dja2jMmW.js +0 -12509
  89. package/dist/docs-raw/skills/forgecad-api-dogfood.md +0 -130
  90. package/dist-skill/library/forgecad-api-dogfood/SKILL.md +0 -125
@@ -4,10 +4,10 @@ Every public API function belongs to one of 16 fundamental concepts. This docume
4
4
 
5
5
  ## Concepts
6
6
 
7
- - **[C1: Primitive Construction](#c1-primitive-construction)** — Create geometry from parameters — no input geometry required. *(74 functions)*
7
+ - **[C1: Primitive Construction](#c1-primitive-construction)** — Create geometry from parameters — no input geometry required. *(76 functions)*
8
8
  - **[C2: Boolean Combination](#c2-boolean-combination)** — Combine same-dimension geometry using CSG set operations. *(6 functions)*
9
9
  - **[C3: Rigid Transform](#c3-rigid-transform)** — Reposition or reorient geometry without changing its shape. *(3 functions)*
10
- - **[C4: Dimensional Promotion](#c4-dimensional-promotion)** — Convert a 2D profile into a 3D solid (extrude, revolve, loft, sweep). *(30 functions)*
10
+ - **[C4: Dimensional Promotion](#c4-dimensional-promotion)** — Convert a 2D profile into a 3D solid (extrude, revolve, loft, sweep). *(40 functions)*
11
11
  - **[C5: Topology Query](#c5-topology-query)** — Select or inspect named faces and edges on a shape. *(3 functions)*
12
12
  - **[C6: Edge Feature](#c6-edge-feature)** — Modify edges of a solid — fillets, chamfers, draft, offset. *(7 functions)*
13
13
  - **[C7: Pattern Replication](#c7-pattern-replication)** — Duplicate geometry in regular arrangements (linear, circular, mirror). *(6 functions)*
@@ -259,6 +259,12 @@ sdf.basketWeave(options?: BasketWeaveOptions): SurfacePattern
259
259
  - `threadWidth?: number` — Thread width in mm. Default: 1.5
260
260
  - `depth?: number` — Thread protrusion depth in mm. Default: 0.8
261
261
 
262
+ #### `sdf.pattern2d()` — Create typed, composable 2D surface patterns for `.surfaceDisplace()`.
263
+
264
+ ```ts
265
+ sdf.pattern2d(): Pattern2DBuilder
266
+ ```
267
+
262
268
  #### `sdf.twist()` — Twist an SDF shape around the Z axis.
263
269
 
264
270
  ```ts
@@ -277,6 +283,12 @@ sdf.bend(shape: SdfShape, radius: number): SdfShape
277
283
  sdf.repeat(shape: SdfShape, spacing: Vec3, count?: Vec3): SdfShape
278
284
  ```
279
285
 
286
+ #### `sdf.circularArray()` — Arrange an SDF shape in a circular array around the Z axis with O(1) folded-domain evaluation.
287
+
288
+ ```ts
289
+ sdf.circularArray(shape: SdfShape, count: number, offset?: number): SdfShape
290
+ ```
291
+
280
292
  #### `sdf.SurfacePattern()` — A 2D surface pattern — a heightmap function for use with `.surfaceDisplace()`.
281
293
 
282
294
  ```ts
@@ -362,7 +374,6 @@ sdf.Sculpt: { sphere: (radius: number) => SdfShape; box: (x: number, y: number,
362
374
  | `behavior?` | `"opt-in" \| "auto"` | Whether the viewer should offer or auto-open the journey. First slice supports opt-in. |
363
375
  | `steps` | `SceneJourneyStepConfig[]` | Ordered journey spine. Branches can be added later without changing this core contract. |
364
376
  | `valid?` | `boolean` | True unless any journey or step diagnostic has level "error". |
365
- | `diagnostics?` | `SceneJourneyDiagnostic[]` | Whole-journey diagnostics, including unresolved startsAt and step target diagnostics. |
366
377
 
367
378
  **`SceneJourneyStepConfig`**
368
379
 
@@ -375,9 +386,6 @@ sdf.Sculpt: { sphere: (radius: number) => SdfShape; box: (x: number, y: number,
375
386
  | `camera?` | `SceneViewCameraConfig` | Optional explicit camera for this step. When omitted, the viewer fits `focus`. |
376
387
  | `resolvedFocusId?` | `string \| null` | Resolved object id after script execution, when `focus` matched exactly one object. |
377
388
  | `resolvedFocusPath?` | `string \| null` | Resolved object tree path or name after script execution. |
378
- | `diagnostics?` | `SceneJourneyDiagnostic[]` | Resolution diagnostics for this step. |
379
-
380
- `SceneJourneyDiagnostic`: `{ level: SceneJourneyDiagnosticLevel, message: string, stepId?: string, suggestions?: string[] }`
381
389
 
382
390
  **`SceneLightConfig`**
383
391
 
@@ -994,6 +1002,87 @@ composeChain(...steps: TransformInput[]): Transform
994
1002
 
995
1003
  Convert a 2D profile into a 3D solid (extrude, revolve, loft, sweep).
996
1004
 
1005
+ #### `Loft.station()` — Create a loft station from a 2D profile and an axis position.
1006
+
1007
+ ```ts
1008
+ Loft.station(profile: Sketch, position: number): LoftStation
1009
+ ```
1010
+
1011
+ `LoftStation`: `{ profile: Sketch, position: number }`
1012
+
1013
+ #### `Loft.leftRail()` — Create a guide rail that constrains the section-local negative-X side.
1014
+
1015
+ ```ts
1016
+ Loft.leftRail(path: LoftGuideRailPath): LoftGuideRail
1017
+ ```
1018
+
1019
+ `LoftGuideRail`: `{ side: LoftGuideRailSide, path: LoftGuideRailPath }`
1020
+
1021
+ #### `Loft.rightRail()` — Create a guide rail that constrains the section-local positive-X side.
1022
+
1023
+ ```ts
1024
+ Loft.rightRail(path: LoftGuideRailPath): LoftGuideRail
1025
+ ```
1026
+
1027
+ #### `Loft.frontRail()` — Create a guide rail that constrains the section-local positive-Y side.
1028
+
1029
+ ```ts
1030
+ Loft.frontRail(path: LoftGuideRailPath): LoftGuideRail
1031
+ ```
1032
+
1033
+ #### `Loft.backRail()` — Create a guide rail that constrains the section-local negative-Y side.
1034
+
1035
+ ```ts
1036
+ Loft.backRail(path: LoftGuideRailPath): LoftGuideRail
1037
+ ```
1038
+
1039
+ #### `Loft.centerRail()` — Create a guide rail that moves section centers along the loft.
1040
+
1041
+ ```ts
1042
+ Loft.centerRail(path: LoftGuideRailPath): LoftGuideRail
1043
+ ```
1044
+
1045
+ #### `Loft.pathOnXz()` — Place a 2D guide path onto the XZ plane.
1046
+
1047
+ The path's first coordinate becomes X and its second coordinate becomes Z. Use this for left/right silhouette rails authored with `path()` or `constrainedSketch()`.
1048
+
1049
+ ```ts
1050
+ Loft.pathOnXz(path: LoftPath2D, y?: number): Vec3[]
1051
+ ```
1052
+
1053
+ #### `Loft.pathOnYz()` — Place a 2D guide path onto the YZ plane.
1054
+
1055
+ The path's first coordinate becomes Y and its second coordinate becomes Z. Use this for front/back crown rails authored with `path()` or `constrainedSketch()`.
1056
+
1057
+ ```ts
1058
+ Loft.pathOnYz(path: LoftPath2D, x?: number): Vec3[]
1059
+ ```
1060
+
1061
+ #### `Loft.pathOnXy()` — Place a 2D guide path onto the XY plane.
1062
+
1063
+ The path's first coordinate becomes X and its second coordinate becomes Y. Use this when lofting along X or Y and a rail lives in a horizontal sketch plane.
1064
+
1065
+ ```ts
1066
+ Loft.pathOnXy(path: LoftPath2D, z?: number): Vec3[]
1067
+ ```
1068
+
1069
+ #### `Loft.withGuideRails()` — Loft through profile stations while forcing generated sections to follow guide rails.
1070
+
1071
+ Stations define the cross-section family. Guide rails define the side or center paths the loft must pass through. With opposite side rails, the section is scaled to touch both rails. With one side rail, the section keeps its interpolated size unless a center rail is also present.
1072
+
1073
+ ```ts
1074
+ Loft.withGuideRails(stations: LoftStation[], rails: LoftGuideRail[], options?: LoftWithGuideRailsOptions): Shape
1075
+ ```
1076
+
1077
+ **`LoftOptions`**
1078
+ - `edgeLength?: number` — Marching-grid edge length for level-set meshing. Smaller = finer.
1079
+ - `boundsPadding?: number` — Optional extra bounds padding.
1080
+
1081
+ **`LoftWithGuideRailsOptions`** extends LoftOptions
1082
+ - `axis?: LoftAxis` — Primary station axis. Default Z.
1083
+ - `samples?: number` — Number of generated loft stations including ends. Default scales with station count.
1084
+ - `railSamples?: number` — Number of points sampled from curve-backed rails before axis interpolation. Default 64.
1085
+
997
1086
  #### `Analysis.EdgeContinuity()`
998
1087
 
999
1088
  ```ts
@@ -1059,14 +1148,6 @@ Blend.Surface(options: BlendSurfaceOptions): Shape
1059
1148
 
1060
1149
  `SurfaceMatchConstraintInput`: `{ target: EdgeRef, continuity?: SurfaceContinuity }`
1061
1150
 
1062
- #### `Blend.CornerY()` — Current implementation uses continuity-controlled edge fillets on solid edges. It does not yet provide a dedicated open-sheet or multi-patch Y-corner solver. Follow progress: https://github.com/KoStard/forgecad-private/issues/162
1063
-
1064
- ```ts
1065
- Blend.CornerY(options: BlendCornerYOptions): Shape
1066
- ```
1067
-
1068
- `BlendCornerYOptions`: `{ edges: EdgeRef[], cornerTolerance?: number, minBranchAngleDeg?: number }`
1069
-
1070
1151
  #### `Surface.Nurbs()`
1071
1152
 
1072
1153
  ```ts
@@ -1254,11 +1335,8 @@ connectEdges(edgeA: EdgeSegment, edgeB: EdgeSegment, options?: ConnectEdgesOptio
1254
1335
  | `normalA` | `Vec3` | Normal of first adjacent face. |
1255
1336
  | `normalB` | `Vec3` | Normal of second adjacent face (same as normalA for boundary edges). |
1256
1337
  | `boundary` | `boolean` | true if this is a boundary (unmatched) edge — unusual for closed solids. |
1257
- | `nativeTopology?` | `EdgeNativeTopologyRef` | Native kernel topology identity when the active backend can provide one. |
1258
1338
  | `start`, `end`, `midpoint`, `length` | | — |
1259
1339
 
1260
- `EdgeNativeTopologyRef`: `{ backend: "truck", edge: number }`
1261
-
1262
1340
  **`TransitionCurveOptions`**
1263
1341
  - `weightA?: number` — Weight for the start edge. Controls tangent magnitude at the start. - 1.0 (default): balanced transition - > 1.0: curve follows start edge longer before turning - < 1.0: curve turns sooner at the start
1264
1342
  - `weightB?: number` — Weight for the end edge. Controls tangent magnitude at the end. - 1.0 (default): balanced transition - > 1.0: curve follows end edge longer before turning - < 1.0: curve turns sooner at the end
@@ -1315,10 +1393,6 @@ Performance note: loft is significantly heavier than primitive/extrude/revolve.
1315
1393
  loft(profiles: Sketch[], heights: number[], options?: LoftOptions): Shape
1316
1394
  ```
1317
1395
 
1318
- **`LoftOptions`**
1319
- - `edgeLength?: number` — Marching-grid edge length for level-set meshing. Smaller = finer.
1320
- - `boundsPadding?: number` — Optional extra bounds padding.
1321
-
1322
1396
  #### `loftAlongSpine()` — Loft between multiple profiles positioned along an arbitrary 3D spine curve.
1323
1397
 
1324
1398
  Unlike loft() which only supports Z heights, loftAlongSpine() places each profile at a position along a 3D spine, oriented perpendicular to the spine tangent. This enables lofting along curved paths — e.g., a wing root-to-tip transition that follows a swept-back leading edge.
@@ -1495,11 +1569,8 @@ coalesceEdges(segments: EdgeSegment[], tolerance?: number): EdgeSegment[]
1495
1569
  | `normalA` | `Vec3` | Normal of first adjacent face. |
1496
1570
  | `normalB` | `Vec3` | Normal of second adjacent face (same as normalA for boundary edges). |
1497
1571
  | `boundary` | `boolean` | true if this is a boundary (unmatched) edge — unusual for closed solids. |
1498
- | `nativeTopology?` | `EdgeNativeTopologyRef` | Native kernel topology identity when the active backend can provide one. |
1499
1572
  | `start`, `end`, `midpoint`, `length` | | — |
1500
1573
 
1501
- `EdgeNativeTopologyRef`: `{ backend: "truck", edge: number }`
1502
-
1503
1574
  #### `selectEdge()` — Select the single best-matching edge from a shape.
1504
1575
 
1505
1576
  When `near` is specified, returns the edge whose midpoint is closest to that point. Otherwise returns the first matching edge in mesh order. Throws if no edges match the query — useful as a guard when you expect exactly one result.
@@ -1559,9 +1630,11 @@ selectEdges(shape: Shape, query?: EdgeQuery): EdgeSegment[]
1559
1630
 
1560
1631
  Modify edges of a solid — fillets, chamfers, draft, offset.
1561
1632
 
1562
- #### `chamfer()` — Apply chamfers (beveled edges) to one or more edges of a shape.
1633
+ #### `chamfer()` — Apply experimental chamfers (beveled edges) to one or more edges of a shape.
1634
+
1635
+ **Experimental**: chamfers are still backend-sensitive. The Manifold backend is known to produce incorrect results for some edge-finish cases, and the OCCT backend can be very slow, especially with broad edge selections. Prefer targeted edge selectors and inspect the result before treating it as production-ready geometry.
1563
1636
 
1564
- Produces a 45° bevel at the specified `size` (distance from edge). Works on edge selections from any active backend. Truck and OCCT route chamfers through native kernel operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
1637
+ 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.
1565
1638
 
1566
1639
  The `edges` parameter accepts the same options as `fillet()`: inline `EdgeQuery`, pre-selected `EdgeSegment`/`EdgeSegment[]`, or `undefined` (all sharp edges).
1567
1640
 
@@ -1595,9 +1668,11 @@ draft(myShape, 2, [0, 0, 1], 10)
1595
1668
  draft(shape: Shape, angleDeg: number, pullDirection?: [ number, number, number ], neutralPlaneOffset?: number): Shape
1596
1669
  ```
1597
1670
 
1598
- #### `fillet()` — Apply fillets (rounded edges) to one or more edges of a shape.
1671
+ #### `fillet()` — Apply experimental fillets (rounded edges) to one or more edges of a shape.
1599
1672
 
1600
- Works on edge selections from any active backend. Truck and OCCT route edge finishes through native kernel operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
1673
+ **Experimental**: fillets are still backend-sensitive. The Manifold backend is known to produce incorrect results for some edge-finish cases, and the OCCT backend can be very slow, especially with broad edge selections. Prefer targeted edge selectors and inspect the result before treating it as production-ready geometry.
1674
+
1675
+ Edge selections compile into backend operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
1601
1676
 
1602
1677
  The `edges` parameter is flexible:
1603
1678
 
@@ -2165,7 +2240,12 @@ bomToCsv(rows: BomRow[]): string
2165
2240
 
2166
2241
  **`BomRow`**: `part: string`, `qty: number`, `material?: string`, `process?: string`, `tolerance?: string`, `notes?: string`, `metadata?: PartMetadata`
2167
2242
 
2168
- **`PartMetadata`**: `material?: string`, `process?: string`, `tolerance?: string`, `qty?: number`, `notes?: string`, `densityKgM3?: number`, `massKg?: number`
2243
+ **`PartMetadata`**
2244
+
2245
+ | Option | Type | Description |
2246
+ |--------|------|-------------|
2247
+ | `tags?` | `string \| readonly string[]` | Viewport organization tags applied to scene objects produced from this part. |
2248
+ | `material?`, `process?`, `tolerance?`, `qty?`, `notes?`, `densityKgM3?`, `massKg?` | | — |
2169
2249
 
2170
2250
  #### `joint()` — Create a revolute joint that auto-generates a parameter slider and rotates the shape.
2171
2251
 
@@ -2599,7 +2679,12 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
2599
2679
 
2600
2680
  `AssemblyPartDef`: `{ name: string, part: AssemblyPart, base: Transform, metadata?: PartMetadata }`
2601
2681
 
2602
- **`PartMetadata`**: `material?: string`, `process?: string`, `tolerance?: string`, `qty?: number`, `notes?: string`, `densityKgM3?: number`, `massKg?: number`
2682
+ **`PartMetadata`**
2683
+
2684
+ | Option | Type | Description |
2685
+ |--------|------|-------------|
2686
+ | `tags?` | `string \| readonly string[]` | Viewport organization tags applied to scene objects produced from this part. |
2687
+ | `material?`, `process?`, `tolerance?`, `qty?`, `notes?`, `densityKgM3?`, `massKg?` | | — |
2603
2688
 
2604
2689
  **`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`
2605
2690
 
@@ -2978,7 +3063,7 @@ When `lights` is specified, **all** default lights are removed. You must include
2978
3063
 
2979
3064
  Setting `camera.position` overrides auto-framing — the viewport will no longer auto-fit the geometry on script reload.
2980
3065
 
2981
- Named render views let scripts check in repeatable cameras next to the model code. The canonical shape is `{ camera: { position, target } }`, and a direct camera shorthand `{ position, target }` is also accepted. Use the canonical shape when you may add view metadata later. Use it from the CLI with `forgecad render 3d model.forge.js --view hero`.
3066
+ Named render views let scripts check in repeatable cameras next to the model code. The canonical shape is `{ camera: { position, target } }`, and a direct camera shorthand `{ position, target }` is also accepted. Use the canonical shape when you may add view metadata later. Use it from the CLI with `--view hero` on `forgecad render 3d`, `forgecad render hq`, or `forgecad capture`.
2982
3067
 
2983
3068
  Model journeys let scripts check in a compact guided path through named objects. Each journey has ordered `steps`; each step can name a `focus` target by object name/tree path, provide a caption, and optionally provide an explicit camera. In the viewer, journeys are opt-in: they appear as a small Explore control and do not move the camera until the user starts them. Use `forgecad run model.forge.js --journeys` or `--journeys-json` to inspect resolved targets.
2984
3069
 
@@ -3047,7 +3132,6 @@ scene(options: SceneOptions): void
3047
3132
  | `behavior?` | `"opt-in" \| "auto"` | Whether the viewer should offer or auto-open the journey. First slice supports opt-in. |
3048
3133
  | `steps` | `SceneJourneyStepConfig[]` | Ordered journey spine. Branches can be added later without changing this core contract. |
3049
3134
  | `valid?` | `boolean` | True unless any journey or step diagnostic has level "error". |
3050
- | `diagnostics?` | `SceneJourneyDiagnostic[]` | Whole-journey diagnostics, including unresolved startsAt and step target diagnostics. |
3051
3135
 
3052
3136
  **`SceneJourneyStepConfig`**
3053
3137
 
@@ -3060,9 +3144,6 @@ scene(options: SceneOptions): void
3060
3144
  | `camera?` | `SceneViewCameraConfig` | Optional explicit camera for this step. When omitted, the viewer fits `focus`. |
3061
3145
  | `resolvedFocusId?` | `string \| null` | Resolved object id after script execution, when `focus` matched exactly one object. |
3062
3146
  | `resolvedFocusPath?` | `string \| null` | Resolved object tree path or name after script execution. |
3063
- | `diagnostics?` | `SceneJourneyDiagnostic[]` | Resolution diagnostics for this step. |
3064
-
3065
- `SceneJourneyDiagnostic`: `{ level: SceneJourneyDiagnosticLevel, message: string, stepId?: string, suggestions?: string[] }`
3066
3147
 
3067
3148
  **`SceneLightConfig`**
3068
3149
 
@@ -3146,10 +3227,6 @@ viewConfig({
3146
3227
  viewConfig(options?: ViewConfigOptions): void
3147
3228
  ```
3148
3229
 
3149
- `ViewConfigOptions`: `{ jointOverlay?: JointOverlayViewConfigOptions }`
3150
-
3151
- **`JointOverlayViewConfigOptions`**: `enabled?: boolean`, `axisColor?: string`, `axisCoreColor?: string`, `arcColor?: string`, `zeroColor?: string`, `arcVisualLimitDeg?: number`, `axisLengthScale?: number`, `axisLengthMin?: number`, `axisLineRadiusScale?: number`, `axisLineRadiusMin?: number`, `axisLineRadiusMax?: number`, `spokeLineRadiusScale?: number`, `spokeLineRadiusMin?: number`, `spokeLineRadiusMax?: number`, `arcLineRadiusScale?: number`, `arcLineRadiusMin?: number`, `arcLineRadiusMax?: number`, `axisDotRadiusScale?: number`, `axisDotRadiusMin?: number`, `axisArrowRadiusScale?: number`, `axisArrowRadiusMin?: number`, `axisArrowLengthScale?: number`, `axisArrowLengthMin?: number`, `axisArrowOffsetFactor?: number`, `arcRadiusScale?: number`, `arcRadiusMin?: number`, `arcDotRadiusScale?: number`, `arcDotRadiusMin?: number`, `arcArrowRadiusScale?: number`, `arcArrowRadiusMin?: number`, `arcArrowLengthScale?: number`, `arcArrowLengthMin?: number`, `arcArrowOffsetFactor?: number`, `arcStepDeg?: number`, `arcMinSteps?: number`, `arcTubeSegmentsMin?: number`, `arcTubeSegmentsFactor?: number`, `arcTubeRadialSegments?: number`
3152
-
3153
3230
  #### `spec()` — Create a named, reusable bundle of verification checks.
3154
3231
 
3155
3232
  A spec groups related `verify.*` calls under a collapsible header in the Checks panel. This makes large check suites scannable. Specs can be applied to multiple shapes and can check relationships between parts.
@@ -3197,18 +3274,21 @@ Bring external geometry or other ForgeCAD modules into the current script.
3197
3274
 
3198
3275
  Unlike union(), child colors and individual identities are preserved. Children can be plain shapes, named descriptors ({ name, shape/sketch/group }), or nested groups. The returned ShapeGroup supports all Shape transforms (translate, rotate, etc.).
3199
3276
 
3277
+ Named descriptors can include `tags` for viewport organization. Tags do not affect geometry; they let the command palette hide, show only, or focus all objects with the same tag.
3278
+
3200
3279
  **Local coordinate pattern:** Build child parts at the origin (local coordinates), then group and translate once to place the whole assembly. This eliminates the error-prone pattern of manually adding parent offsets to every sub-part.
3201
3280
 
3202
3281
  ```js
3203
- // BAD every sub-part repeats the parent's global offset
3204
- const unitX = 0, unitY = -18, unitZ = 70;
3205
- const body = roundedBox(100, 20, 32, 4).translate(unitX, unitY, unitZ);
3206
- const panel = box(98, 2, 18).translate(unitX, unitY - 12, unitZ + 4);
3207
- const louver = box(88, 2, 6).translate(unitX, unitY - 14, unitZ - 11);
3282
+ const body = roundedBox(100, 20, 32, 4);
3283
+ const panel = box(98, 2, 18).translate(0, -12, 4);
3284
+ const louver = box(88, 2, 6).translate(0, -14, -11);
3285
+ const indoorUnit = group(
3286
+ { name: 'Body', shape: body },
3287
+ { name: 'Panel', tags: 'cover', shape: panel },
3288
+ { name: 'Louver', tags: ['cover', 'moving'], shape: louver },
3289
+ ).translate(0, -18, 70);
3208
3290
  ```
3209
3291
 
3210
- // GOOD — build at origin, group, translate once const body = roundedBox(100, 20, 32, 4); const panel = box(98, 2, 18).translate(0, -12, 4); const louver = box(88, 2, 6).translate(0, -14, -11); const indoorUnit = group( { name: 'Body', shape: body }, { name: 'Panel', shape: panel }, { name: 'Louver', shape: louver }, ).translate(0, -18, 70);
3211
-
3212
3292
  ```ts
3213
3293
  group(...items: GroupInput[]): ShapeGroup
3214
3294
  ```
@@ -18,15 +18,15 @@ skill-order: 100
18
18
  - [Grouping & Local Coordinates](#grouping-local-coordinates) — `group`
19
19
  - [Section & Projection](#section-projection) — `intersectWithPlane`, `faceProfile`, `projectToPlane`
20
20
  - [Transforms](#transforms) — `composeChain`
21
- - [Backend Runtime](#backend-runtime) — `initKernel`, `setActiveBackend`, `activateBackend`, `getActiveBackend`
22
21
  - [Verification](#verification) — `spec`
23
22
  - [Shape](#shape) — Appearance, Face Topology, Edge Topology, Transforms, Booleans & Cutting, Features, Placement, Connectors, References, Measurement
24
23
  - [Transform](#transform)
25
24
  - [ShapeGroup](#shapegroup) — Children, Transforms, Placement, Connectors, References
26
25
  - [SurfacePattern](#surfacepattern)
26
+ - [Pattern2D](#pattern2d)
27
+ - [Pattern2DBuilder](#pattern2dbuilder)
27
28
  - [ShapeRef](#shaperef)
28
29
  - [ANCHOR3D_NAMES](#anchor3d-names)
29
- - [DEFAULT_ACTIVE_BACKEND](#default-active-backend)
30
30
  - [verify](#verify)
31
31
  - [Constraint](#constraint)
32
32
  - [Points](#points)
@@ -121,9 +121,11 @@ intersection(...inputs: ShapeOperandInput[]): Shape
121
121
 
122
122
  ### Edge Features
123
123
 
124
- #### `fillet()` — Apply fillets (rounded edges) to one or more edges of a shape.
124
+ #### `fillet()` — Apply experimental fillets (rounded edges) to one or more edges of a shape.
125
125
 
126
- Works on edge selections from any active backend. Truck and OCCT route edge finishes through native kernel operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
126
+ **Experimental**: fillets are still backend-sensitive. The Manifold backend is known to produce incorrect results for some edge-finish cases, and the OCCT backend can be very slow, especially with broad edge selections. Prefer targeted edge selectors and inspect the result before treating it as production-ready geometry.
127
+
128
+ Edge selections compile into backend operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
127
129
 
128
130
  The `edges` parameter is flexible:
129
131
 
@@ -149,9 +151,11 @@ fillet(myShape, 3, edges)
149
151
  fillet(shape: Shape, radius: number, edges?: EdgeSelector, segments?: number): Shape
150
152
  ```
151
153
 
152
- #### `chamfer()` — Apply chamfers (beveled edges) to one or more edges of a shape.
154
+ #### `chamfer()` — Apply experimental chamfers (beveled edges) to one or more edges of a shape.
155
+
156
+ **Experimental**: chamfers are still backend-sensitive. The Manifold backend is known to produce incorrect results for some edge-finish cases, and the OCCT backend can be very slow, especially with broad edge selections. Prefer targeted edge selectors and inspect the result before treating it as production-ready geometry.
153
157
 
154
- Produces a 45° bevel at the specified `size` (distance from edge). Works on edge selections from any active backend. Truck and OCCT route chamfers through native kernel operations; unsupported selections fail as explicit kernel gaps instead of using TypeScript geometry fallbacks.
158
+ 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.
155
159
 
156
160
  The `edges` parameter accepts the same options as `fillet()`: inline `EdgeQuery`, pre-selected `EdgeSegment`/`EdgeSegment[]`, or `undefined` (all sharp edges).
157
161
 
@@ -376,11 +380,8 @@ selectEdges(shape: Shape, query?: EdgeQuery): EdgeSegment[]
376
380
  | `normalA` | `Vec3` | Normal of first adjacent face. |
377
381
  | `normalB` | `Vec3` | Normal of second adjacent face (same as normalA for boundary edges). |
378
382
  | `boundary` | `boolean` | true if this is a boundary (unmatched) edge — unusual for closed solids. |
379
- | `nativeTopology?` | `EdgeNativeTopologyRef` | Native kernel topology identity when the active backend can provide one. |
380
383
  | `start`, `end`, `midpoint`, `length` | | — |
381
384
 
382
- `EdgeNativeTopologyRef`: `{ backend: "truck", edge: number }`
383
-
384
385
  #### `selectEdge()` — Select the single best-matching edge from a shape.
385
386
 
386
387
  When `near` is specified, returns the edge whose midpoint is closest to that point. Otherwise returns the first matching edge in mesh order. Throws if no edges match the query — useful as a guard when you expect exactly one result.
@@ -481,7 +482,7 @@ importSvgSketch(fileName: string, options?: SvgImportOptions): Sketch
481
482
  importMesh(fileName: string, options?: { scale?: number; center?: boolean; }): Shape
482
483
  ```
483
484
 
484
- #### `importStep()` — Import a STEP file (.step, .stp) as an exact OCCT-backed Shape. Preserves NURBS curves, B-spline surfaces, and exact topology. Requires `setActiveBackend('occt')`.
485
+ #### `importStep()` — 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.
485
486
 
486
487
  ```ts
487
488
  importStep(fileName: string): Shape
@@ -617,18 +618,21 @@ Param.list<T extends Record<string, number | boolean | string>>(name: string, de
617
618
 
618
619
  Unlike union(), child colors and individual identities are preserved. Children can be plain shapes, named descriptors ({ name, shape/sketch/group }), or nested groups. The returned ShapeGroup supports all Shape transforms (translate, rotate, etc.).
619
620
 
621
+ Named descriptors can include `tags` for viewport organization. Tags do not affect geometry; they let the command palette hide, show only, or focus all objects with the same tag.
622
+
620
623
  **Local coordinate pattern:** Build child parts at the origin (local coordinates), then group and translate once to place the whole assembly. This eliminates the error-prone pattern of manually adding parent offsets to every sub-part.
621
624
 
622
625
  ```js
623
- // BAD every sub-part repeats the parent's global offset
624
- const unitX = 0, unitY = -18, unitZ = 70;
625
- const body = roundedBox(100, 20, 32, 4).translate(unitX, unitY, unitZ);
626
- const panel = box(98, 2, 18).translate(unitX, unitY - 12, unitZ + 4);
627
- const louver = box(88, 2, 6).translate(unitX, unitY - 14, unitZ - 11);
626
+ const body = roundedBox(100, 20, 32, 4);
627
+ const panel = box(98, 2, 18).translate(0, -12, 4);
628
+ const louver = box(88, 2, 6).translate(0, -14, -11);
629
+ const indoorUnit = group(
630
+ { name: 'Body', shape: body },
631
+ { name: 'Panel', tags: 'cover', shape: panel },
632
+ { name: 'Louver', tags: ['cover', 'moving'], shape: louver },
633
+ ).translate(0, -18, 70);
628
634
  ```
629
635
 
630
- // GOOD — build at origin, group, translate once const body = roundedBox(100, 20, 32, 4); const panel = box(98, 2, 18).translate(0, -12, 4); const louver = box(88, 2, 6).translate(0, -14, -11); const indoorUnit = group( { name: 'Body', shape: body }, { name: 'Panel', shape: panel }, { name: 'Louver', shape: louver }, ).translate(0, -18, 70);
631
-
632
636
  ```ts
633
637
  group(...items: GroupInput[]): ShapeGroup
634
638
  ```
@@ -663,32 +667,6 @@ projectToPlane(shape: Shape, plane: PlaneSpec): Sketch
663
667
  composeChain(...steps: TransformInput[]): Transform
664
668
  ```
665
669
 
666
- ### Backend Runtime
667
-
668
- #### `initKernel()`
669
-
670
- ```ts
671
- initKernel(): Promise<unknown>
672
- ```
673
-
674
- #### `setActiveBackend()`
675
-
676
- ```ts
677
- setActiveBackend(backend: ActiveBackend): void
678
- ```
679
-
680
- #### `activateBackend()` — Set the active backend and ensure its WASM module is initialized. Call this instead of `setActiveBackend` when you're about to execute code — it guarantees the backend is ready, not just selected.
681
-
682
- ```ts
683
- activateBackend(backend: ActiveBackend): Promise<void>
684
- ```
685
-
686
- #### `getActiveBackend()`
687
-
688
- ```ts
689
- getActiveBackend(): ActiveBackend
690
- ```
691
-
692
670
  ### Verification
693
671
 
694
672
  #### `spec()` — Create a named, reusable bundle of verification checks.
@@ -1674,6 +1652,82 @@ color(hex: string): ShapeGroup
1674
1652
  | `body` | `string` | Function body: receives (u, v) in surface mm, returns height displacement. |
1675
1653
  | `constants` | `Record<string, number>` | Named constants injected into the function. |
1676
1654
 
1655
+ ### `Pattern2D`
1656
+
1657
+ #### `add()` — Add this pattern to one or more patterns or constant height offsets.
1658
+
1659
+ ```ts
1660
+ add(...patterns: Pattern2DInput[]): Pattern2D
1661
+ ```
1662
+
1663
+ #### `subtract()` — Subtract another pattern or constant height offset from this pattern.
1664
+
1665
+ ```ts
1666
+ subtract(pattern: Pattern2DInput): Pattern2D
1667
+ ```
1668
+
1669
+ #### `multiply()` — Multiply this pattern by one or more patterns or numeric scale factors.
1670
+
1671
+ ```ts
1672
+ multiply(...patterns: Pattern2DInput[]): Pattern2D
1673
+ ```
1674
+
1675
+ #### `min()` — Keep the lower height between this pattern and one or more other patterns.
1676
+
1677
+ ```ts
1678
+ min(...patterns: Pattern2DInput[]): Pattern2D
1679
+ ```
1680
+
1681
+ #### `max()` — Keep the higher height between this pattern and one or more other patterns.
1682
+
1683
+ ```ts
1684
+ max(...patterns: Pattern2DInput[]): Pattern2D
1685
+ ```
1686
+
1687
+ #### `clamp()` — Limit pattern height to the inclusive `[min, max]` range in millimeters.
1688
+
1689
+ ```ts
1690
+ clamp(min: number, max: number): Pattern2D
1691
+ ```
1692
+
1693
+ #### `abs()` — Convert negative heights to positive heights.
1694
+
1695
+ ```ts
1696
+ abs(): Pattern2D
1697
+ ```
1698
+
1699
+ #### `negate()` — Flip the pattern height sign.
1700
+
1701
+ ```ts
1702
+ negate(): Pattern2D
1703
+ ```
1704
+
1705
+ ### `Pattern2DBuilder`
1706
+
1707
+ #### `constant()` — Create a constant-height pattern in millimeters.
1708
+
1709
+ ```ts
1710
+ constant(value?: number): Pattern2D
1711
+ ```
1712
+
1713
+ #### `sineWave()` — Create a sinusoidal wave pattern in UV space.
1714
+
1715
+ ```ts
1716
+ sineWave(options: Pattern2DSineWaveOptions): Pattern2D
1717
+ ```
1718
+
1719
+ #### `stripes()` — Create recessed stripe bands in UV space.
1720
+
1721
+ ```ts
1722
+ stripes(options: Pattern2DStripesOptions): Pattern2D
1723
+ ```
1724
+
1725
+ #### `overUnderWeave()` — Create an over-under woven relief pattern in UV space.
1726
+
1727
+ ```ts
1728
+ overUnderWeave(options: Pattern2DOverUnderWeaveOptions): Pattern2D
1729
+ ```
1730
+
1677
1731
  ### `ShapeRef`
1678
1732
 
1679
1733
  A first-class reference path over a shape's semantic faces and face relationships.
@@ -1796,10 +1850,6 @@ toString(): string
1796
1850
 
1797
1851
  ### `ANCHOR3D_NAMES`
1798
1852
 
1799
- ### `DEFAULT_ACTIVE_BACKEND`
1800
-
1801
- Default geometry backend when no explicit backend is selected.
1802
-
1803
1853
  ### `verify`
1804
1854
 
1805
1855
  - `that(label: string, check: () => boolean, message?: string): void` — Custom predicate check.