forgecad 0.6.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +3 -12
  2. package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-D4bocK4E.js} +250 -151
  3. package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
  4. package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-D3A_g8V3.js} +329 -163
  5. package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-BWYUSpUN.css} +590 -136
  6. package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
  7. package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-kWjKaC_t.js} +2 -4
  8. package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
  9. package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
  10. package/dist/assets/PricingPage-BsU5vzEx.js +232 -0
  11. package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-PqvpAKIs.js} +129 -5
  12. package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-C-hzNUMy.js} +8949 -3161
  13. package/dist/assets/{Viewport-CoB46f5R.js → index-Pz321YAt.js} +38382 -7501
  14. package/dist/assets/{index-2hfs_ub0.css → index-ay13WNfa.css} +726 -53
  15. package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
  16. package/dist/assets/{manifold-CqNMHHKO.js → manifold-BcbjWLIo.js} +4 -3
  17. package/dist/assets/{manifold-Cce9wRFz.js → manifold-DBckbFgx.js} +1 -1
  18. package/dist/assets/{manifold-D6BeHIOo.js → manifold-O2AAGXyj.js} +1 -1
  19. package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-Dxr-5A7w.js} +8760 -3559
  20. package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
  21. package/dist/docs/index.html +2 -2
  22. package/dist/docs-raw/CLI.md +341 -718
  23. package/dist/docs-raw/generated/assembly.md +699 -112
  24. package/dist/docs-raw/generated/concepts.md +1834 -1346
  25. package/dist/docs-raw/generated/core.md +1012 -1059
  26. package/dist/docs-raw/generated/curves.md +759 -116
  27. package/dist/docs-raw/generated/lib.md +43 -748
  28. package/dist/docs-raw/generated/output.md +139 -245
  29. package/dist/docs-raw/generated/sdf.md +208 -0
  30. package/dist/docs-raw/generated/sheet-metal.md +473 -21
  31. package/dist/docs-raw/generated/sketch.md +1518 -362
  32. package/dist/docs-raw/generated/viewport.md +368 -299
  33. package/dist/docs-raw/generated/wood.md +104 -0
  34. package/dist/index.html +2 -2
  35. package/dist/landing/proof-ams-adapter.png +0 -0
  36. package/dist/landing/proof-bolt-and-nut.png +0 -0
  37. package/dist/landing/proof-fillet-enclosure.png +0 -0
  38. package/dist/landing/proof-glasses.png +0 -0
  39. package/dist/landing/proof-gyroid.png +0 -0
  40. package/dist/sitemap.xml +6 -6
  41. package/dist-cli/forgecad.js +12321 -5700
  42. package/dist-cli/forgecad.js.map +1 -0
  43. package/dist-cli/solver-46FFSK2U.js +363 -0
  44. package/dist-cli/solver-46FFSK2U.js.map +1 -0
  45. package/dist-skill/CONTEXT.md +4890 -6302
  46. package/dist-skill/SKILL-dev.md +22 -66
  47. package/dist-skill/SKILL.md +20 -59
  48. package/dist-skill/docs/API/core/concepts.md +37 -92
  49. package/dist-skill/docs/CLI.md +341 -718
  50. package/dist-skill/docs/generated/assembly.md +699 -112
  51. package/dist-skill/docs/generated/core.md +1012 -1059
  52. package/dist-skill/docs/generated/curves.md +759 -116
  53. package/dist-skill/docs/generated/lib.md +43 -748
  54. package/dist-skill/docs/generated/output.md +139 -245
  55. package/dist-skill/docs/generated/sdf.md +208 -0
  56. package/dist-skill/docs/generated/sheet-metal.md +473 -21
  57. package/dist-skill/docs/generated/sketch.md +1518 -362
  58. package/dist-skill/docs/generated/viewport.md +368 -299
  59. package/dist-skill/docs/generated/wood.md +104 -0
  60. package/dist-skill/docs/guides/coordinate-system.md +11 -17
  61. package/dist-skill/docs/guides/geometry-conventions.md +13 -70
  62. package/dist-skill/docs/guides/joint-design.md +78 -0
  63. package/dist-skill/docs/guides/modeling-recipes.md +22 -195
  64. package/dist-skill/docs/guides/positioning.md +88 -147
  65. package/dist-skill/docs-dev/API/core/concepts.md +78 -0
  66. package/dist-skill/docs-dev/CLI.md +488 -0
  67. package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
  68. package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
  69. package/dist-skill/{docs → docs-dev}/coding.md +2 -4
  70. package/dist-skill/docs-dev/component-model.md +164 -0
  71. package/dist-skill/docs-dev/generated/assembly.md +779 -0
  72. package/dist-skill/docs-dev/generated/core.md +1676 -0
  73. package/dist-skill/docs-dev/generated/curves.md +855 -0
  74. package/dist-skill/docs-dev/generated/lib.md +55 -0
  75. package/dist-skill/docs-dev/generated/output.md +234 -0
  76. package/dist-skill/docs-dev/generated/sdf.md +208 -0
  77. package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
  78. package/dist-skill/docs-dev/generated/sketch.md +1753 -0
  79. package/dist-skill/docs-dev/generated/viewport.md +513 -0
  80. package/dist-skill/docs-dev/generated/wood.md +104 -0
  81. package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
  82. package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
  83. package/dist-skill/docs-dev/guides/joint-design.md +78 -0
  84. package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
  85. package/dist-skill/docs-dev/guides/positioning.md +151 -0
  86. package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
  87. package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
  88. package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
  89. package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
  90. package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
  91. package/examples/api/attachTo-basics.forge.js +8 -8
  92. package/examples/api/bill-of-materials.forge.js +9 -9
  93. package/examples/api/bolt-pattern.forge.js +5 -5
  94. package/examples/api/boolean-operations.forge.js +5 -5
  95. package/examples/api/bounding-box-visualizer.forge.js +3 -3
  96. package/examples/api/clone-duplicate.forge.js +2 -2
  97. package/examples/api/colors-union-vs-array.forge.js +6 -6
  98. package/examples/api/connector-assembly.forge.js +8 -6
  99. package/examples/api/connector-basics.forge.js +7 -7
  100. package/examples/api/constrained-sketch-mechanical.forge.js +4 -4
  101. package/examples/api/elbow-test.forge.js +3 -3
  102. package/examples/api/extrude-options.forge.js +8 -14
  103. package/examples/api/feature-created-faces.forge.js +6 -10
  104. package/examples/api/fillet-showcase.forge.js +2 -2
  105. package/examples/api/folded-service-panel-cover.forge.js +2 -2
  106. package/examples/api/gears-tier1.forge.js +5 -5
  107. package/examples/api/group-test.forge.js +3 -3
  108. package/examples/api/group-vs-union.forge.js +1 -1
  109. package/examples/api/highlight-debug.forge.js +4 -0
  110. package/examples/api/js-module-pillars.js +1 -1
  111. package/examples/api/js-module-scene.js +2 -2
  112. package/examples/api/mesh-import-slats.forge.js +4 -4
  113. package/examples/api/patterns.forge.js +3 -3
  114. package/examples/api/pointAlong-orientation.forge.js +3 -3
  115. package/examples/api/profile-2020-b-slot6.forge.js +4 -5
  116. package/examples/api/route-perimeter-flange.forge.js +1 -1
  117. package/examples/api/sdf-rover-demo.forge.js +10 -10
  118. package/examples/api/sketch-on-face-demo.forge.js +2 -2
  119. package/examples/api/sketch-regions.forge.js +4 -4
  120. package/examples/api/sketch-rounding-strategies.forge.js +1 -1
  121. package/examples/api/smooth-curve-connections.forge.js +1 -1
  122. package/examples/api/transition-curves.forge.js +4 -4
  123. package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
  124. package/examples/api/variable-sweep-test.forge.js +2 -2
  125. package/examples/api/wood-joinery.forge.js +60 -0
  126. package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
  127. package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
  128. package/examples/constraints/01-fully-constrained-rect.forge.js +2 -2
  129. package/examples/constraints/02-underconstrained-triangle.forge.js +1 -1
  130. package/examples/constraints/03-redundant-constraints.forge.js +2 -2
  131. package/examples/constraints/05-parallel-with-linedistance.forge.js +2 -2
  132. package/examples/constraints/06-complex-spectrogram.forge.js +1 -1
  133. package/examples/constraints/07-perpendicular-chain.forge.js +4 -4
  134. package/examples/constraints/08-symmetric-bracket.forge.js +4 -4
  135. package/examples/constraints/09-stress-spiral.forge.js +1 -1
  136. package/examples/constraints/10-stress-honeycomb.forge.js +1 -1
  137. package/examples/constraints/11-surface-grid.forge.js +2 -2
  138. package/examples/constraints/12-surface-nested.forge.js +4 -4
  139. package/examples/constraints/13-surface-complex.forge.js +1 -1
  140. package/examples/exact-arc-housing.forge.js +12 -0
  141. package/examples/experiments/drone-arm.forge.js +53 -0
  142. package/examples/furniture/adjustable-table.forge.js +15 -15
  143. package/examples/furniture/bathroom.forge.js +26 -26
  144. package/examples/furniture/chair.forge.js +13 -13
  145. package/examples/furniture/picture-frame.forge.js +6 -6
  146. package/examples/furniture/shoe-rack-doors.forge.js +8 -8
  147. package/examples/furniture/shoe-rack.forge.js +7 -7
  148. package/examples/furniture/table-lamp.forge.js +8 -8
  149. package/examples/gcode/lissajous-vase.forge.js +4 -4
  150. package/examples/gcode/math-surface.forge.js +3 -3
  151. package/examples/gcode/parametric-vase.forge.js +4 -4
  152. package/examples/gcode/spiral-tower.forge.js +4 -4
  153. package/examples/generative/crystal-growth.forge.js +9 -9
  154. package/examples/generative/frost-spires.forge.js +9 -9
  155. package/examples/generative/golden-spiral-tower.forge.js +11 -11
  156. package/examples/generative/molten-forge.forge.js +6 -6
  157. package/examples/generative/neon-coral.forge.js +7 -7
  158. package/examples/mechanical/3d-printer.forge.js +37 -37
  159. package/examples/mechanical/5-finger-robot-hand.forge.js +19 -19
  160. package/examples/mechanical/airplane-propeller.forge.js +9 -9
  161. package/examples/mechanical/bolt-and-nut.forge.js +10 -10
  162. package/examples/mechanical/door-with-hinges.forge.js +7 -7
  163. package/examples/mechanical/fillet-enclosure.forge.js +15 -11
  164. package/examples/mechanical/headphone-hanger-v2.forge.js +11 -11
  165. package/examples/mechanical/robot_hand.forge.js +24 -24
  166. package/examples/mechanical/robot_hand_2.forge.js +26 -26
  167. package/examples/nurbs-surface.forge.js +8 -0
  168. package/examples/nurbs-tube.forge.js +7 -0
  169. package/examples/products/bottle.forge.js +8 -8
  170. package/examples/products/chess-set.forge.js +25 -25
  171. package/examples/products/classical-piano.forge.js +20 -20
  172. package/examples/products/clock.forge.js +33 -33
  173. package/examples/products/cup.forge.js +5 -5
  174. package/examples/products/iphone.forge.js +20 -20
  175. package/examples/products/laptop.forge.js +24 -24
  176. package/examples/products/laser-cut-box.forge.js +6 -6
  177. package/examples/products/laser-cut-tray.forge.js +6 -6
  178. package/examples/products/liquid-soap-dispenser.forge.js +23 -23
  179. package/examples/products/origami-fish.forge.js +14 -12
  180. package/examples/products/spiderman-cake.forge.js +6 -6
  181. package/examples/shelf/container.forge.js +5 -5
  182. package/examples/shelf/shelf-unit.forge.js +6 -6
  183. package/examples/toolbox/bolted-joint.forge.js +7 -7
  184. package/package.json +9 -4
  185. package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
  186. package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
  187. package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
  188. package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
  189. package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
  190. package/dist/assets/index-1CYp3zUp.js +0 -1455
  191. package/dist-skill/docs/API/API.md +0 -1666
  192. package/dist-skill/docs/API/README.md +0 -37
  193. package/dist-skill/docs/API/assembly/assembly.md +0 -617
  194. package/dist-skill/docs/API/core/edge-queries.md +0 -130
  195. package/dist-skill/docs/API/core/parameters.md +0 -122
  196. package/dist-skill/docs/API/core/reserved-terms.md +0 -137
  197. package/dist-skill/docs/API/core/sdf.md +0 -326
  198. package/dist-skill/docs/API/core/skill-cli.md +0 -194
  199. package/dist-skill/docs/API/core/skill-guide.md +0 -205
  200. package/dist-skill/docs/API/core/specs.md +0 -186
  201. package/dist-skill/docs/API/core/topology.md +0 -372
  202. package/dist-skill/docs/API/entities.md +0 -268
  203. package/dist-skill/docs/API/output/bom.md +0 -58
  204. package/dist-skill/docs/API/output/brep-export.md +0 -87
  205. package/dist-skill/docs/API/output/dimensions.md +0 -67
  206. package/dist-skill/docs/API/output/export.md +0 -110
  207. package/dist-skill/docs/API/output/gcode.md +0 -195
  208. package/dist-skill/docs/API/runtime/viewport.md +0 -420
  209. package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
  210. package/dist-skill/docs/API/sketch/anchor.md +0 -37
  211. package/dist-skill/docs/API/sketch/booleans.md +0 -91
  212. package/dist-skill/docs/API/sketch/core.md +0 -73
  213. package/dist-skill/docs/API/sketch/extrude.md +0 -62
  214. package/dist-skill/docs/API/sketch/on-face.md +0 -104
  215. package/dist-skill/docs/API/sketch/operations.md +0 -78
  216. package/dist-skill/docs/API/sketch/path.md +0 -75
  217. package/dist-skill/docs/API/sketch/primitives.md +0 -146
  218. package/dist-skill/docs/API/sketch/regions.md +0 -80
  219. package/dist-skill/docs/API/sketch/text.md +0 -108
  220. package/dist-skill/docs/API/sketch/transforms.md +0 -65
  221. package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
  222. package/dist-skill/docs/INDEX.md +0 -94
  223. package/dist-skill/docs/RELEASING.md +0 -55
  224. package/dist-skill/docs/cli-monetization.md +0 -111
  225. package/dist-skill/docs/deployment.md +0 -281
  226. package/dist-skill/docs/generated/concepts.md +0 -2112
  227. package/dist-skill/docs/internals/shape-from-slices.md +0 -152
  228. package/dist-skill/docs/platform/admin.md +0 -45
  229. package/dist-skill/docs/platform/architecture.md +0 -79
  230. package/dist-skill/docs/platform/auth.md +0 -110
  231. package/dist-skill/docs/platform/email.md +0 -67
  232. package/dist-skill/docs/platform/projects.md +0 -111
  233. package/dist-skill/docs/platform/sharing.md +0 -90
  234. package/dist-skill/docs/runbook.md +0 -345
