forgecad 0.9.13 → 0.9.15

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 (216) hide show
  1. package/LICENSE +6 -4
  2. package/README.md +8 -4
  3. package/dist/assets/{AdminPage-DramHHDf.js → AdminPage-CDyGUinA.js} +2 -2
  4. package/dist/assets/{BenchmarkPage-Bjgkh5m9.js → BenchmarkPage-DfPMY_-d.js} +4 -15
  5. package/dist/assets/{BlogPage-n_HGP3Qm.js → BlogPage-kF0fkdJT.js} +2 -2
  6. package/dist/assets/{DocsPage-WCIkPmzC.js → DocsPage-B954L3YN.js} +9 -3
  7. package/dist/assets/EditorApp-Beb-IZ0y.js +14014 -0
  8. package/dist/assets/{EditorApp-BAnckbsk.css → EditorApp-CuDLxKqL.css} +698 -0
  9. package/dist/assets/{EmbedViewer-DEZKqdfW.js → EmbedViewer-C77B-TrF.js} +3 -3
  10. package/dist/assets/{LandingPageProofDriven-CeRIctuj.js → LandingPageProofDriven-Cr6fXMDj.js} +35 -37
  11. package/dist/assets/LegalPage-BRlScr9A.css +91 -0
  12. package/dist/assets/LegalPage-Dzklqmmg.js +39 -0
  13. package/dist/assets/{PricingPage-BMedqFef.css → PricingPage-BPF6HKyO.css} +25 -0
  14. package/dist/assets/{PricingPage-rIRa8p4Y.js → PricingPage-zWXkvlwl.js} +19 -19
  15. package/dist/assets/{SettingsPage-BqCUvEXM.js → SettingsPage-Bz0of4KQ.js} +2 -2
  16. package/dist/assets/app-CE3sYcV7.css +3890 -0
  17. package/dist/assets/{app-BUZqJvSO.js → app-D3kDkggg.js} +2305 -960
  18. package/dist/assets/cli/{render-lhGxj50Y.js → render-DSY3mMQa.js} +423 -30
  19. package/dist/assets/{constructionHistoryWorker-ipD1jcIv.js → constructionHistoryWorker-gpDo-uH2.js} +927 -243
  20. package/dist/assets/{evalWorker-CHXSe_-u.js → evalWorker-CU0Ke6DP.js} +7799 -4163
  21. package/dist/assets/{forgecad_geometry-BVnIeXMG.js → forgecad_geometry-Dgceylq9.js} +43 -1
  22. package/dist/assets/{forgecad_geometry_bg-DufhhCBV.wasm → forgecad_geometry_bg-dD4RNQF1.wasm} +0 -0
  23. package/dist/assets/{inspectWorker-DeRnMVv1.js → inspectWorker-COyp8XXA.js} +927 -243
  24. package/dist/assets/{javascript-70-4uGcz.js → javascript-1kQXfVaz.js} +1 -1
  25. package/dist/assets/landing-proof-driven-DiGqdtWa.js +18 -0
  26. package/dist/assets/{landing-proof-driven-oFYW6mjz.css → landing-proof-driven-ORyigZ6p.css} +13 -7
  27. package/dist/assets/legalContent-ZfFGMmi4.js +251 -0
  28. package/dist/assets/{manifold-D1LZIHqn.js → manifold-BRI5prcH.js} +1 -1
  29. package/dist/assets/{manifold-C2fwoTgd.js → manifold-C-3h2M7p.js} +2 -2
  30. package/dist/assets/{manifold-BTkzxi9V.js → manifold-DNkrUWpA.js} +1 -1
  31. package/dist/assets/{reportWorker-Cq1qGmg0.js → reportWorker-CdBz5bNg.js} +7537 -10856
  32. package/dist/assets/{scalar-sampling-budget-D9Qv_UlJ.js → scalar-sampling-budget-wJF98aY9.js} +6943 -4345
  33. package/dist/assets/{scanProxyWorker-Bs2TDgLw.js → scanProxyWorker-B-9VbLIs.js} +32 -1
  34. package/dist/assets/{renderSceneState-Dr0xPq1A.js → targets-B9sGB5nB.js} +27 -1
  35. package/dist/assets/{vendor-react-Da3A2QmU.js → vendor-react-6j1Kke-Y.js} +6 -5
  36. package/dist/cli/render.html +1 -1
  37. package/dist/docs/index.html +2 -2
  38. package/dist/docs-raw/AI/ai-native-cad.md +50 -0
  39. package/dist/docs-raw/AI/usage.md +9 -17
  40. package/dist/docs-raw/CLI.md +71 -21
  41. package/dist/docs-raw/component-model.md +27 -11
  42. package/dist/docs-raw/generated/assembly.md +301 -212
  43. package/dist/docs-raw/generated/concepts.md +238 -240
  44. package/dist/docs-raw/generated/core.md +283 -6
  45. package/dist/docs-raw/generated/curves.md +274 -361
  46. package/dist/docs-raw/generated/lib.md +7 -1
  47. package/dist/docs-raw/generated/output.md +19 -4
  48. package/dist/docs-raw/generated/runtime-names.md +41 -0
  49. package/dist/docs-raw/generated/sdf.md +31 -0
  50. package/dist/docs-raw/generated/sheet-metal.md +9 -0
  51. package/dist/docs-raw/generated/sketch.md +44 -1
  52. package/dist/docs-raw/generated/viewport.md +14 -6
  53. package/dist/docs-raw/guides/coordinate-system.md +20 -16
  54. package/dist/docs-raw/guides/geometry-conventions.md +2 -2
  55. package/dist/docs-raw/guides/inspection-bundles.md +2 -1
  56. package/dist/docs-raw/guides/joint-design.md +24 -0
  57. package/dist/docs-raw/guides/positioning.md +13 -3
  58. package/dist/docs-raw/legal/privacy.md +63 -0
  59. package/dist/docs-raw/legal/software-license.md +55 -0
  60. package/dist/docs-raw/legal/terms.md +87 -0
  61. package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +3 -3
  62. package/dist/docs-raw/skills/forgecad-blockout-model.md +1 -1
  63. package/dist/docs-raw/skills/forgecad-component-model.md +11 -2
  64. package/dist/docs-raw/skills/forgecad-high-level-spec.md +1 -1
  65. package/dist/docs-raw/skills/forgecad-image-replicator.md +8 -8
  66. package/dist/docs-raw/skills/forgecad-lld.md +1 -1
  67. package/dist/docs-raw/skills/forgecad-make-a-model.md +4 -4
  68. package/dist/docs-raw/skills/forgecad-model-grader.md +2 -2
  69. package/dist/docs-raw/skills/forgecad-prepare-prompt.md +2 -2
  70. package/dist/docs-raw/skills/forgecad-project.md +1 -1
  71. package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +4 -4
  72. package/dist/docs-raw/skills/forgecad-render-inspect.md +4 -2
  73. package/dist/docs-raw/skills/forgecad-visual-spec.md +1 -1
  74. package/dist/docs-raw/skills/forgecad.md +4 -3
  75. package/dist/index.html +40 -12
  76. package/dist/llms.txt +8 -0
  77. package/dist/site.webmanifest +1 -1
  78. package/dist/sitemap.xml +49 -13
  79. package/dist-cli/{check-compiler-LOXCPEOI.js → check-compiler-SDX5QIXI.js} +1 -2
  80. package/dist-cli/{check-query-propagation-BAKNVWXR.js → check-query-propagation-EAYEFT77.js} +1 -2
  81. package/dist-cli/{chunk-RY43WF46.js → chunk-N4O47JLF.js} +13772 -9938
  82. package/dist-cli/forgecad.js +2387 -899
  83. package/dist-cli/{forgecad_geometry-GYVNKPIE.js → forgecad_geometry-QOQIIP53.js} +42 -1
  84. package/dist-cli/forgecad_geometry_bg.wasm +0 -0
  85. package/dist-cli/{solver-46FFSK2U.js → solver-OK4HECRH.js} +0 -1
  86. package/dist-skill/CONTEXT.md +1120 -724
  87. package/dist-skill/SKILL.md +3 -2
  88. package/dist-skill/docs/API/core/concepts.md +64 -1
  89. package/dist-skill/docs/CLI.md +71 -21
  90. package/dist-skill/docs/generated/assembly.md +277 -229
  91. package/dist-skill/docs/generated/core.md +283 -6
  92. package/dist-skill/docs/generated/curves.md +272 -362
  93. package/dist-skill/docs/generated/lib.md +7 -1
  94. package/dist-skill/docs/generated/output.md +19 -4
  95. package/dist-skill/docs/generated/runtime-names.md +41 -0
  96. package/dist-skill/docs/generated/sdf.md +31 -0
  97. package/dist-skill/docs/generated/sheet-metal.md +9 -0
  98. package/dist-skill/docs/generated/sketch.md +44 -2
  99. package/dist-skill/docs/generated/viewport.md +5 -90
  100. package/dist-skill/docs/guides/coordinate-system.md +20 -16
  101. package/dist-skill/docs/guides/geometry-conventions.md +2 -2
  102. package/dist-skill/docs/guides/inspection-bundles.md +2 -1
  103. package/dist-skill/docs/guides/joint-design.md +24 -0
  104. package/dist-skill/docs/guides/positioning.md +13 -3
  105. package/dist-skill/library/forgecad-3d-reconstruction/SKILL.md +2 -2
  106. package/dist-skill/library/forgecad-component-model/SKILL.md +10 -1
  107. package/dist-skill/library/forgecad-image-replicator/SKILL.md +6 -6
  108. package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.py +166 -0
  109. package/dist-skill/library/forgecad-make-a-model/SKILL.md +3 -3
  110. package/dist-skill/library/forgecad-model-grader/SKILL.md +1 -1
  111. package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +1 -1
  112. package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +3 -3
  113. package/dist-skill/library/forgecad-render-inspect/SKILL.md +3 -1
  114. package/examples/api/assembly-kinematics-foundation.forge.js +65 -0
  115. package/examples/api/assembly-kinematics-four-bar.forge.js +115 -0
  116. package/examples/api/assembly-kinematics-limb.forge.js +116 -0
  117. package/examples/api/connector-frame-rig-chain.forge.js +102 -0
  118. package/examples/api/exact-sheet-shell-assembly.forge.js +0 -2
  119. package/examples/api/exact-surface-studio.forge.js +6 -8
  120. package/examples/api/helix-basics.forge.js +6 -6
  121. package/examples/api/lean-foundations/README.md +12 -0
  122. package/examples/api/lean-foundations/curve-blend-exact.forge.js +22 -0
  123. package/examples/api/lean-foundations/curve-fit-interpolation.forge.js +18 -0
  124. package/examples/api/lean-foundations/curve-helix-canonicalization.forge.js +27 -0
  125. package/examples/api/lean-foundations/curve-route-canonicalization.forge.js +16 -0
  126. package/examples/api/lean-foundations/curve-trim-reverse.forge.js +24 -0
  127. package/examples/api/lean-foundations/exact-curve-arc.forge.js +36 -0
  128. package/examples/api/mixed-edge-finishes-proof.forge.js +8 -11
  129. package/examples/api/route3d-elbow.forge.js +68 -0
  130. package/examples/api/transition-curves.forge.js +44 -15
  131. package/examples/api/y-blend-corner-showcase.forge.js +0 -2
  132. package/examples/generative/coral-vase.forge.js +1 -1
  133. package/examples/nurbs-tube.forge.js +1 -1
  134. package/package.json +14 -18
  135. package/dist/assets/EditorApp-CP9Za6tm.js +0 -13630
  136. package/dist/assets/app-CsHnaBWt.css +0 -1789
  137. package/dist/docs-raw/API/README.md +0 -16
  138. package/dist/docs-raw/API/core/concepts.md +0 -118
  139. package/dist/docs-raw/INDEX.md +0 -138
  140. package/dist/docs-raw/RELEASING.md +0 -87
  141. package/dist/docs-raw/agent-native-api.md +0 -27
  142. package/dist/docs-raw/beta-deployment.md +0 -304
  143. package/dist/docs-raw/beta-operations.md +0 -325
  144. package/dist/docs-raw/blueprint-first.md +0 -145
  145. package/dist/docs-raw/cli-monetization.md +0 -112
  146. package/dist/docs-raw/coding-best-practices.md +0 -120
  147. package/dist/docs-raw/coding.md +0 -340
  148. package/dist/docs-raw/deployment.md +0 -374
  149. package/dist/docs-raw/guides/skill-maintenance.md +0 -161
  150. package/dist/docs-raw/guides/surface-members.md +0 -82
  151. package/dist/docs-raw/internals/backend-vocabulary.md +0 -35
  152. package/dist/docs-raw/internals/compiler.md +0 -307
  153. package/dist/docs-raw/internals/constraint-solver-quality.md +0 -161
  154. package/dist/docs-raw/internals/constraint-solver.md +0 -176
  155. package/dist/docs-raw/internals/shape-from-slices.md +0 -152
  156. package/dist/docs-raw/internals/sketch-2d-pipeline.md +0 -108
  157. package/dist/docs-raw/platform/admin.md +0 -45
  158. package/dist/docs-raw/platform/architecture.md +0 -82
  159. package/dist/docs-raw/platform/auth.md +0 -139
  160. package/dist/docs-raw/platform/email.md +0 -67
  161. package/dist/docs-raw/platform/google-oauth-setup.md +0 -88
  162. package/dist/docs-raw/platform/observability.md +0 -197
  163. package/dist/docs-raw/platform/projects.md +0 -111
  164. package/dist/docs-raw/platform/sharing.md +0 -90
  165. package/dist/docs-raw/product/README.md +0 -39
  166. package/dist/docs-raw/product/api-as-product-language.md +0 -13
  167. package/dist/docs-raw/product/business-model.md +0 -15
  168. package/dist/docs-raw/product/competitive-positioning.md +0 -17
  169. package/dist/docs-raw/product/creative-manufacturing.md +0 -15
  170. package/dist/docs-raw/product/founder-story.md +0 -11
  171. package/dist/docs-raw/product/manufacturing-workflows.md +0 -15
  172. package/dist/docs-raw/product/onboarding-first-experience.md +0 -256
  173. package/dist/docs-raw/product/product-loop.md +0 -17
  174. package/dist/docs-raw/product/strategic-decisions.md +0 -22
  175. package/dist/docs-raw/product/user-outreach-email-templates.md +0 -161
  176. package/dist/docs-raw/product/user-segments.md +0 -15
  177. package/dist/docs-raw/product/vision.md +0 -26
  178. package/dist/docs-raw/rl-environments.md +0 -508
  179. package/dist/docs-raw/runbook.md +0 -611
  180. package/dist-cli/check-compiler-LOXCPEOI.js.map +0 -1
  181. package/dist-cli/check-query-propagation-BAKNVWXR.js.map +0 -1
  182. package/dist-cli/chunk-RY43WF46.js.map +0 -1
  183. package/dist-cli/forgecad.js.map +0 -1
  184. package/dist-cli/forgecad_geometry-GYVNKPIE.js.map +0 -1
  185. package/dist-cli/solver-46FFSK2U.js.map +0 -1
  186. package/dist-skill/SKILL-dev.md +0 -145
  187. package/dist-skill/docs-dev/API/core/concepts.md +0 -118
  188. package/dist-skill/docs-dev/CLI.md +0 -647
  189. package/dist-skill/docs-dev/agent-native-api.md +0 -27
  190. package/dist-skill/docs-dev/blueprint-first.md +0 -145
  191. package/dist-skill/docs-dev/coding-best-practices.md +0 -120
  192. package/dist-skill/docs-dev/coding.md +0 -340
  193. package/dist-skill/docs-dev/component-model.md +0 -164
  194. package/dist-skill/docs-dev/generated/assembly.md +0 -794
  195. package/dist-skill/docs-dev/generated/core.md +0 -2117
  196. package/dist-skill/docs-dev/generated/curves.md +0 -2583
  197. package/dist-skill/docs-dev/generated/lib.md +0 -169
  198. package/dist-skill/docs-dev/generated/output.md +0 -247
  199. package/dist-skill/docs-dev/generated/sdf.md +0 -446
  200. package/dist-skill/docs-dev/generated/sheet-metal.md +0 -504
  201. package/dist-skill/docs-dev/generated/sketch.md +0 -1811
  202. package/dist-skill/docs-dev/generated/viewport.md +0 -585
  203. package/dist-skill/docs-dev/generated/wood.md +0 -108
  204. package/dist-skill/docs-dev/guides/coordinate-system.md +0 -46
  205. package/dist-skill/docs-dev/guides/geometry-conventions.md +0 -52
  206. package/dist-skill/docs-dev/guides/inspection-bundles.md +0 -485
  207. package/dist-skill/docs-dev/guides/joint-design.md +0 -78
  208. package/dist-skill/docs-dev/guides/modeling-recipes.md +0 -78
  209. package/dist-skill/docs-dev/guides/positioning.md +0 -161
  210. package/dist-skill/docs-dev/guides/skill-maintenance.md +0 -161
  211. package/dist-skill/docs-dev/internals/backend-vocabulary.md +0 -35
  212. package/dist-skill/docs-dev/internals/compiler.md +0 -307
  213. package/dist-skill/docs-dev/internals/constraint-solver-quality.md +0 -161
  214. package/dist-skill/docs-dev/internals/constraint-solver.md +0 -176
  215. package/dist-skill/docs-dev/internals/sketch-2d-pipeline.md +0 -108
  216. package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.mjs +0 -289
@@ -9,15 +9,13 @@ Smooth curves, lofted surfaces, swept solids, splines, and high-level product sk
9
9
 
10
10
  ## Contents
11
11
 
12
- - [Curves & Surfacing](#curves-surfacing) — `Loft.station`, `Loft.leftRail`, `Loft.rightRail`, `Loft.frontRail`, `Loft.backRail`, `Loft.centerRail`, `Loft.pathOnXz`, `Loft.pathOnYz`, `Loft.pathOnXy`, `Loft.withGuideRails`, `Helix.path`, `Helix.coil`, `hermiteTransitionG2`, `nurbs3d`, `spline2d`, `spline3d`, `loft`, `loftAlongSpine`, `sweep`, `variableSweep`, `nurbsSurface`, `surfacePatch`, `transitionCurve`, `transitionSurface`, `connectEdges`
12
+ - [Curves & Surfacing](#curves-surfacing) — `Curve.Blend`, `Curve.BlendG2`, `Curve.Arc`, `Curve.Line`, `Curve.Polyline`, `Curve.Spline`, `Curve.Nurbs`, `Curve.Fit`, `Curve.Trim`, `Curve.Reverse`, `Curve.Route`, `Curve.Helix`, `Loft.station`, `Loft.leftRail`, `Loft.rightRail`, `Loft.frontRail`, `Loft.backRail`, `Loft.centerRail`, `Loft.pathOnXz`, `Loft.pathOnYz`, `Loft.pathOnXy`, `Loft.withGuideRails`, `spline2d`, `loft`, `sweep`, `variableSweep`, `nurbsSurface`, `surfacePatch`
13
13
  - [Surface Members](#surface-members) — `surfaceBand`, `SurfaceBody`
14
14
  - [Curve3D](#curve3d)
15
- - [HelixCurve](#helixcurve)
15
+ - [Route3D](#route3d)
16
16
  - [NurbsCurve3D](#nurbscurve3d)
17
17
  - [NurbsSurface](#nurbssurface)
18
18
  - [PathBuilder](#pathbuilder) — Line Segments, Arcs, Curves, Closing & Output
19
- - [HermiteCurve3D](#hermitecurve3d)
20
- - [QuinticHermiteCurve3D](#quintichermitecurve3d)
21
19
  - [ProductSkin](#productskin)
22
20
  - [ProductSurfaceRef](#productsurfaceref)
23
21
  - [ProductSurfaceBuilder](#productsurfacebuilder)
@@ -39,6 +37,7 @@ Smooth curves, lofted surfaces, swept solids, splines, and high-level product sk
39
37
  - [SurfaceJoinBuilder](#surfacejoinbuilder)
40
38
  - [CounterboreBuilder](#counterborebuilder)
41
39
  - [RoundedSlotBuilder](#roundedslotbuilder)
40
+ - [Curve](#curve)
42
41
  - [Surface](#surface)
43
42
  - [Blend](#blend)
44
43
  - [Analysis](#analysis)
@@ -48,97 +47,186 @@ Smooth curves, lofted surfaces, swept solids, splines, and high-level product sk
48
47
  - [Slot](#slot)
49
48
  - [Counterbore](#counterbore)
50
49
  - [Ribs](#ribs)
51
- - [Helix](#helix)
52
50
 
53
51
  ## Functions
54
52
 
55
53
  ### Curves & Surfacing
56
54
 
57
- #### `Loft.station()` — Create a loft station from a 2D profile and an axis position.
55
+ #### `Curve.Blend()` — Create an exact G1 blend curve between two directed endpoints.
56
+
57
+ The returned curve is a cubic non-rational `NurbsCurve3D`: ForgeCAD converts the endpoint positions and tangents into Bezier control points, so the curve can feed `sweep` and exact surface boundaries through the existing `nurbs` IR rather than a sampled polyline.
58
+
59
+ ```js
60
+ const rail = Curve.Blend(
61
+ { point: [0, 0, 0], tangent: [1, 0, 0], weight: 0.8 },
62
+ { point: [40, 20, 8], tangent: [0, 1, 0], weight: 0.8 },
63
+ );
64
+ const tube = sweep(circle2d(2), rail);
65
+ ```
58
66
 
59
67
  ```ts
60
- Loft.station(profile: Sketch, position: number): LoftStation
68
+ Curve.Blend(start: CurveBlendEndpoint, end: CurveBlendEndpoint): NurbsCurve3D
61
69
  ```
62
70
 
63
- `LoftStation`: `{ profile: Sketch, position: number }`
71
+ **`CurveBlendEndpoint`**
72
+ - `point: Vec3` — Endpoint position.
73
+ - `tangent: Vec3` — Tangent direction at this endpoint. Magnitude is ignored.
74
+ - `weight?: number` — Tangent reach relative to the endpoint chord length. Default 1.
64
75
 
65
- #### `Loft.leftRail()` — Create a guide rail that constrains the section-local negative-X side.
76
+ #### `Curve.BlendG2()` — Create an exact G2 blend curve between two directed endpoints.
77
+
78
+ This is the curvature-aware companion to `Curve.Blend()`. It returns a degree-5 non-rational `NurbsCurve3D` that matches endpoint position, tangent direction, and optional curvature/second-derivative vectors.
79
+
80
+ ```js
81
+ const rail = Curve.BlendG2(
82
+ { point: [0, 0, 0], tangent: [1, 0, 0], curvature: [0, 0.02, 0] },
83
+ { point: [50, 20, 0], tangent: [0, 1, 0], curvature: [-0.02, 0, 0] },
84
+ );
85
+ ```
66
86
 
67
87
  ```ts
68
- Loft.leftRail(path: LoftGuideRailPath): LoftGuideRail
88
+ Curve.BlendG2(start: CurveBlendG2Endpoint, end: CurveBlendG2Endpoint): NurbsCurve3D
69
89
  ```
70
90
 
71
- `LoftGuideRail`: `{ side: LoftGuideRailSide, path: LoftGuideRailPath }`
91
+ **`CurveBlendG2Endpoint`** extends CurveBlendEndpoint
92
+ - `curvature?: Vec3` — Optional endpoint curvature/second-derivative vector. Default is zero.
72
93
 
73
- #### `Loft.rightRail()` — Create a guide rail that constrains the section-local positive-X side.
94
+ #### `Curve.Arc()` — Create an exact circular 3D arc from start, end, and start tangent.
95
+
96
+ The returned curve is a rational quadratic `NurbsCurve3D`, split into stable spans when needed, so it can feed `sweep` without sampling the authoring intent away.
97
+
98
+ ```js
99
+ const rail = Curve.Arc({
100
+ start: [40, 0, 0],
101
+ end: [0, 40, 0],
102
+ tangent: [0, 1, 0],
103
+ });
104
+ const tube = sweep(circle2d(2), rail);
105
+ ```
74
106
 
75
107
  ```ts
76
- Loft.rightRail(path: LoftGuideRailPath): LoftGuideRail
108
+ Curve.Arc(options: CurveArcOptions): NurbsCurve3D
77
109
  ```
78
110
 
79
- #### `Loft.frontRail()` — Create a guide rail that constrains the section-local positive-Y side.
111
+ **`CurveArcOptions`**
112
+ - `start: Vec3` — Arc start point.
113
+ - `end: Vec3` — Arc end point.
114
+ - `tangent: Vec3` — Tangent direction at the start point. Magnitude is ignored.
115
+
116
+ #### `Curve.Line()` — Create an exact straight 3D NURBS line segment.
117
+
118
+ ```js
119
+ const rail = Curve.Line([0, 0, 0], [80, 0, 15]);
120
+ const rib = sweep(circle2d(2), rail);
121
+ ```
80
122
 
81
123
  ```ts
82
- Loft.frontRail(path: LoftGuideRailPath): LoftGuideRail
124
+ Curve.Line(start: Vec3, end: Vec3): NurbsCurve3D
83
125
  ```
84
126
 
85
- #### `Loft.backRail()` — Create a guide rail that constrains the section-local negative-Y side.
127
+ #### `Curve.Polyline()` — Create a polyline path as cloned 3D points.
128
+
129
+ Polylines are exact as route/path input to `sweep`. Use `Curve.Route` when the centerline needs bend and endpoint-frame metadata.
86
130
 
87
131
  ```ts
88
- Loft.backRail(path: LoftGuideRailPath): LoftGuideRail
132
+ Curve.Polyline(points: Vec3[]): Vec3[]
89
133
  ```
90
134
 
91
- #### `Loft.centerRail()` — Create a guide rail that moves section centers along the loft.
135
+ #### `Curve.Spline()` — Create a smooth Catmull-Rom spline path.
136
+
137
+ This is a smooth sampled curve object. Use `Curve.Nurbs` when the path must preserve exact control-point and knot data.
92
138
 
93
139
  ```ts
94
- Loft.centerRail(path: LoftGuideRailPath): LoftGuideRail
140
+ Curve.Spline(points: Vec3[], options?: Spline3DOptions): Curve3D
95
141
  ```
96
142
 
97
- #### `Loft.pathOnXz()` — Place a 2D guide path onto the XZ plane.
143
+ **`Spline3DOptions`**
144
+ - `closed?: boolean` — Closed loop (default false).
145
+ - `tension?: number` — Catmull-Rom tension in [0, 1]. 0 = very round, 1 = linear-ish. Default 0.5.
98
146
 
99
- The path's first coordinate becomes X and its second coordinate becomes Z. Use this for left/right silhouette rails authored with [`path()`](/docs/sketch#path) or [`constrainedSketch()`](/docs/sketch#constrainedsketch).
147
+ #### `Curve.Nurbs()` Create an exact NURBS 3D curve from control points, weights, knots, and degree.
148
+
149
+ ```js
150
+ const rail = Curve.Nurbs([[0, 0, 0], [30, 4, 12], [60, -4, 12], [90, 0, 0]]);
151
+ const tube = sweep(circle2d(2), rail);
152
+ ```
100
153
 
101
154
  ```ts
102
- Loft.pathOnXz(path: LoftPath2D, y?: number): Vec3[]
155
+ Curve.Nurbs(points: Vec3[], options?: NurbsCurve3DOptions): NurbsCurve3D
103
156
  ```
104
157
 
105
- #### `Loft.pathOnYz()` — Place a 2D guide path onto the YZ plane.
158
+ **`NurbsCurve3DOptions`**
106
159
 
107
- The path's first coordinate becomes Y and its second coordinate becomes Z. Use this for front/back crown rails authored with [`path()`](/docs/sketch#path) or [`constrainedSketch()`](/docs/sketch#constrainedsketch).
160
+ | Option | Type | Description |
161
+ |--------|------|-------------|
162
+ | `degree?` | `number` | Polynomial degree (default 3 = cubic). Must be ≥ 1. |
163
+ | `weights?` | `number[]` | Rational weights, one per control point (default: all 1.0 = non-rational). |
164
+ | `knots?` | `number[]` | Knot vector (default: uniform clamped). Must have length = controlPoints.length + degree + 1. |
165
+ | `closed?` | `boolean` | Whether the curve is closed/periodic (default false). |
166
+
167
+ #### `Curve.Fit()` — Fit a non-rational NURBS curve that interpolates every input point.
168
+
169
+ This is global B-spline interpolation, not approximate curve reduction: ForgeCAD computes chord-length parameters, averaged clamped knots, solves the control points, then verifies the interpolation residual against `tolerance`.
170
+
171
+ ```js
172
+ const rail = Curve.Fit(
173
+ [[0, 0, 0], [20, 8, 12], [50, -4, 18], [80, 0, 0]],
174
+ { degree: 3, tolerance: 0.001 },
175
+ );
176
+ const tube = sweep(circle2d(2), rail);
177
+ ```
108
178
 
109
179
  ```ts
110
- Loft.pathOnYz(path: LoftPath2D, x?: number): Vec3[]
180
+ Curve.Fit(points: Vec3[], options?: CurveFitOptions): NurbsCurve3D
111
181
  ```
112
182
 
113
- #### `Loft.pathOnXy()` — Place a 2D guide path onto the XY plane.
183
+ **`CurveFitOptions`**
184
+ - `degree?: number` — Polynomial degree. Default is cubic, reduced automatically for short point lists.
185
+ - `tolerance?: number` — Maximum allowed interpolation residual in model units. Default 1e-7.
114
186
 
115
- 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.
187
+ #### `Curve.Trim()` Extract an exact curve segment from normalized parameter `start` to `end`.
188
+
189
+ `NurbsCurve3D` inputs are trimmed with exact knot insertion/subdomain extraction. Polyline point arrays are trimmed by arclength over their exact line segments. Sampled `Curve3D` splines are rejected until ForgeCAD has a tolerance-controlled rebuild path.
116
190
 
117
191
  ```ts
118
- Loft.pathOnXy(path: LoftPath2D, z?: number): Vec3[]
192
+ Curve.Trim<T extends CurveTrimInput>(curve: T, start: number, end: number): CurveTrimOutput<T>
119
193
  ```
120
194
 
121
- #### `Loft.withGuideRails()` — Loft through profile stations while forcing generated sections to follow guide rails.
195
+ #### `Curve.Reverse()` — Reverse an exact curve without changing its geometry.
122
196
 
123
- 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.
197
+ `NurbsCurve3D` inputs reverse control points, weights, and knots. Polyline point arrays are cloned and reversed. Sampled `Curve3D` splines are rejected until ForgeCAD has a tolerance-controlled rebuild path.
124
198
 
125
199
  ```ts
126
- Loft.withGuideRails(stations: LoftStation[], rails: LoftGuideRail[], options?: LoftWithGuideRailsOptions): Shape
200
+ Curve.Reverse<T extends CurveTrimInput>(curve: T): CurveTrimOutput<T>
127
201
  ```
128
202
 
129
- **`LoftOptions`**
130
- - `edgeLength?: number` — Marching-grid edge length for level-set meshing. Smaller = finer.
131
- - `boundsPadding?: number` — Optional extra bounds padding.
203
+ #### `Curve.Route()` — Build analytic 3D line/arc routes for sweeps.
132
204
 
133
- **`LoftWithGuideRailsOptions`** extends LoftOptions
134
- - `axis?: LoftAxis` — Primary station axis. Default Z.
135
- - `samples?: number` — Number of generated loft stations including ends. Default scales with station count.
136
- - `railSamples?: number` — Number of points sampled from curve-backed rails before axis interpolation. Default 64.
205
+ `Curve.Route.fromPolyline()` is the canonical route API. It returns a `Route3D` value object, preserving exact route segments, named port frames, and the lowerable `route3d` sweep compile plan.
206
+
207
+ ```js
208
+ const route = Curve.Route.fromPolyline(
209
+ [[0, 0, 0], [0, 0, 50], [40, 0, 50]],
210
+ { cornerRadius: 12, startPort: 'inlet', endPort: 'outlet' },
211
+ );
212
+ const tube = sweep(circle2d(4), route);
213
+ ```
214
+
215
+ ```ts
216
+ Curve.Route: typeof Route3D
217
+ ```
137
218
 
138
- #### `Helix.path()` — Create a metadata-bearing helical centerline around the Z axis.
219
+ #### `Curve.Helix()` — Build helical paths and swept coils.
220
+
221
+ `Curve.Helix` is the canonical namespace for helical paths and coils. It uses the same sweep-based lowering as other curve paths.
222
+
223
+ ```js
224
+ const guide = Curve.Helix.path({ radius: 20, pitch: 6, turns: 4 });
225
+ const spring = Curve.Helix.coil({ radius: 20, pitch: 6, turns: 4, wireRadius: 1 });
226
+ ```
139
227
 
140
228
  ```ts
141
- Helix.path(options: HelixOptions): HelixCurve
229
+ Curve.Helix: { path(options: HelixOptions): CurveHelixPath; coil: CurveHelixCoil; }
142
230
  ```
143
231
 
144
232
  **`HelixOptions`**
@@ -153,66 +241,88 @@ Helix.path(options: HelixOptions): HelixCurve
153
241
  | `clockwise?` | `boolean` | Reverse winding direction when viewed from +Z. |
154
242
  | `samplesPerTurn?` | `number` | Point samples per turn for the metadata path. Default 32. |
155
243
 
156
- #### `Helix.coil()` Create a solid helical coil by sweeping a profile through helix-local frames.
244
+ `CurveHelixPath`: `{ radius: number, pitch: number, turns: number, height: number, startAngle: number, clockwise: boolean }`
157
245
 
158
- Overloads:
246
+ #### `Loft.station()` — Create a loft station from a 2D profile and an axis position.
159
247
 
160
- - `Helix.coil(options: HelixCoilOptions): Shape`
161
- - `Helix.coil(profile: Sketch, options: HelixCoilOptions): Shape`
248
+ ```ts
249
+ Loft.station(profile: Sketch, position: number): LoftStation
250
+ ```
162
251
 
252
+ `LoftStation`: `{ profile: Sketch, position: number }`
163
253
 
164
- **`HelixCoilOptions`** extends HelixOptions
165
- - `wireRadius?: number` — Radius of the circular wire profile. Required unless a custom profile is passed.
166
- - `profileSegments?: number` — Segment count for the default circular wire profile. Default 24.
167
- - `divisionsPerTurn?: number` — Sweep path samples per turn. Default 32.
254
+ #### `Loft.leftRail()` — Create a guide rail that constrains the section-local negative-X side.
168
255
 
169
- #### `hermiteTransitionG2()` — Create a quintic Hermite transition curve between two edge endpoints (G2 continuity).
256
+ ```ts
257
+ Loft.leftRail(path: LoftGuideRailPath): LoftGuideRail
258
+ ```
259
+
260
+ `LoftGuideRail`: `{ side: LoftGuideRailSide, path: LoftGuideRailPath }`
170
261
 
171
- The curve starts at `a.point` tangent to `a.tangent` with curvature `a.curvature`, and ends at `b.point` tangent to `b.tangent` with curvature `b.curvature`, with smooth G2-continuous interpolation matching position, tangent, and curvature.
262
+ #### `Loft.rightRail()` Create a guide rail that constrains the section-local positive-X side.
172
263
 
173
264
  ```ts
174
- hermiteTransitionG2(a: QuinticHermiteCurveEndpoint, b: QuinticHermiteCurveEndpoint): QuinticHermiteCurve3D
265
+ Loft.rightRail(path: LoftGuideRailPath): LoftGuideRail
175
266
  ```
176
267
 
177
- **`QuinticHermiteCurveEndpoint`**
268
+ #### `Loft.frontRail()` — Create a guide rail that constrains the section-local positive-Y side.
178
269
 
179
- | Option | Type | Description |
180
- |--------|------|-------------|
181
- | `point` | `Vec3` | Position |
182
- | `tangent` | `Vec3` | Tangent direction (will be normalized internally) |
183
- | `curvature?` | `Vec3` | Second derivative / curvature vector. Default [0, 0, 0]. |
184
- | `weight?` | `number` | Weight: scales tangent magnitude relative to chord length. Default 1.0. |
270
+ ```ts
271
+ Loft.frontRail(path: LoftGuideRailPath): LoftGuideRail
272
+ ```
185
273
 
186
- #### `nurbs3d()` — Create a NURBS curve from control points.
274
+ #### `Loft.backRail()` — Create a guide rail that constrains the section-local negative-Y side.
187
275
 
188
- With default options, creates a cubic non-rational B-spline with uniform clamped knots. Set `weights` for rational curves (exact circles, conics). Set `degree` for linear (1), quadratic (2), cubic (3), or higher-order curves.
276
+ ```ts
277
+ Loft.backRail(path: LoftGuideRailPath): LoftGuideRail
278
+ ```
189
279
 
190
- ```js
191
- // Simple cubic B-spline through control points
192
- const curve = nurbs3d([[0,0,0], [10,5,0], [20,-5,10], [30,0,5]]);
193
- const tube = sweep(circle(2), curve);
280
+ #### `Loft.centerRail()` — Create a guide rail that moves section centers along the loft.
281
+
282
+ ```ts
283
+ Loft.centerRail(path: LoftGuideRailPath): LoftGuideRail
194
284
  ```
195
285
 
196
- ```js
197
- // Rational quadratic — exact circular arc
198
- const arc = nurbs3d(
199
- [[10,0,0], [10,10,0], [0,10,0]],
200
- { degree: 2, weights: [1, Math.SQRT1_2, 1] }
201
- );
286
+ #### `Loft.pathOnXz()` — Place a 2D guide path onto the XZ plane.
287
+
288
+ The path's first coordinate becomes X and its second coordinate becomes Z. Use this for left/right silhouette rails authored with [`path()`](/docs/sketch#path) or [`constrainedSketch()`](/docs/sketch#constrainedsketch).
289
+
290
+ ```ts
291
+ Loft.pathOnXz(path: LoftPath2D, y?: number): Vec3[]
202
292
  ```
203
293
 
294
+ #### `Loft.pathOnYz()` — Place a 2D guide path onto the YZ plane.
295
+
296
+ The path's first coordinate becomes Y and its second coordinate becomes Z. Use this for front/back crown rails authored with [`path()`](/docs/sketch#path) or [`constrainedSketch()`](/docs/sketch#constrainedsketch).
297
+
204
298
  ```ts
205
- nurbs3d(points: Vec3[], options?: NurbsCurve3DOptions): NurbsCurve3D
299
+ Loft.pathOnYz(path: LoftPath2D, x?: number): Vec3[]
206
300
  ```
207
301
 
208
- **`NurbsCurve3DOptions`**
302
+ #### `Loft.pathOnXy()` — Place a 2D guide path onto the XY plane.
209
303
 
210
- | Option | Type | Description |
211
- |--------|------|-------------|
212
- | `degree?` | `number` | Polynomial degree (default 3 = cubic). Must be ≥ 1. |
213
- | `weights?` | `number[]` | Rational weights, one per control point (default: all 1.0 = non-rational). |
214
- | `knots?` | `number[]` | Knot vector (default: uniform clamped). Must have length = controlPoints.length + degree + 1. |
215
- | `closed?` | `boolean` | Whether the curve is closed/periodic (default false). |
304
+ 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.
305
+
306
+ ```ts
307
+ Loft.pathOnXy(path: LoftPath2D, z?: number): Vec3[]
308
+ ```
309
+
310
+ #### `Loft.withGuideRails()` — Loft through profile stations while forcing generated sections to follow guide rails.
311
+
312
+ 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.
313
+
314
+ ```ts
315
+ Loft.withGuideRails(stations: LoftStation[], rails: LoftGuideRail[], options?: LoftWithGuideRailsOptions): Shape
316
+ ```
317
+
318
+ **`LoftOptions`**
319
+ - `edgeLength?: number` — Marching-grid edge length for level-set meshing. Smaller = finer.
320
+ - `boundsPadding?: number` — Optional extra bounds padding.
321
+
322
+ **`LoftWithGuideRailsOptions`** extends LoftOptions
323
+ - `axis?: LoftAxis` — Primary station axis. Default Z.
324
+ - `samples?: number` — Number of generated loft stations including ends. Default scales with station count.
325
+ - `railSamples?: number` — Number of points sampled from curve-backed rails before axis interpolation. Default 64.
216
326
 
217
327
  #### `spline2d()` — Build a smooth Catmull-Rom spline sketch from 2D control points.
218
328
 
@@ -232,18 +342,6 @@ spline2d(points: Vec2[], options?: Spline2DOptions): Sketch
232
342
  | `strokeWidth?` | `number` | For open splines, provide stroke width to return a solid Sketch. If omitted for open splines, an error is thrown. |
233
343
  | `join?` | `"Round" \| "Square"` | Stroke join for open splines. Default 'Round'. |
234
344
 
235
- #### `spline3d()` — Create a reusable 3D spline curve object (Catmull-Rom).
236
-
237
- The returned Curve3D provides sample(), pointAt(t), tangentAt(t), and length() for downstream use in sweep() or manual path operations.
238
-
239
- ```ts
240
- spline3d(points: Vec3[], options?: Spline3DOptions): Curve3D
241
- ```
242
-
243
- **`Spline3DOptions`**
244
- - `closed?: boolean` — Closed loop (default false).
245
- - `tension?: number` — Catmull-Rom tension in [0, 1]. 0 = very round, 1 = linear-ish. Default 0.5.
246
-
247
345
  #### `loft()` — Loft between multiple sketches along Z stations.
248
346
 
249
347
  Profiles can differ in topology and vertex count: interpolation is done on signed-distance fields and meshed with level-set extraction. Heights must be strictly increasing. Compatible loft stacks can also stay on the maintained export-backend path.
@@ -254,29 +352,6 @@ Performance note: loft is significantly heavier than primitive/extrude/revolve.
254
352
  loft(profiles: Sketch[], heights: number[], options?: LoftOptions): Shape
255
353
  ```
256
354
 
257
- #### `loftAlongSpine()` — Loft between multiple profiles positioned along an arbitrary 3D spine curve.
258
-
259
- 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.
260
-
261
- The tValues array specifies where each profile sits along the spine (0 = start, 1 = end). Must have the same length as profiles and be in [0, 1].
262
-
263
- Internally uses variableSweep infrastructure with SDF interpolation.
264
-
265
- Performance note: uses level-set meshing, heavier than simple loft().
266
-
267
- ```ts
268
- loftAlongSpine(profiles: Sketch[], spine: Curve3D | Vec3[], tValues: number[], options?: LoftAlongSpineOptions): Shape
269
- ```
270
-
271
- **`LoftAlongSpineOptions`**
272
-
273
- | Option | Type | Description |
274
- |--------|------|-------------|
275
- | `samples?` | `number` | Number of samples when spine is a Curve3D. Default 48. |
276
- | `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
277
- | `boundsPadding?` | `number` | Optional extra bounds padding. |
278
- | `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
279
-
280
355
  #### `sweep()`
281
356
 
282
357
  ```ts
@@ -400,106 +475,6 @@ surfacePatch(curves: { ... }, options?: SurfacePatchOptions): Shape
400
475
  - `thickness?: number` — Thickness of the generated solid. Default 0 for an open exact sheet.
401
476
  - `approximate?: boolean` — Allow explicit approximation for non-exact curve inputs such as Curve3D samples.
402
477
 
403
- #### `transitionCurve()` — Create a smooth transition curve between two edges.
404
-
405
- Returns a `HermiteCurve3D` that starts at `edgeA.point` tangent to `edgeA.tangent` and ends at `edgeB.point` tangent to `edgeB.tangent`.
406
-
407
- The curve maintains G1 continuity (matching tangent direction) at both endpoints. Weight parameters control the shape of the transition.
408
-
409
- ```js
410
- // Connect two edges with a balanced transition
411
- const curve = transitionCurve(
412
- { point: [0, 0, 0], tangent: [1, 0, 0] },
413
- { point: [10, 5, 0], tangent: [1, 0, 0] },
414
- );
415
- ```
416
-
417
- // Weighted: curve hugs edge A longer const weighted = transitionCurve( { point: [0, 0, 0], tangent: [1, 0, 0] }, { point: [10, 5, 0], tangent: [1, 0, 0] }, { weightA: 2.0, weightB: 0.5 }, );
418
-
419
- ```
420
-
421
- ```ts
422
- transitionCurve(edgeA: TransitionEdge, edgeB: TransitionEdge, options?: TransitionCurveOptions): HermiteCurve3D
423
- ```
424
-
425
- **`TransitionEdge`**
426
- - `point: Vec3` — Connection point on the edge. Can be any point along the edge where the transition should connect.
427
- - `tangent: Vec3` — Tangent direction at the connection point. This is the direction the curve should initially follow when leaving this edge. For a straight edge, this is typically the edge direction pointing "outward" (away from the body of the edge, toward the other edge).
428
- - `normal?: Vec3` — Surface normal at the connection point (optional). Used as a hint for the sweep frame's up vector.
429
-
430
- **`TransitionCurveOptions`**
431
- - `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
432
- - `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
433
- - `samples?: number` — Number of sample points for the output polyline. Default 64. Higher values give smoother curves at the cost of more geometry.
434
-
435
- #### `transitionSurface()` — Create a solid transition surface between two edges by sweeping a profile along a Hermite transition curve.
436
-
437
- This produces a watertight solid that smoothly connects the two edges. Works with both Manifold and OCCT backends.
438
-
439
- ```js
440
- // Circular tube connecting two edges
441
- const tube = transitionSurface(
442
- { point: [0, 0, 0], tangent: [1, 0, 0] },
443
- { point: [10, 5, 3], tangent: [0, 1, 0] },
444
- { radius: 0.5 },
445
- );
446
- ```
447
-
448
- // Custom profile with weights const custom = transitionSurface( { point: [0, 0, 0], tangent: [1, 0, 0] }, { point: [10, 5, 3], tangent: [0, 1, 0] }, { profile: mySketch, weightA: 1.5, weightB: 0.8 }, );
449
-
450
- ```
451
-
452
- ```ts
453
- transitionSurface(edgeA: TransitionEdge, edgeB: TransitionEdge, options?: TransitionSurfaceOptions): Shape
454
- ```
455
-
456
-
457
- **`TransitionSurfaceOptions`** extends TransitionCurveOptions
458
-
459
- | Option | Type | Description |
460
- |--------|------|-------------|
461
- | `profile?` | `Sketch` | Cross-section profile to sweep along the transition curve. If omitted, a circular profile with `radius` is used. |
462
- | `radius?` | `number` | Radius of circular cross-section (used when `profile` is omitted). Default: 5% of chord length. |
463
- | `rectangleSection?` | `{ width: number; height: number; }` | Width and height for rectangular cross-section. Alternative to `radius` when `profile` is omitted. |
464
- | `up?` | `Vec3` | Preferred up vector for the sweep frame. Default: auto-detected. |
465
- | `edgeLength?` | `number` | Edge length for level-set meshing. Smaller = finer. |
466
- | `boundsPadding?` | `number` | Extra bounds padding for level-set meshing. |
467
-
468
- #### `connectEdges()` — Create a transition surface or solid bridge between two edge segments.
469
-
470
- Tangents can be inferred from neighboring geometry or supplied explicitly through `options`. This is useful for loft-like blends where you want a direct connection between two edge spans.
471
-
472
- ```ts
473
- connectEdges(edgeA: EdgeSegment, edgeB: EdgeSegment, options?: ConnectEdgesOptions): Shape
474
- ```
475
-
476
- **`EdgeSegment`**
477
-
478
- | Option | Type | Description |
479
- |--------|------|-------------|
480
- | `index` | `number` | Stable index within the extraction (deterministic for a given mesh). |
481
- | `direction` | `Vec3` | Normalized direction from start → end. |
482
- | `dihedralAngle` | `number` | Dihedral angle in degrees (0 = coplanar, 180 = knife edge). |
483
- | `convex` | `boolean` | true = outside corner (convex), false = inside corner (concave). |
484
- | `normalA` | `Vec3` | Normal of first adjacent face. |
485
- | `normalB` | `Vec3` | Normal of second adjacent face (same as normalA for boundary edges). |
486
- | `boundary` | `boolean` | true if this is a boundary (unmatched) edge — unusual for closed solids. |
487
- | `start`, `end`, `midpoint`, `length` | | — |
488
-
489
-
490
- **`ConnectEdgesOptions`** extends TransitionSurfaceOptions
491
-
492
- | Option | Type | Description |
493
- |--------|------|-------------|
494
- | `endA?` | `EdgeEnd` | Which end of edge A to connect. Default: 'start'. |
495
- | `endB?` | `EdgeEnd` | Which end of edge B to connect. Default: 'start'. |
496
- | `tangentModeA?` | `TangentMode` | Tangent mode for edge A. Default: 'along'. |
497
- | `tangentModeB?` | `TangentMode` | Tangent mode for edge B. Default: 'along'. |
498
- | `tangentA?` | `Vec3` | Explicit tangent for edge A. |
499
- | `tangentB?` | `Vec3` | Explicit tangent for edge B. |
500
- | `flipA?` | `boolean` | Flip tangent A. |
501
- | `flipB?` | `boolean` | Flip tangent B. |
502
-
503
478
  ### Surface Members
504
479
 
505
480
  #### `surfaceBand()`
@@ -579,47 +554,76 @@ tangentAt(t: number): Vec3
579
554
  length(samples?: number): number
580
555
  ```
581
556
 
582
- ### `HelixCurve`
557
+ ### `Route3D`
583
558
 
584
- Metadata-bearing helical curve around the Z axis. Use `Helix.path(...)` for sampling, placement, or `sweep()`, and `Helix.coil(...)` for helix-oriented solids.
559
+ Metadata-bearing analytic 3D route made from line and arc segments.
585
560
 
586
- **Properties:**
561
+ Use `Curve.Route.fromPolyline()` when you know the virtual design skeleton points and bend radius. ForgeCAD computes tangent trim points, bend arcs, total length, and named start/end port frames. Pass the route directly to `sweep()`.
587
562
 
588
- | Property | Type | Description |
589
- |----------|------|-------------|
590
- | `radius` | `number` | |
591
- | `pitch` | `number` | |
592
- | `turns` | `number` | — |
593
- | `height` | `number` | — |
594
- | `startAngle` | `number` | — |
595
- | `clockwise` | `boolean` | — |
563
+ ```js
564
+ const route = Curve.Route.fromPolyline(
565
+ [[0, 0, 0], [0, 0, 80], [60, 0, 80]],
566
+ { cornerRadius: 24, startPort: "inlet", endPort: "outlet" },
567
+ );
568
+ const pipe = sweep(difference2d(circle2d(8), circle2d(6)), route);
569
+ const outlet = route.port("outlet");
570
+ ```
596
571
 
597
- **Methods:**
572
+ #### `fromPolyline()` — Build a line/arc route from virtual polyline corner points.
598
573
 
599
- #### `pointAt()`
574
+ ```ts
575
+ static fromPolyline(points: Route3DVec3[], options?: Route3DFromPolylineOptions): Route3D
576
+ ```
577
+
578
+ **`Route3DFromPolylineOptions`**
579
+
580
+ | Option | Type | Description |
581
+ |--------|------|-------------|
582
+ | `cornerRadius?` | `number` | Bend radius applied to every virtual interior corner. Default 0 keeps sharp polyline corners. |
583
+ | `startPort?` | `string` | Name for the start port. Default "start". |
584
+ | `endPort?` | `string` | Name for the end port. Default "end". |
585
+ | `up?` | `Vec3` | Preferred up vector for deterministic port frames. Default [0, 0, 1]. |
586
+
587
+ #### `length()` — Total centerline length, including line and bend arc segments.
600
588
 
601
589
  ```ts
602
- pointAt(t: number): Vec3
590
+ get length(): number
603
591
  ```
604
592
 
605
- #### `tangentAt()`
593
+ #### `segments()` — Exact line and arc segments that make up this route.
606
594
 
607
595
  ```ts
608
- tangentAt(t: number): Vec3
596
+ get segments(): Route3DSegment[]
609
597
  ```
610
598
 
611
- #### `sample()`
599
+ #### `ports()` — Named port frames, keyed by port name.
612
600
 
613
601
  ```ts
614
- sample(count?: number): Vec3[]
602
+ get ports(): Record<string, RoutePortFrame>
615
603
  ```
616
604
 
617
- #### `length()`
605
+ #### `port()` — Return one named route port frame.
618
606
 
619
607
  ```ts
620
- length(): number
608
+ port(name: string): RoutePortFrame
621
609
  ```
622
610
 
611
+ #### `toSweepPathPlan()` — Convert this route to the compile plan consumed by sweep().
612
+
613
+ ```ts
614
+ toSweepPathPlan(): SweepPathCompilePlan
615
+ ```
616
+
617
+ #### `toPolyline()` — Sample this analytic route as a polyline for inspection or backend lowering.
618
+
619
+ ```ts
620
+ toPolyline(options?: number | Route3DToPolylineOptions): Route3DVec3[]
621
+ ```
622
+
623
+ **`Route3DToPolylineOptions`**
624
+ - `samples?: number` — Approximate target point count for the full route.
625
+ - `maxAngleDeg?: number` — Maximum angular spacing on arc segments. Default 6 degrees.
626
+
623
627
  ### `NurbsCurve3D`
624
628
 
625
629
  **Properties:**
@@ -993,120 +997,6 @@ toPolyline(): [ number, number ][]
993
997
  closeOffset(delta: number, join?: "Round" | "Square" | "Miter"): Sketch
994
998
  ```
995
999
 
996
- ### `HermiteCurve3D`
997
-
998
- **Properties:**
999
-
1000
- | Property | Type | Description |
1001
- |----------|------|-------------|
1002
- | `p0` | `Vec3` | Start position |
1003
- | `p1` | `Vec3` | End position |
1004
- | `t0` | `Vec3` | Scaled tangent at start (direction * weight * chordLength) |
1005
- | `t1` | `Vec3` | Scaled tangent at end (direction * weight * chordLength) |
1006
- | `chordLength` | `number` | Chord length (straight-line distance between endpoints) |
1007
-
1008
- **Methods:**
1009
-
1010
- #### `pointAt()` — Evaluate position at parameter t ∈ [0, 1]
1011
-
1012
- ```ts
1013
- pointAt(t: number): Vec3
1014
- ```
1015
-
1016
- #### `tangentAt()` — Evaluate tangent (first derivative) at parameter t ∈ [0, 1]
1017
-
1018
- ```ts
1019
- tangentAt(t: number): Vec3
1020
- ```
1021
-
1022
- #### `curvatureAt()` — Evaluate curvature vector (second derivative) at parameter t ∈ [0, 1]
1023
-
1024
- ```ts
1025
- curvatureAt(t: number): Vec3
1026
- ```
1027
-
1028
- #### `sample()` — Sample the curve as a polyline of evenly-spaced parameter values.
1029
-
1030
- ```ts
1031
- sample(count?: number): Vec3[]
1032
- ```
1033
-
1034
- #### `length()` — Approximate arc length by sampling.
1035
-
1036
- ```ts
1037
- length(samples?: number): number
1038
- ```
1039
-
1040
- #### `sampleAdaptive()` — Sample with adaptive density — more points where curvature is higher. Returns at least `minCount` points, up to `maxCount`.
1041
-
1042
- ```ts
1043
- sampleAdaptive(minCount?: number, maxCount?: number): Vec3[]
1044
- ```
1045
-
1046
- #### `toPolyline()` — Convert to a format compatible with sweep() path input.
1047
-
1048
- ```ts
1049
- toPolyline(samples?: number): Vec3[]
1050
- ```
1051
-
1052
- ### `QuinticHermiteCurve3D`
1053
-
1054
- **Properties:**
1055
-
1056
- | Property | Type | Description |
1057
- |----------|------|-------------|
1058
- | `p0` | `Vec3` | Start position |
1059
- | `p1` | `Vec3` | End position |
1060
- | `t0` | `Vec3` | Scaled tangent at start (direction * weight * chordLength) |
1061
- | `t1` | `Vec3` | Scaled tangent at end (direction * weight * chordLength) |
1062
- | `c0` | `Vec3` | Scaled second derivative at start (curvature * weight² * chordLength²) |
1063
- | `c1` | `Vec3` | Scaled second derivative at end (curvature * weight² * chordLength²) |
1064
- | `chordLength` | `number` | Chord length (straight-line distance between endpoints) |
1065
-
1066
- **Methods:**
1067
-
1068
- #### `pointAt()` — Evaluate position at parameter t ∈ [0, 1]
1069
-
1070
- ```ts
1071
- pointAt(t: number): Vec3
1072
- ```
1073
-
1074
- #### `tangentAt()` — Evaluate tangent (first derivative, normalized) at parameter t ∈ [0, 1]
1075
-
1076
- ```ts
1077
- tangentAt(t: number): Vec3
1078
- ```
1079
-
1080
- #### `curvatureAt()` — Evaluate curvature vector (second derivative) at parameter t ∈ [0, 1]
1081
-
1082
- ```ts
1083
- curvatureAt(t: number): Vec3
1084
- ```
1085
-
1086
- #### `sample()` — Sample the curve as a polyline of evenly-spaced parameter values.
1087
-
1088
- ```ts
1089
- sample(count?: number): Vec3[]
1090
- ```
1091
-
1092
- #### `length()` — Approximate arc length by sampling.
1093
-
1094
- ```ts
1095
- length(samples?: number): number
1096
- ```
1097
-
1098
- #### `sampleAdaptive()` — Sample with adaptive density — more points where curvature is higher. Returns at least `minCount` points, up to `maxCount`.
1099
-
1100
- ```ts
1101
- sampleAdaptive(minCount?: number, maxCount?: number): Vec3[]
1102
- ```
1103
-
1104
- #### `toPolyline()` — Convert to a format compatible with sweep() path input.
1105
-
1106
- ```ts
1107
- toPolyline(samples?: number): Vec3[]
1108
- ```
1109
-
1110
1000
  ### `ProductSkin`
1111
1001
 
1112
1002
  **Properties:**
@@ -1539,7 +1429,6 @@ attachTo(ref: ProductRefInput, options?: ProductPanelAttachOptions): Shape
1539
1429
 
1540
1430
  `ProductSurfaceRef`
1541
1431
 
1542
-
1543
1432
  `ProductPanelAttachOptions`: `{ at?: Partial<ProductSkinRefQuery>, thickness?: number, material?: ProductMaterial, color?: string }`
1544
1433
 
1545
1434
  ### `ProductRibbonBuilder`
@@ -1863,6 +1752,8 @@ bottom(options?: { angle?: number; offset?: number; }): SurfaceAnchor<CylinderSu
1863
1752
  pointAt(coordinate: CylinderSurfaceCoordinate): Vec3
1864
1753
  ```
1865
1754
 
1755
+ `CylinderSurfaceCoordinate`: `{ kind?: "cylinder", angle: number, z: number, offset?: number }`
1756
+
1866
1757
  #### `mirrorPoint()`
1867
1758
 
1868
1759
  ```ts
@@ -1982,6 +1873,8 @@ bottom(options?: { x?: number; offset?: number; }): SurfaceAnchor<PlaneSurfaceCo
1982
1873
  pointAt(coordinate: PlaneSurfaceCoordinate): Vec3
1983
1874
  ```
1984
1875
 
1876
+ `PlaneSurfaceCoordinate`: `{ kind?: "plane", x: number, y: number, offset?: number }`
1877
+
1985
1878
  #### `mirrorPoint()`
1986
1879
 
1987
1880
  ```ts
@@ -2266,6 +2159,8 @@ boundaries(samples?: number): SurfaceBandBoundarySample[]
2266
2159
  withHole(name: string, input: SurfaceBandHoleInput): SurfaceBand<C>
2267
2160
  ```
2268
2161
 
2162
+ `SurfaceBandHoleInput`: `{ length: number, width: number, along?: number, across?: number }`
2163
+
2269
2164
  #### `holes()` — Resolve recorded hole regions into member-local across/along loops.
2270
2165
 
2271
2166
  ```ts
@@ -2288,6 +2183,8 @@ holes(): SurfaceBandHoleRegion[]
2288
2183
  carrier(carrier: CarrierSurface): this
2289
2184
  ```
2290
2185
 
2186
+ `CarrierSurface`: `{ name: string, kind: SurfaceCarrierKind }`
2187
+
2291
2188
  #### `member()`
2292
2189
 
2293
2190
  ```ts
@@ -2332,6 +2229,8 @@ band(): this
2332
2229
  at(anchor: SurfaceAnchor<C>): this
2333
2230
  ```
2334
2231
 
2232
+ `SurfaceAnchor`: `{ carrier: CarrierSurface<C>, coordinate: C }`
2233
+
2335
2234
  #### `size()`
2336
2235
 
2337
2236
  ```ts
@@ -2350,6 +2249,10 @@ path(path: SurfacePath<C> | SurfacePathBuilder<C>): this
2350
2249
  section(section: MemberSectionInput): this
2351
2250
  ```
2352
2251
 
2252
+ **`MemberSectionInput`**: `width?: number`, `thickness: number`, `edgeRadius?: number`, `direction?: MemberOutwardDirection`, `material?: ProductMaterial`, `stations?: MemberSectionStation[]`
2253
+
2254
+ `MemberSectionStation`: `{ t: number, width?: number, thickness?: number }`
2255
+
2353
2256
  #### `cap()`
2354
2257
 
2355
2258
  ```ts
@@ -2362,6 +2265,8 @@ cap(style: SurfaceBandCap): this
2362
2265
  slot(name: string, feature: MemberFeature | RoundedSlotBuilder): this
2363
2266
  ```
2364
2267
 
2268
+ **`MemberFeature`**: `type: MemberFeatureType`, `name?: string`, `length?: number`, `width?: number`, `diameter?: number`, `counterboreDiameter?: number`, `clearanceDiameter?: number`, `height?: number`, `depth?: number`, `count?: number`, `along?: number`, `across?: number`, `verticalTravel?: number`
2269
+
2365
2270
  #### `cutout()`
2366
2271
 
2367
2272
  ```ts
@@ -2486,6 +2391,25 @@ toFeature(name?: string): MemberFeature
2486
2391
 
2487
2392
  ## Constants
2488
2393
 
2394
+ ### `Curve`
2395
+
2396
+ Canonical exact/smooth 3D curve constructors.
2397
+
2398
+ `Curve.*` is the public home for reference curves and route centerlines that feed `sweep`, `variableSweep`, route visualization, and future path consumers. Standalone 3D curve constructors have been collapsed into this namespace.
2399
+
2400
+ - `Blend(start: CurveBlendEndpoint, end: CurveBlendEndpoint): NurbsCurve3D` — Create an exact G1 blend curve between two directed endpoints. The returned curve is a cubic non-rational `NurbsCurve3D`: ForgeCAD converts the endpoint positions and tangents into Bezier control points, so the curve can feed `sweep` and exact surface boundaries through the existing `nurbs` IR rather than a sampled polyline.
2401
+ - `BlendG2(start: CurveBlendG2Endpoint, end: CurveBlendG2Endpoint): NurbsCurve3D` — Create an exact G2 blend curve between two directed endpoints. This is the curvature-aware companion to `Curve.Blend()`. It returns a degree-5 non-rational `NurbsCurve3D` that matches endpoint position, tangent direction, and optional curvature/second-derivative vectors.
2402
+ - `Arc(options: CurveArcOptions): NurbsCurve3D` — Create an exact circular 3D arc from start, end, and start tangent. The returned curve is a rational quadratic `NurbsCurve3D`, split into stable spans when needed, so it can feed `sweep` without sampling the authoring intent away.
2403
+ - `Line(start: Vec3, end: Vec3): NurbsCurve3D` — Create an exact straight 3D NURBS line segment.
2404
+ - `Polyline(points: Vec3[]): Vec3[]` — Create a polyline path as cloned 3D points. Polylines are exact as route/path input to `sweep`. Use `Curve.Route` when the centerline needs bend and endpoint-frame metadata.
2405
+ - `Spline(points: Vec3[], options?: Spline3DOptions): Curve3D` — Create a smooth Catmull-Rom spline path. This is a smooth sampled curve object. Use `Curve.Nurbs` when the path must preserve exact control-point and knot data.
2406
+ - `Nurbs(points: Vec3[], options?: NurbsCurve3DOptions): NurbsCurve3D` — Create an exact NURBS 3D curve from control points, weights, knots, and degree.
2407
+ - `Fit(points: Vec3[], options?: CurveFitOptions): NurbsCurve3D` — Fit a non-rational NURBS curve that interpolates every input point. This is global B-spline interpolation, not approximate curve reduction: ForgeCAD computes chord-length parameters, averaged clamped knots, solves the control points, then verifies the interpolation residual against `tolerance`.
2408
+ - `Trim<T extends CurveTrimInput>(curve: T, start: number, end: number): CurveTrimOutput<T>` — Extract an exact curve segment from normalized parameter `start` to `end`. `NurbsCurve3D` inputs are trimmed with exact knot insertion/subdomain extraction. Polyline point arrays are trimmed by arclength over their exact line segments. Sampled `Curve3D` splines are rejected until ForgeCAD has a tolerance-controlled rebuild path.
2409
+ - `Reverse<T extends CurveTrimInput>(curve: T): CurveTrimOutput<T>` — Reverse an exact curve without changing its geometry. `NurbsCurve3D` inputs reverse control points, weights, and knots. Polyline point arrays are cloned and reversed. Sampled `Curve3D` splines are rejected until ForgeCAD has a tolerance-controlled rebuild path.
2410
+ - `Route: typeof Route3D` — Build analytic 3D line/arc routes for sweeps. `Curve.Route.fromPolyline()` is the canonical route API. It returns a `Route3D` value object, preserving exact route segments, named port frames, and the lowerable `route3d` sweep compile plan.
2411
+ - `Helix: { path(options: HelixOptions): CurveHelixPath; coil: CurveHelixCoil; }` — Build helical paths and swept coils. `Curve.Helix` is the canonical namespace for helical paths and coils. It uses the same sweep-based lowering as other curve paths.
2412
+
2489
2413
  ### `Surface`
2490
2414
 
2491
2415
  - `Plane(options: SurfacePlaneOptions): Shape` — Create a finite analytic plane sheet that can be trimmed, sewn, thickened, or used as a low-level face.
@@ -2567,17 +2491,3 @@ toFeature(name?: string): MemberFeature
2567
2491
  ### `Ribs`
2568
2492
 
2569
2493
  - `repeated(input: { count: number; height: number; }): MemberFeature` — Create repeated ribs that belong to a surface member before lowering.
2570
-
2571
- ### `Helix`
2572
-
2573
- Helical curve helpers.
2574
-
2575
- ```ts
2576
- const guide = Helix.path({ radius: 20, pitch: 6, turns: 4 });
2577
- const wire = Helix.coil({ radius: 20, pitch: 6, turns: 4, wireRadius: 1 });
2578
- const rectangular = Helix.coil(rect(2, 1), { radius: 20, height: 30, turns: 5 });
2579
- ```
2580
-
2581
- - `path(options: HelixOptions): HelixCurve` — Create a metadata-bearing helical centerline around the Z axis.
2582
- - `coil(options: HelixCoilOptions): Shape` — Create a solid helical coil by sweeping a circular profile through helix-local frames.
2583
- - `coil(profile: Sketch, options: HelixCoilOptions): Shape` — Create a solid helical coil by sweeping a profile through helix-local frames.