@@ -0,0 +1,855 @@
1
+ ---
2
+ skill-group: curves
3
+ skill-order: 100
4
+ ---
5
+
6
+ # Curves & Surfacing
7
+
8
+ Smooth curves, lofted surfaces, swept solids, and splines.
9
+
10
+ ## Contents
11
+
12
+ - [Curves & Surfacing](#curves-surfacing) — `hermiteTransitionG2`, `nurbs3d`, `spline2d`, `spline3d`, `loft`, `loftAlongSpine`, `sweep`, `variableSweep`, `nurbsSurface`, `surfacePatch`, `transitionCurve`, `transitionSurface`, `connectEdges`
13
+ - [Curve3D](#curve3d)
14
+ - [NurbsCurve3D](#nurbscurve3d)
15
+ - [NurbsSurface](#nurbssurface)
16
+ - [PathBuilder](#pathbuilder) — Line Segments, Arcs, Curves, Closing & Output
17
+ - [HermiteCurve3D](#hermitecurve3d)
18
+ - [QuinticHermiteCurve3D](#quintichermitecurve3d)
19
+
20
+ ## Functions
21
+
22
+ ### Curves & Surfacing
23
+
24
+ #### `hermiteTransitionG2()` — Create a quintic Hermite transition curve between two edge endpoints (G2 continuity).
25
+
26
+ 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.
27
+
28
+ ```ts
29
+ hermiteTransitionG2(a: QuinticHermiteCurveEndpoint, b: QuinticHermiteCurveEndpoint): QuinticHermiteCurve3D
30
+ ```
31
+
32
+ **`QuinticHermiteCurveEndpoint`**
33
+
34
+ | Option | Type | Description |
35
+ |--------|------|-------------|
36
+ | `point` | `Vec3` | Position |
37
+ | `tangent` | `Vec3` | Tangent direction (will be normalized internally) |
38
+ | `curvature?` | `Vec3` | Second derivative / curvature vector. Default [0, 0, 0]. |
39
+ | `weight?` | `number` | Weight: scales tangent magnitude relative to chord length. Default 1.0. |
40
+
41
+ #### `nurbs3d()` — Create a NURBS curve from control points.
42
+
43
+ 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.
44
+
45
+ ```js
46
+ // Simple cubic B-spline through control points
47
+ const curve = nurbs3d([[0,0,0], [10,5,0], [20,-5,10], [30,0,5]]);
48
+ const tube = sweep(circle(2), curve);
49
+ ```
50
+
51
+ ```js
52
+ // Rational quadratic — exact circular arc
53
+ const arc = nurbs3d(
54
+ [[10,0,0], [10,10,0], [0,10,0]],
55
+ { degree: 2, weights: [1, Math.SQRT1_2, 1] }
56
+ );
57
+ ```
58
+
59
+ ```ts
60
+ nurbs3d(points: Vec3[], options?: NurbsCurve3DOptions): NurbsCurve3D
61
+ ```
62
+
63
+ **`NurbsCurve3DOptions`**
64
+
65
+ | Option | Type | Description |
66
+ |--------|------|-------------|
67
+ | `degree?` | `number` | Polynomial degree (default 3 = cubic). Must be ≥ 1. |
68
+ | `weights?` | `number[]` | Rational weights, one per control point (default: all 1.0 = non-rational). |
69
+ | `knots?` | `number[]` | Knot vector (default: uniform clamped). Must have length = controlPoints.length + degree + 1. |
70
+ | `closed?` | `boolean` | Whether the curve is closed/periodic (default false). |
71
+
72
+ #### `spline2d()` — Build a smooth Catmull-Rom spline sketch from 2D control points.
73
+
74
+ A closed spline (default) returns a filled profile. An open spline requires a strokeWidth option to produce a solid sketch. Use tension (0..1, default 0.5) to control curve tightness.
75
+
76
+ ```ts
77
+ spline2d(points: Vec2[], options?: Spline2DOptions): Sketch
78
+ ```
79
+
80
+ **`Spline2DOptions`**
81
+
82
+ | Option | Type | Description |
83
+ |--------|------|-------------|
84
+ | `closed?` | `boolean` | Closed loop (default true). |
85
+ | `tension?` | `number` | Catmull-Rom tension in [0, 1]. 0 = very round, 1 = linear-ish. Default 0.5. |
86
+ | `samplesPerSegment?` | `number` | Samples per segment (minimum 3). Default 16. |
87
+ | `strokeWidth?` | `number` | For open splines, provide stroke width to return a solid Sketch. If omitted for open splines, an error is thrown. |
88
+ | `join?` | `"Round" | "Square"` | Stroke join for open splines. Default 'Round'. |
89
+
90
+ #### `spline3d()` — Create a reusable 3D spline curve object (Catmull-Rom).
91
+
92
+ The returned Curve3D provides sample(), pointAt(t), tangentAt(t), and length() for downstream use in sweep() or manual path operations.
93
+
94
+ ```ts
95
+ spline3d(points: Vec3[], options?: Spline3DOptions): Curve3D
96
+ ```
97
+
98
+ **`Spline3DOptions`**
99
+ - `closed?: boolean` — Closed loop (default false).
100
+ - `tension?: number` — Catmull-Rom tension in [0, 1]. 0 = very round, 1 = linear-ish. Default 0.5.
101
+
102
+ #### `loft()` — Loft between multiple sketches along Z stations.
103
+
104
+ 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 export through the OCCT exact route.
105
+
106
+ Performance note: loft is significantly heavier than primitive/extrude/revolve. If the part is axis-symmetric (bottles, vases, knobs), prefer revolve().
107
+
108
+ ```ts
109
+ loft(profiles: Sketch[], heights: number[], options?: LoftOptions): Shape
110
+ ```
111
+
112
+ **`LoftOptions`**
113
+ - `edgeLength?: number` — Marching-grid edge length for level-set meshing. Smaller = finer.
114
+ - `boundsPadding?: number` — Optional extra bounds padding.
115
+
116
+ #### `loftAlongSpine()` — Loft between multiple profiles positioned along an arbitrary 3D spine curve.
117
+
118
+ 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.
119
+
120
+ 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].
121
+
122
+ Internally uses variableSweep infrastructure with SDF interpolation.
123
+
124
+ Performance note: uses level-set meshing, heavier than simple loft().
125
+
126
+ ```ts
127
+ loftAlongSpine(profiles: Sketch[], spine: Curve3D | Vec3[], tValues: number[], options?: LoftAlongSpineOptions): Shape
128
+ ```
129
+
130
+ **`LoftAlongSpineOptions`**
131
+
132
+ | Option | Type | Description |
133
+ |--------|------|-------------|
134
+ | `samples?` | `number` | Number of samples when spine is a Curve3D. Default 48. |
135
+ | `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
136
+ | `boundsPadding?` | `number` | Optional extra bounds padding. |
137
+ | `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
138
+
139
+ #### `sweep()`
140
+
141
+ ```ts
142
+ sweep(profile: Sketch, path: SweepPathInput, options?: SweepOptions): Shape
143
+ ```
144
+
145
+ **`SweepOptions`**
146
+
147
+ | Option | Type | Description |
148
+ |--------|------|-------------|
149
+ | `samples?` | `number` | Number of samples when path is a Curve3D. Default 48. |
150
+ | `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
151
+ | `boundsPadding?` | `number` | Optional extra bounds padding. |
152
+ | `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
153
+
154
+ #### `variableSweep()` — Sweep a variable cross-section along a 3D spine curve.
155
+
156
+ Unlike sweep(), which uses a single constant profile, variableSweep() interpolates between multiple profiles at different stations along the spine. This enables organic shapes like tapering tubes, bone-like structures, and sculptural forms.
157
+
158
+ Each section specifies a t parameter (0 = start, 1 = end of spine) and a 2D profile sketch. The SDF-based level-set mesher smoothly blends between profiles at intermediate positions.
159
+
160
+ Performance note: like sweep(), this uses level-set meshing internally.
161
+
162
+ ```ts
163
+ variableSweep(spine: SweepPathInput, sections: VariableSweepSection[], options?: VariableSweepOptions): Shape
164
+ ```
165
+
166
+ **`VariableSweepSection`**
167
+ - `t: number` — Parameter along the spine (0 = start, 1 = end).
168
+ - `profile: Sketch` — Cross-section profile at this station.
169
+
170
+ **`VariableSweepOptions`**
171
+
172
+ | Option | Type | Description |
173
+ |--------|------|-------------|
174
+ | `samples?` | `number` | Number of samples when spine is a Curve3D. Default 48. |
175
+ | `edgeLength?` | `number` | Marching-grid edge length for level-set meshing. Smaller = finer. |
176
+ | `boundsPadding?` | `number` | Optional extra bounds padding. |
177
+ | `up?` | `Vec3` | Preferred "up" vector for local profile frame. Auto fallback is used near parallel segments. |
178
+
179
+ #### `nurbsSurface()` — Create a NURBS surface from a grid of control points.
180
+
181
+ The control grid is indexed as `controlGrid[u][v]` — each row is a curve in the V direction, and columns trace curves in the U direction.
182
+
183
+ With default options, creates a bicubic non-rational B-spline surface with uniform clamped knots.
184
+
185
+ ```js
186
+ // Simple 4×4 control grid — a gently curved surface
187
+ const grid = [
188
+ [[0,0,0], [10,0,2], [20,0,2], [30,0,0]],
189
+ [[0,10,1], [10,10,5], [20,10,5], [30,10,1]],
190
+ [[0,20,1], [10,20,5], [20,20,5], [30,20,1]],
191
+ [[0,30,0], [10,30,2], [20,30,2], [30,30,0]],
192
+ ];
193
+ const surface = nurbsSurface(grid, { thickness: 2 });
194
+ ```
195
+
196
+ ```ts
197
+ nurbsSurface(controlGrid: Vec3[][], options?: NurbsSurfaceOptions): Shape
198
+ ```
199
+
200
+ **`NurbsSurfaceOptions`**
201
+
202
+ | Option | Type | Description |
203
+ |--------|------|-------------|
204
+ | `degreeU?` | `number` | Degree in U direction (default 3). |
205
+ | `degreeV?` | `number` | Degree in V direction (default 3). |
206
+ | `weights?` | `number[][]` | Weights grid — same dimensions as controlGrid (default: all 1.0). |
207
+ | `knotsU?` | `number[]` | Knot vector in U direction (default: uniform clamped). |
208
+ | `knotsV?` | `number[]` | Knot vector in V direction (default: uniform clamped). |
209
+ | `thickness?` | `number` | Sheet thickness — if > 0, thickens the surface into a solid (default 0 = surface only). |
210
+ | `resolution?` | `number` | Tessellation resolution — points per direction (default 32). |
211
+
212
+ #### `surfacePatch()` — Create a smooth surface patch from 4 boundary curves (Coons patch).
213
+
214
+ The four curves form the boundary of a quadrilateral patch:
215
+
216
+ - bottom: u=0..1 at v=0 (from corner00 to corner10)
217
+ - top: u=0..1 at v=1 (from corner01 to corner11)
218
+ - left: v=0..1 at u=0 (from corner00 to corner01)
219
+ - right: v=0..1 at u=1 (from corner10 to corner11)
220
+
221
+ The interior is filled using bilinear Coons patch interpolation: P(u,v) = Lc(u,v) + Ld(u,v) - B(u,v)
222
+
223
+ The result is a thin solid created by offsetting the surface mesh along its normals by the specified thickness.
224
+
225
+ Note: curves should meet at corners. Small gaps are tolerated.
226
+
227
+ ```ts
228
+ surfacePatch(curves: { ... }, options?: SurfacePatchOptions): Shape
229
+ ```
230
+
231
+ **`SurfacePatchOptions`**
232
+ - `resolution?: number` — Number of samples along each direction. Default 24.
233
+ - `thickness?: number` — Thickness of the generated solid. Default 0.5.
234
+
235
+ #### `transitionCurve()` — Create a smooth transition curve between two edges.
236
+
237
+ Returns a `HermiteCurve3D` that starts at `edgeA.point` tangent to `edgeA.tangent` and ends at `edgeB.point` tangent to `edgeB.tangent`.
238
+
239
+ The curve maintains G1 continuity (matching tangent direction) at both endpoints. Weight parameters control the shape of the transition.
240
+
241
+ ```js
242
+ ```js
243
+
244
+ // Connect two edges with a balanced transition const curve = transitionCurve( { point: [0, 0, 0], tangent: [1, 0, 0] }, { point: [10, 5, 0], tangent: [1, 0, 0] }, );
245
+
246
+ ```
247
+
248
+ // Weighted: curve hugs edge A longer
249
+ const weighted = transitionCurve(
250
+ { point: [0, 0, 0], tangent: [1, 0, 0] },
251
+ { point: [10, 5, 0], tangent: [1, 0, 0] },
252
+ { weightA: 2.0, weightB: 0.5 },
253
+ );
254
+ ```
255
+
256
+ ```ts
257
+ transitionCurve(edgeA: TransitionEdge, edgeB: TransitionEdge, options?: TransitionCurveOptions): HermiteCurve3D
258
+ ```
259
+
260
+ **`TransitionEdge`**
261
+ - `point: Vec3` — Connection point on the edge. Can be any point along the edge where the transition should connect.
262
+ - `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).
263
+ - `normal?: Vec3` — Surface normal at the connection point (optional). Used as a hint for the sweep frame's up vector.
264
+
265
+ **`TransitionCurveOptions`**
266
+ - `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
267
+ - `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
268
+ - `samples?: number` — Number of sample points for the output polyline. Default 64. Higher values give smoother curves at the cost of more geometry.
269
+
270
+ #### `transitionSurface()` — Create a solid transition surface between two edges by sweeping a profile along a Hermite transition curve.
271
+
272
+ This produces a watertight solid that smoothly connects the two edges. Works with both Manifold and OCCT backends.
273
+
274
+ ```js
275
+ ```js
276
+
277
+ // Circular tube connecting two edges const tube = transitionSurface( { point: [0, 0, 0], tangent: [1, 0, 0] }, { point: [10, 5, 3], tangent: [0, 1, 0] }, { radius: 0.5 }, );
278
+
279
+ ```
280
+
281
+ // Custom profile with weights
282
+ const custom = transitionSurface(
283
+ { point: [0, 0, 0], tangent: [1, 0, 0] },
284
+ { point: [10, 5, 3], tangent: [0, 1, 0] },
285
+ { profile: mySketch, weightA: 1.5, weightB: 0.8 },
286
+ );
287
+ ```
288
+
289
+ ```ts
290
+ transitionSurface(edgeA: TransitionEdge, edgeB: TransitionEdge, options?: TransitionSurfaceOptions): Shape
291
+ ```
292
+
293
+
294
+ **`TransitionSurfaceOptions`** extends TransitionCurveOptions
295
+
296
+ | Option | Type | Description |
297
+ |--------|------|-------------|
298
+ | `profile?` | `Sketch` | Cross-section profile to sweep along the transition curve. If omitted, a circular profile with `radius` is used. |
299
+ | `radius?` | `number` | Radius of circular cross-section (used when `profile` is omitted). Default: 5% of chord length. |
300
+ | `up?` | `Vec3` | Preferred up vector for the sweep frame. Default: auto-detected. |
301
+ | `edgeLength?` | `number` | Edge length for level-set meshing. Smaller = finer. |
302
+ | `boundsPadding?` | `number` | Extra bounds padding for level-set meshing. |
303
+ | `width`, `height` | | — |
304
+
305
+ #### `connectEdges()` — Create a transition surface or solid bridge between two edge segments.
306
+
307
+ 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.
308
+
309
+ ```ts
310
+ connectEdges(edgeA: EdgeSegment, edgeB: EdgeSegment, options?: ConnectEdgesOptions): Shape
311
+ ```
312
+
313
+ **`EdgeSegment`**
314
+
315
+ | Option | Type | Description |
316
+ |--------|------|-------------|
317
+ | `index` | `number` | Stable index within the extraction (deterministic for a given mesh). |
318
+ | `direction` | `Vec3` | Normalized direction from start → end. |
319
+ | `dihedralAngle` | `number` | Dihedral angle in degrees (0 = coplanar, 180 = knife edge). |
320
+ | `convex` | `boolean` | true = outside corner (convex), false = inside corner (concave). |
321
+ | `normalA` | `Vec3` | Normal of first adjacent face. |
322
+ | `normalB` | `Vec3` | Normal of second adjacent face (same as normalA for boundary edges). |
323
+ | `boundary` | `boolean` | true if this is a boundary (unmatched) edge — unusual for closed solids. |
324
+ | `start`, `end`, `midpoint`, `length` | | — |
325
+
326
+
327
+ **`ConnectEdgesOptions`** extends TransitionSurfaceOptions
328
+
329
+ | Option | Type | Description |
330
+ |--------|------|-------------|
331
+ | `endA?` | `EdgeEnd` | Which end of edge A to connect. Default: 'start'. |
332
+ | `endB?` | `EdgeEnd` | Which end of edge B to connect. Default: 'start'. |
333
+ | `tangentModeA?` | `TangentMode` | Tangent mode for edge A. Default: 'along'. |
334
+ | `tangentModeB?` | `TangentMode` | Tangent mode for edge B. Default: 'along'. |
335
+ | `tangentA?` | `Vec3` | Explicit tangent for edge A. |
336
+ | `tangentB?` | `Vec3` | Explicit tangent for edge B. |
337
+ | `flipA?` | `boolean` | Flip tangent A. |
338
+ | `flipB?` | `boolean` | Flip tangent B. |
339
+
340
+ ---
341
+
342
+ ## Classes
343
+
344
+ ### `Curve3D`
345
+
346
+ **Properties:**
347
+
348
+ | Property | Type | Description |
349
+ |----------|------|-------------|
350
+ | `points` | `Vec3[]` | — |
351
+ | `closed` | `boolean` | — |
352
+ | `tension` | `number` | — |
353
+
354
+ **Methods:**
355
+
356
+ #### `sampleBySegment()` — Sample the curve with a fixed number of points per segment.
357
+
358
+ ```ts
359
+ sampleBySegment(samplesPerSegment?: number): Vec3[]
360
+ ```
361
+
362
+ #### `sample()` — Sample the curve to an approximate total point count.
363
+
364
+ ```ts
365
+ sample(count?: number): Vec3[]
366
+ ```
367
+
368
+ #### `pointAt()` — Return the position on the curve at normalized parameter `t` in `[0, 1]`. O(1), no allocations.
369
+
370
+ ```ts
371
+ pointAt(t: number): Vec3
372
+ ```
373
+
374
+ #### `tangentAt()` — Return a unit tangent vector at normalized parameter `t` in `[0, 1]`. O(1), analytical derivative.
375
+
376
+ ```ts
377
+ tangentAt(t: number): Vec3
378
+ ```
379
+
380
+ #### `length()` — Approximate the curve length by polyline sampling.
381
+
382
+ ```ts
383
+ length(samples?: number): number
384
+ ```
385
+
386
+ ### `NurbsCurve3D`
387
+
388
+ **Properties:**
389
+
390
+ | Property | Type | Description |
391
+ |----------|------|-------------|
392
+ | `controlPoints` | `Vec3[]` | — |
393
+ | `weights` | `number[]` | — |
394
+ | `knots` | `number[]` | — |
395
+ | `degree` | `number` | — |
396
+ | `closed` | `boolean` | — |
397
+
398
+ **Methods:**
399
+
400
+ #### `pointAt()` — Evaluate the curve at parameter t ∈ [0, 1]. Uses De Boor's algorithm — exact, O(degree²).
401
+
402
+ ```ts
403
+ pointAt(t: number): Vec3
404
+ ```
405
+
406
+ #### `tangentAt()` — Evaluate the unit tangent vector at parameter t ∈ [0, 1].
407
+
408
+ ```ts
409
+ tangentAt(t: number): Vec3
410
+ ```
411
+
412
+ #### `sample()` — Sample the curve uniformly at `count` points.
413
+
414
+ ```ts
415
+ sample(count?: number): Vec3[]
416
+ ```
417
+
418
+ #### `sampleAdaptive()` — Sample with adaptive density — more points in high-curvature regions.
419
+
420
+ ```ts
421
+ sampleAdaptive(minCount?: number, maxCount?: number): Vec3[]
422
+ ```
423
+
424
+ #### `length()` — Approximate arc length by summing polyline segment lengths.
425
+
426
+ ```ts
427
+ length(samples?: number): number
428
+ ```
429
+
430
+ #### `toPolyline()` — Convert to a format compatible with sweep() path input.
431
+
432
+ ```ts
433
+ toPolyline(samples?: number): Vec3[]
434
+ ```
435
+
436
+ ### `NurbsSurface`
437
+
438
+ **Properties:**
439
+
440
+ | Property | Type | Description |
441
+ |----------|------|-------------|
442
+ | `controlGrid` | `Vec3[][]` | — |
443
+ | `weightsGrid` | `number[][]` | — |
444
+ | `knotsU` | `number[]` | — |
445
+ | `knotsV` | `number[]` | — |
446
+ | `degreeU` | `number` | — |
447
+ | `degreeV` | `number` | — |
448
+ | `nU` | `number` | — |
449
+ | `nV` | `number` | — |
450
+
451
+ **Methods:**
452
+
453
+ #### `pointAt()` — Evaluate the surface at parameters (u, v) ∈ [0, 1]². Uses tensor product evaluation: evaluate basis functions in U and V independently.
454
+
455
+ ```ts
456
+ pointAt(u: number, v: number): Vec3
457
+ ```
458
+
459
+ #### `normalAt()` — Evaluate the surface normal at (u, v) via cross product of partial derivatives.
460
+
461
+ ```ts
462
+ normalAt(u: number, v: number): Vec3
463
+ ```
464
+
465
+ #### `tessellate()` — Tessellate the surface into a triangle mesh. Returns positions, normals, and triangle indices.
466
+
467
+ ```ts
468
+ tessellate(resU?: number, resV?: number): { positions: Vec3[]; normals: Vec3[]; indices: number[]; }
469
+ ```
470
+
471
+ ### `PathBuilder`
472
+
473
+ **Line Segments**
474
+
475
+ #### `moveTo()` — Move the cursor to an absolute position without drawing a segment.
476
+
477
+ When called after the initial [`path()`](/docs/sketch#path), this establishes the start of the outline. Calling `moveTo` again mid-path starts a new sub-path (hole in `close()`, separate segment for [`stroke()`](/docs/sketch#stroke)).
478
+
479
+ ```ts
480
+ moveTo(x: number, y: number): this
481
+ ```
482
+
483
+ #### `lineTo()` — Draw a straight line from the current cursor to an absolute position.
484
+
485
+ ```ts
486
+ lineTo(x: number, y: number): this
487
+ ```
488
+
489
+ #### `lineH()` — Draw a horizontal line segment by `dx` units from the current cursor.
490
+
491
+ Positive `dx` moves right; negative moves left.
492
+
493
+ ```ts
494
+ lineH(dx: number): this
495
+ ```
496
+
497
+ #### `lineV()` — Draw a vertical line segment by `dy` units from the current cursor.
498
+
499
+ Positive `dy` moves up; negative moves down.
500
+
501
+ ```ts
502
+ lineV(dy: number): this
503
+ ```
504
+
505
+ #### `lineAngled()` — Draw a line at the given angle and length from the current cursor.
506
+
507
+ Angle convention: `0°` points right (+X), `90°` points up (+Y).
508
+
509
+ ```ts
510
+ // L-bracket with angled return
511
+ path().moveTo(0, 0).lineH(50).lineV(-70).lineAngled(20, 235).stroke(4);
512
+ ```
513
+
514
+ ```ts
515
+ lineAngled(length: number, degrees: number): this
516
+ ```
517
+
518
+ **Arcs**
519
+
520
+ #### `arc()` — Draw an arc defined by center, radius, and angle range (no trig needed). If the path has no segments yet, automatically moves to the arc start. Positive sweep (startDeg < endDeg) = CCW, negative = CW.
521
+
522
+ ```js
523
+ // Arc centered at (10, 0), radius 50, from -30° to +30°
524
+ path().arc(10, 0, 50, -30, 30).stroke(8, 'Round')
525
+ ```
526
+
527
+ ```ts
528
+ arc(cx: number, cy: number, radius: number, startDeg: number, endDeg: number): this
529
+ ```
530
+
531
+ #### `arcTo()` — Draw a circular arc from the current position to (x, y) with the given radius. `clockwise=true` → arc curves to the right of the start→end direction. `clockwise=false` → arc curves to the left of the start→end direction.
532
+
533
+ ```ts
534
+ arcTo(x: number, y: number, radius: number, clockwise?: boolean): this
535
+ ```
536
+
537
+ #### `tangentArcTo()` — G1-continuous arc — radius derived from current tangent + endpoint. Throws if endpoint is collinear with current direction.
538
+
539
+ ```ts
540
+ tangentArcTo(x: number, y: number): this
541
+ ```
542
+
543
+ **Curves**
544
+
545
+ #### `bezierTo()` — Cubic bezier from current position to (x, y) via two control points.
546
+
547
+ ```ts
548
+ bezierTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): this
549
+ ```
550
+
551
+ **Closing & Output**
552
+
553
+ #### `close()` — Close the path and return a filled [`Sketch`](/docs/sketch#sketch).
554
+
555
+ The winding of the polygon is automatically corrected to CCW (the expected orientation for ForgeCAD sketches). If the path contains multiple sub-paths (started with subsequent `moveTo` calls), the first sub-path is the outer contour and subsequent sub-paths become holes subtracted from it.
556
+
557
+ Edge labels (assigned with `.label('name')`) are transferred to the resulting sketch and propagate through `extrude()`, `revolve()`, `loft()`, and `sweep()` into named faces on the resulting [`Shape`](/docs/core#shape).
558
+
559
+ ```ts
560
+ const triangle = path().moveTo(0, 0).lineH(50).lineV(30).close();
561
+
562
+ // With a hole (second sub-path)
563
+ const frame = path()
564
+ .moveTo(0, 0).lineH(40).lineV(30).lineH(-40).close(); // outer
565
+ // (hole would be added with another moveTo and line sequence before close)
566
+ ```
567
+
568
+ ```ts
569
+ close(): Sketch
570
+ ```
571
+
572
+ #### `closeLabel()` — Label the closing segment and close the path. Shorthand for labeling the implicit line from the last point back to the start, then closing.
573
+
574
+ ```ts
575
+ closeLabel(name: string): Sketch
576
+ ```
577
+
578
+ #### [`stroke()`](/docs/sketch#stroke) — Thicken an open polyline (centerline) into a solid filled profile with uniform width.
579
+
580
+ Expands the path into a closed profile `width` units wide (half-width on each side of the centerline). Use `'Round'` for ribs, wire traces, and organic profiles — it adds semicircular endcaps and rounds joins. Use `'Square'` (default) for sharp miter joins without endcaps.
581
+
582
+ Not the same as rounding corners of a closed polygon — for mixed sharp-and-rounded outlines, build the polygon first and apply [`filletCorners()`](/docs/core#filletcorners).
583
+
584
+ ```ts
585
+ // Square-join L-bracket
586
+ const bracket = path().moveTo(0, 0).lineH(50).lineV(-70).lineAngled(20, 235).stroke(4);
587
+
588
+ // Round-join rib
589
+ const rib = path().moveTo(0, 0).lineH(60).stroke(6, 'Round');
590
+
591
+ // Equivalent standalone form
592
+ const wire = stroke([[0, 0], [50, 0], [50, -70]], 4);
593
+ ```
594
+
595
+ and semicircular endcaps.
596
+
597
+ ```ts
598
+ stroke(width: number, join?: "Round" | "Square"): Sketch
599
+ ```
600
+
601
+ #### `label()` — Label the most recently added segment. Labels are born here and grow into face names when the sketch is extruded, lofted, swept, or revolved.
602
+
603
+ Labels must be unique within a path. Each segment can have at most one label.
604
+
605
+ ```ts
606
+ label(name: string): this
607
+ ```
608
+
609
+ **Other**
610
+
611
+ #### `getX()` — Current cursor X position.
612
+
613
+ ```ts
614
+ getX(): number
615
+ ```
616
+
617
+ #### `getY()` — Current cursor Y position.
618
+
619
+ ```ts
620
+ getY(): number
621
+ ```
622
+
623
+ #### `lineBy()` — Draw a line by a relative `(dx, dy)` displacement from the current cursor.
624
+
625
+ ```ts
626
+ lineBy(dx: number, dy: number): this
627
+ ```
628
+
629
+ #### `arcBy()` — Draw an arc to a point offset from the current cursor.
630
+
631
+ ```ts
632
+ arcBy(dx: number, dy: number, radius: number, clockwise?: boolean): this
633
+ ```
634
+
635
+ #### `bezierBy()` — Draw a cubic Bezier using control points relative to the current cursor.
636
+
637
+ ```ts
638
+ bezierBy(dcp1x: number, dcp1y: number, dcp2x: number, dcp2y: number, dx: number, dy: number): this
639
+ ```
640
+
641
+ #### `arcAround()` — Arc around a known center point, sweeping by the given angle. Radius is derived from the distance between the current position and the center. Positive sweep = CCW (math convention), negative = CW.
642
+
643
+ ```js
644
+ // Arc 90° CCW around (50, 50)
645
+ path().moveTo(70, 50).arcAround(50, 50, 90)
646
+ // Arc 45° CW around the origin
647
+ path().moveTo(10, 0).arcAround(0, 0, -45)
648
+ ```
649
+
650
+ ```ts
651
+ arcAround(cx: number, cy: number, sweepDeg: number): this
652
+ ```
653
+
654
+ #### `arcAroundRelative()` — Arc around a center point given as an offset from the current position. `(dx, dy)` is the vector from the current point to the center. Positive sweep = CCW (math convention), negative = CW.
655
+
656
+ ```js
657
+ // Arc 90° CCW around a center 20 units to the right
658
+ path().moveTo(50, 50).arcAroundRelative(20, 0, 90)
659
+ // Equivalent to: path().moveTo(50, 50).arcAround(70, 50, 90)
660
+ ```
661
+
662
+ ```ts
663
+ arcAroundRelative(dx: number, dy: number, sweepDeg: number): this
664
+ ```
665
+
666
+ #### `smoothCapTo()` — Smooth three-arc end cap from the current position to (endX, endY). Inserts: small corner arc → large cap arc → small corner arc, all G1-continuous.
667
+
668
+ ```ts
669
+ smoothCapTo(endX: number, endY: number, cornerRadius: number, capRadius: number): this
670
+ ```
671
+
672
+ #### `tangentBezierTo()` — G1-continuous cubic bezier — first control point is auto-derived from the current tangent direction. `weight` controls how far the auto-placed control point extends along the tangent (default: 1/3 of the chord).
673
+
674
+ The second control point `(cp2x, cp2y)` must be provided — it controls the arrival curvature. For a fully automatic smooth curve, see `smoothThrough`.
675
+
676
+ ```ts
677
+ tangentBezierTo(cp2x: number, cp2y: number, x: number, y: number, weight?: number): this
678
+ ```
679
+
680
+ #### `smoothThrough()` — Catmull-Rom spline through a list of waypoints from the current position. The current position is included as the first point. The last waypoint becomes the new cursor position.
681
+
682
+ ```ts
683
+ smoothThrough(waypoints: [ number, number ][], tension?: number): this
684
+ ```
685
+
686
+ #### `nurbsTo()` — Rational B-spline edge to (x, y) with explicit control points and weights.
687
+
688
+ The control points define the B-spline shape between the current position and (x, y). The current position is NOT included in `controlPoints` — it is automatically prepended. The endpoint (x, y) is the last control point.
689
+
690
+ ```ts
691
+ nurbsTo(controlPoints: [ number, number ][], opts?: { weights?: number[]; degree?: number; }): this
692
+ ```
693
+
694
+ #### `exactArcTo()` — Exact circular arc to (x, y) using a rational quadratic NURBS.
695
+
696
+ Unlike `arcTo()` which tessellates to a polyline, this preserves the exact arc definition. When extruded through the OCCT backend, it produces a true cylindrical face — not a faceted approximation.
697
+
698
+ ```ts
699
+ exactArcTo(x: number, y: number, opts?: { radius?: number; clockwise?: boolean; }): this
700
+ ```
701
+
702
+ #### [`fillet()`](/docs/core#fillet) — Round the last corner (the junction between the previous two segments) with a tangent arc of the given radius.
703
+
704
+ Must be called after at least two line/arc segments that form a corner. The fillet trims back both segments and inserts a tangent arc.
705
+
706
+ ```js
707
+ path().moveTo(0,0).lineTo(10,0).lineTo(10,10).fillet(2).lineTo(0,10).close()
708
+ ```
709
+
710
+ ```ts
711
+ fillet(radius: number): this
712
+ ```
713
+
714
+ #### [`chamfer()`](/docs/core#chamfer) — Chamfer the last corner with a straight cut of the given distance.
715
+
716
+ ```js
717
+ path().moveTo(0,0).lineTo(10,0).lineTo(10,10).chamfer(2).lineTo(0,10).close()
718
+ ```
719
+
720
+ ```ts
721
+ chamfer(distance: number): this
722
+ ```
723
+
724
+ #### `mirror()` — Mirror all existing segments across an axis and append the mirrored copy in reverse order, creating a symmetric path. The axis passes through the current cursor position.
725
+
726
+ 'y' mirrors across the local Y-axis (flips X), or `[nx, ny]` for an arbitrary axis direction.
727
+
728
+ ```js
729
+ // Build right half, mirror to get full symmetric profile
730
+ path().moveTo(0,0).lineTo(10,0).lineTo(10,5).mirror('x').close()
731
+ ```
732
+
733
+ ```ts
734
+ mirror(axis: "x" | "y" | [ number, number ]): this
735
+ ```
736
+
737
+ #### `closeOffset()` — Close the path and return an offset version of the filled Sketch. Positive delta expands outward, negative shrinks inward.
738
+
739
+ ```ts
740
+ closeOffset(delta: number, join?: "Round" | "Square" | "Miter"): Sketch
741
+ ```
742
+
743
+ ### `HermiteCurve3D`
744
+
745
+ **Properties:**
746
+
747
+ | Property | Type | Description |
748
+ |----------|------|-------------|
749
+ | `p0` | `Vec3` | Start position |
750
+ | `p1` | `Vec3` | End position |
751
+ | `t0` | `Vec3` | Scaled tangent at start (direction * weight * chordLength) |
752
+ | `t1` | `Vec3` | Scaled tangent at end (direction * weight * chordLength) |
753
+ | `chordLength` | `number` | Chord length (straight-line distance between endpoints) |
754
+
755
+ **Methods:**
756
+
757
+ #### `pointAt()` — Evaluate position at parameter t ∈ [0, 1]
758
+
759
+ ```ts
760
+ pointAt(t: number): Vec3
761
+ ```
762
+
763
+ #### `tangentAt()` — Evaluate tangent (first derivative) at parameter t ∈ [0, 1]
764
+
765
+ ```ts
766
+ tangentAt(t: number): Vec3
767
+ ```
768
+
769
+ #### `curvatureAt()` — Evaluate curvature vector (second derivative) at parameter t ∈ [0, 1]
770
+
771
+ ```ts
772
+ curvatureAt(t: number): Vec3
773
+ ```
774
+
775
+ #### `sample()` — Sample the curve as a polyline of evenly-spaced parameter values.
776
+
777
+ ```ts
778
+ sample(count?: number): Vec3[]
779
+ ```
780
+
781
+ #### `length()` — Approximate arc length by sampling.
782
+
783
+ ```ts
784
+ length(samples?: number): number
785
+ ```
786
+
787
+ #### `sampleAdaptive()` — Sample with adaptive density — more points where curvature is higher. Returns at least `minCount` points, up to `maxCount`.
788
+
789
+ ```ts
790
+ sampleAdaptive(minCount?: number, maxCount?: number): Vec3[]
791
+ ```
792
+
793
+ #### `toPolyline()` — Convert to a format compatible with sweep() path input.
794
+
795
+ ```ts
796
+ toPolyline(samples?: number): Vec3[]
797
+ ```
798
+
799
+ ### `QuinticHermiteCurve3D`
800
+
801
+ **Properties:**
802
+
803
+ | Property | Type | Description |
804
+ |----------|------|-------------|
805
+ | `p0` | `Vec3` | Start position |
806
+ | `p1` | `Vec3` | End position |
807
+ | `t0` | `Vec3` | Scaled tangent at start (direction * weight * chordLength) |
808
+ | `t1` | `Vec3` | Scaled tangent at end (direction * weight * chordLength) |
809
+ | `c0` | `Vec3` | Scaled second derivative at start (curvature * weight² * chordLength²) |
810
+ | `c1` | `Vec3` | Scaled second derivative at end (curvature * weight² * chordLength²) |
811
+ | `chordLength` | `number` | Chord length (straight-line distance between endpoints) |
812
+
813
+ **Methods:**
814
+
815
+ #### `pointAt()` — Evaluate position at parameter t ∈ [0, 1]
816
+
817
+ ```ts
818
+ pointAt(t: number): Vec3
819
+ ```
820
+
821
+ #### `tangentAt()` — Evaluate tangent (first derivative, normalized) at parameter t ∈ [0, 1]
822
+
823
+ ```ts
824
+ tangentAt(t: number): Vec3
825
+ ```
826
+
827
+ #### `curvatureAt()` — Evaluate curvature vector (second derivative) at parameter t ∈ [0, 1]
828
+
829
+ ```ts
830
+ curvatureAt(t: number): Vec3
831
+ ```
832
+
833
+ #### `sample()` — Sample the curve as a polyline of evenly-spaced parameter values.
834
+
835
+ ```ts
836
+ sample(count?: number): Vec3[]
837
+ ```
838
+
839
+ #### `length()` — Approximate arc length by sampling.
840
+
841
+ ```ts
842
+ length(samples?: number): number
843
+ ```
844
+
845
+ #### `sampleAdaptive()` — Sample with adaptive density — more points where curvature is higher. Returns at least `minCount` points, up to `maxCount`.
846
+
847
+ ```ts
848
+ sampleAdaptive(minCount?: number, maxCount?: number): Vec3[]
849
+ ```
850
+
851
+ #### `toPolyline()` — Convert to a format compatible with sweep() path input.
852
+
853
+ ```ts
854
+ toPolyline(samples?: number): Vec3[]
855
+ ```