forgecad 0.9.16 → 0.10.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 (147) hide show
  1. package/dist/assets/{AdminPage-CXvls4-J.js → AdminPage-DwYHz72L.js} +1 -1
  2. package/dist/assets/{BenchmarkPage-B27zk8xL.js → BenchmarkPage-a9_f-1US.js} +1 -1
  3. package/dist/assets/{BlogPage-CMAVvgQL.js → BlogPage-DodHpvmf.js} +1 -1
  4. package/dist/assets/{DocsPage-knf4I4h7.js → DocsPage-B5LePEuj.js} +8 -858
  5. package/dist/assets/EditorApp-QXsAISLR.js +16307 -0
  6. package/dist/assets/{EmbedViewer-D7ZGlFjx.js → EmbedViewer-DdEHGUMU.js} +2 -2
  7. package/dist/assets/{LandingPageProofDriven-CnevhTE8.js → LandingPageProofDriven-yhhOodbf.js} +1 -1
  8. package/dist/assets/{LegalPage-BPTUmqeg.js → LegalPage-5RbKRGYK.js} +1 -1
  9. package/dist/assets/{PricingPage-B0D4goG_.js → PricingPage-E3Rma7aV.js} +1 -1
  10. package/dist/assets/{SettingsPage-CFF-UgjI.js → SettingsPage-BJZcM97j.js} +1 -1
  11. package/dist/assets/{app-T0pDcSX4.js → app-DSYrDg0V.js} +733 -205
  12. package/dist/assets/cli/{render-C5pcIISc.js → render-ZMHR9HkV.js} +19 -46
  13. package/dist/assets/{constructionHistoryWorker-Ba2Hm58b.js → constructionHistoryWorker-AwMMWSxg.js} +1103 -349
  14. package/dist/assets/{evalWorker-vkx310U2.js → evalWorker-DbNs7Dkp.js} +3798 -1622
  15. package/dist/assets/{inspectWorker-BuTJDVX6.js → inspectWorker-CZsCFtQT.js} +1163 -409
  16. package/dist/assets/{jointPose-B_Cgedn9.js → jointPose-DO6mnXn_.js} +1 -1
  17. package/dist/assets/{manifold-BWgsjmAM.js → manifold-BGlQBBH9.js} +1 -1
  18. package/dist/assets/{manifold-rZexZI0G.js → manifold-BU-tJwQh.js} +1 -1
  19. package/dist/assets/{manifold-D6IFSkhH.js → manifold-fy2MV7K1.js} +2 -2
  20. package/dist/assets/{reportWorker-0AGij1Ru.js → reportWorker-DO6hcQbh.js} +7155 -2437
  21. package/dist/assets/{scalar-sampling-budget-J5cuzxT1.js → scalar-sampling-budget-o90NSNmF.js} +3940 -1742
  22. package/dist/assets/{scanProxyWorker-Vl4Wxa1y.js → scanProxyWorker-2GtDLk-R.js} +1 -1
  23. package/dist/assets/{javascript-1kQXfVaz.js → typescript-DBQ6RN5l.js} +874 -22
  24. package/dist/cli/render.html +1 -1
  25. package/dist/docs/index.html +3 -3
  26. package/dist/docs-raw/AI/usage.md +1 -1
  27. package/dist/docs-raw/CLI.md +63 -241
  28. package/dist/docs-raw/README.md +6 -0
  29. package/dist/docs-raw/component-model.md +17 -150
  30. package/dist/docs-raw/generated/assembly.md +139 -598
  31. package/dist/docs-raw/generated/concepts.md +245 -3501
  32. package/dist/docs-raw/generated/core.md +277 -1251
  33. package/dist/docs-raw/generated/curves.md +387 -1608
  34. package/dist/docs-raw/generated/legacy.md +162 -0
  35. package/dist/docs-raw/generated/lib.md +227 -85
  36. package/dist/docs-raw/generated/output.md +38 -73
  37. package/dist/docs-raw/generated/runtime-names.md +23 -23
  38. package/dist/docs-raw/generated/sdf.md +68 -284
  39. package/dist/docs-raw/generated/sheet-metal.md +68 -335
  40. package/dist/docs-raw/generated/sketch.md +240 -1161
  41. package/dist/docs-raw/generated/viewport.md +75 -316
  42. package/dist/docs-raw/generated/wood.md +21 -49
  43. package/dist/docs-raw/guides/coordinate-system.md +4 -42
  44. package/dist/docs-raw/guides/inspection-bundles.md +44 -442
  45. package/dist/docs-raw/guides/joint-design.md +18 -79
  46. package/dist/docs-raw/guides/positioning.md +21 -143
  47. package/dist/docs-raw/guides/scene-presentation.md +89 -0
  48. package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +25 -111
  49. package/dist/docs-raw/skills/forgecad-blockout-model.md +20 -117
  50. package/dist/docs-raw/skills/forgecad-component-model.md +23 -107
  51. package/dist/docs-raw/skills/forgecad-high-level-spec.md +47 -155
  52. package/dist/docs-raw/skills/forgecad-image-replicator.md +26 -143
  53. package/dist/docs-raw/skills/forgecad-lld.md +19 -113
  54. package/dist/docs-raw/skills/forgecad-make-a-model.md +112 -532
  55. package/dist/docs-raw/skills/forgecad-model-grader.md +38 -108
  56. package/dist/docs-raw/skills/forgecad-prepare-prompt.md +24 -211
  57. package/dist/docs-raw/skills/forgecad-project.md +13 -131
  58. package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +42 -134
  59. package/dist/docs-raw/skills/forgecad-render-inspect.md +27 -174
  60. package/dist/docs-raw/skills/forgecad-visual-spec.md +32 -112
  61. package/dist/docs-raw/skills/forgecad.md +19 -18
  62. package/dist/docs-raw/skills/index.md +2 -0
  63. package/dist/docs-raw/welcome.md +2 -2
  64. package/dist/index.html +1 -1
  65. package/dist/llms.txt +1 -2
  66. package/dist/sitemap.xml +13 -13
  67. package/dist-cli/{check-compiler-SYQ2PWOB.js → check-compiler-JTVBITCR.js} +1 -1
  68. package/dist-cli/{check-query-propagation-HIAGV62W.js → check-query-propagation-3FFLSMVN.js} +1 -1
  69. package/dist-cli/{chunk-SPZE3DUY.js → chunk-OAN5T4XD.js} +4412 -2212
  70. package/dist-cli/forgecad.js +507 -179
  71. package/dist-skill/CONTEXT.md +2172 -8377
  72. package/dist-skill/SKILL.md +15 -15
  73. package/dist-skill/docs/API/core/concepts.md +27 -157
  74. package/dist-skill/docs/CLI.md +63 -241
  75. package/dist-skill/docs/generated/assembly.md +138 -549
  76. package/dist-skill/docs/generated/core.md +277 -1251
  77. package/dist-skill/docs/generated/curves.md +387 -1609
  78. package/dist-skill/docs/generated/lib.md +227 -85
  79. package/dist-skill/docs/generated/output.md +38 -73
  80. package/dist-skill/docs/generated/runtime-names.md +16 -21
  81. package/dist-skill/docs/generated/sdf.md +68 -284
  82. package/dist-skill/docs/generated/sheet-metal.md +68 -335
  83. package/dist-skill/docs/generated/sketch.md +240 -1160
  84. package/dist-skill/docs/generated/viewport.md +75 -223
  85. package/dist-skill/docs/generated/wood.md +21 -49
  86. package/dist-skill/docs/guides/coordinate-system.md +4 -42
  87. package/dist-skill/docs/guides/inspection-bundles.md +44 -442
  88. package/dist-skill/docs/guides/joint-design.md +18 -79
  89. package/dist-skill/docs/guides/positioning.md +21 -143
  90. package/dist-skill/docs/guides/scene-presentation.md +89 -0
  91. package/dist-skill/docs/guides/surface-members.md +26 -0
  92. package/dist-skill/library/forgecad-3d-reconstruction/SKILL.md +23 -111
  93. package/dist-skill/library/forgecad-blockout-model/SKILL.md +18 -117
  94. package/dist-skill/library/forgecad-component-model/SKILL.md +21 -107
  95. package/dist-skill/library/forgecad-high-level-spec/SKILL.md +45 -155
  96. package/dist-skill/library/forgecad-image-replicator/SKILL.md +24 -143
  97. package/dist-skill/library/forgecad-lld/SKILL.md +17 -113
  98. package/dist-skill/library/forgecad-make-a-model/SKILL.md +110 -532
  99. package/dist-skill/library/forgecad-model-grader/SKILL.md +36 -108
  100. package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +35 -224
  101. package/dist-skill/library/forgecad-prepare-prompt/references/default-profiles.md +43 -271
  102. package/dist-skill/library/forgecad-prepare-prompt/references/master-prompt.md +30 -99
  103. package/dist-skill/library/forgecad-project/SKILL.md +13 -133
  104. package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +29 -123
  105. package/dist-skill/library/forgecad-render-inspect/SKILL.md +25 -174
  106. package/dist-skill/library/forgecad-visual-spec/SKILL.md +30 -111
  107. package/dist-skill/website/skills/forgecad-3d-reconstruction.md +58 -0
  108. package/dist-skill/website/skills/forgecad-blockout-model.md +49 -0
  109. package/dist-skill/website/skills/forgecad-component-model.md +53 -0
  110. package/dist-skill/website/skills/forgecad-high-level-spec.md +101 -0
  111. package/dist-skill/website/skills/forgecad-image-replicator.md +63 -0
  112. package/dist-skill/website/skills/forgecad-lld.md +41 -0
  113. package/dist-skill/website/skills/forgecad-make-a-model.md +186 -0
  114. package/dist-skill/website/skills/forgecad-model-grader.md +82 -0
  115. package/dist-skill/website/skills/forgecad-prepare-prompt.md +63 -0
  116. package/dist-skill/website/skills/forgecad-project.md +26 -0
  117. package/dist-skill/website/skills/forgecad-reconstruction-benchmark.md +60 -0
  118. package/dist-skill/website/skills/forgecad-render-inspect.md +80 -0
  119. package/dist-skill/website/skills/forgecad-visual-spec.md +71 -0
  120. package/dist-skill/website/skills/forgecad.md +122 -0
  121. package/dist-skill/website/skills/index.md +26 -0
  122. package/examples/api/comparison-imported-sphere-candidate.forge.js +1 -1
  123. package/examples/api/conformal-product-ribbon.forge.js +1 -1
  124. package/examples/api/exact-sheet-shell-assembly.forge.js +1 -1
  125. package/examples/api/extrude-options.forge.js +4 -2
  126. package/examples/api/field-loft-drive-tip.forge.js +40 -0
  127. package/examples/api/guided-loft-olive-oil-bottle.forge.js +1 -1
  128. package/examples/api/highlight-debug.forge.js +10 -10
  129. package/examples/api/mesh-import-slats.forge.js +1 -1
  130. package/examples/api/real-product-curves.forge.js +1 -1
  131. package/examples/api/sculpt-box-circle-booleans.forge.js +1 -1
  132. package/examples/api/sdf-shapes.forge.js +2 -5
  133. package/examples/api/sketch-rounding-strategies.forge.js +6 -6
  134. package/examples/api/surface-member-bottle-cage.forge.js +3 -3
  135. package/examples/api/surface-member-conformal-product-ribbon.forge.js +3 -3
  136. package/examples/api/surface-member-razor-inlay.forge.js +1 -1
  137. package/examples/api/variable-sweep-test.forge.js +3 -3
  138. package/examples/mechanical/airplane-propeller.forge.js +74 -39
  139. package/examples/nurbs-surface.forge.js +1 -1
  140. package/examples/products/iphone.forge.js +1 -1
  141. package/package.json +1 -1
  142. package/dist/assets/EditorApp-BHMQlJ-D.js +0 -14686
  143. package/dist/docs-raw/guides/geometry-conventions.md +0 -52
  144. package/dist/docs-raw/guides/modeling-recipes.md +0 -78
  145. package/dist-skill/docs/guides/geometry-conventions.md +0 -52
  146. package/dist-skill/docs/guides/modeling-recipes.md +0 -78
  147. package/dist-skill/library/forgecad-visual-spec/references/prompt-template.md +0 -79
@@ -9,13 +9,10 @@ skill-order: 100
9
9
 
10
10
  ## Contents
11
11
 
12
- - [2D Sketch Primitives](#2d-sketch-primitives) — `path`, `stroke`, `rect`, `circle2d`, `roundedRect`, `polygon`, `ngon`, `ellipse`, `slot`, `arcSlot`, `star`
13
- - [2D Sketch Booleans](#2d-sketch-booleans) — `union2d`, `difference2d`, `intersection2d`
14
- - [2D Sketch Features](#2d-sketch-features) — `filletCorners`
15
- - [Tracked Solid Edge Features](#tracked-solid-edge-features) — `filletTrackedEdge`, `chamferTrackedEdge`
16
- - [2D Text](#2d-text) — `loadFont`, `text2d`, `textWidth`
17
- - [Constrained Sketches](#constrained-sketches) — `constrainedSketch`, `addRect`, `addPolygon`, `addRegularPolygon`
18
- - [2D Geometry Helpers](#2d-geometry-helpers) — `point`, `line`, `circle`, `degrees`, `radians`
12
+ - [2D Sketch Primitives](#2d-sketch-primitives)
13
+ - [2D Sketch Booleans](#2d-sketch-booleans)
14
+ - [2D Text](#2d-text)
15
+ - [Constrained Sketches](#constrained-sketches)
19
16
  - [Sketch](#sketch) — Transforms, Booleans, Features, Promotion, Placement, Labels, Measurement
20
17
  - [ConstrainedSketchBuilder](#constrainedsketchbuilder) — Drawing, Entities, Geometric Constraints, Dimensional Constraints, Coincidence & Equality, Tangent Transitions, Shape Constraints, Positioning, Solving
21
18
  - [ConstraintSketch](#constraintsketch)
@@ -29,7 +26,7 @@ skill-order: 100
29
26
 
30
27
  ### 2D Sketch Primitives
31
28
 
32
- #### `path()` — Create a new [`PathBuilder`](/docs/curves#pathbuilder) for tracing a 2D outline point by point.
29
+ #### `path(): PathBuilder` — Create a new [`PathBuilder`](/docs/curves#pathbuilder) for tracing a 2D outline point by point.
33
30
 
34
31
  [`PathBuilder`](/docs/curves#pathbuilder) is a fluent API for constructing 2D profiles using a mix of line segments, arcs, bezier curves, and splines. Always start with `.moveTo(x, y)` to set the starting point. Call `.close()` to get a filled `Sketch`, or `.stroke(width)` to thicken an open polyline into a solid profile.
35
32
 
@@ -51,27 +48,17 @@ const slot = path()
51
48
  .close();
52
49
  ```
53
50
 
54
- ```ts
55
- path(): PathBuilder
56
- ```
51
+ #### `stroke(points: Vec2[], width: number, join?: "Round" | "Square"): Sketch` — Thicken a 2D polyline (centerline) into a solid filled profile of uniform width.
57
52
 
58
- #### `stroke()`Create a stroked polyline sketch from an array of 2D points.
59
-
60
- ```ts
61
- stroke(points: [ number, number ][], width: number, join?: "Round" | "Square"): Sketch
62
- ```
53
+ Standalone equivalent of `path()...stroke(width, join)`. Use for centerline-based geometry ribs, wire traces, brackets. For rounding corners of a *closed* outline use `.filletCorners(radius)` (all corners) or `.filletCorner([x, y], radius)` (one corner) instead.
63
54
 
64
- #### `rect()` — Create a 2D rectangle centered at the origin.
55
+ #### `rect(width: number, height: number): Sketch` — Create a 2D rectangle centered at the origin.
65
56
 
66
57
  ```ts
67
58
  rect(40, 20).extrude(5);
68
59
  ```
69
60
 
70
- ```ts
71
- rect(width: number, height: number): Sketch
72
- ```
73
-
74
- #### `circle2d()` — Create a 2D circle centered at the origin.
61
+ #### `circle2d(radius: number, segments?: number): Sketch` — Create a 2D circle centered at the origin.
75
62
 
76
63
  Omit `segments` for a smooth (auto-tessellated) circle. Pass an integer to get a regular polygon approximation — e.g. `6` for a hexagon, `8` for an octagon.
77
64
 
@@ -80,11 +67,7 @@ circle2d(25).extrude(10); // smooth cylinder
80
67
  circle2d(25, 6).extrude(10); // hexagonal prism
81
68
  ```
82
69
 
83
- ```ts
84
- circle2d(radius: number, segments?: number): Sketch
85
- ```
86
-
87
- #### `roundedRect()` — Create a 2D rectangle with rounded corners, centered at the origin.
70
+ #### `roundedRect(width: number, height: number, radius: number): Sketch` — Create a 2D rectangle with rounded corners, centered at the origin.
88
71
 
89
72
  The corner radius is automatically clamped to `min(width/2, height/2)` so it can never exceed the shape dimensions.
90
73
 
@@ -92,11 +75,7 @@ The corner radius is automatically clamped to `min(width/2, height/2)` so it can
92
75
  roundedRect(60, 30, 5).extrude(3);
93
76
  ```
94
77
 
95
- ```ts
96
- roundedRect(width: number, height: number, radius: number): Sketch
97
- ```
98
-
99
- #### `polygon()` — Create a 2D polygon from an array of `[x, y]` points or `Point2D` objects.
78
+ #### `polygon(points: (Vec2 | Point2D)[]): Sketch` — Create a 2D polygon from an array of `[x, y]` points or `Point2D` objects.
100
79
 
101
80
  Winding order is normalized automatically — clockwise (CW) input is silently reversed to CCW before being passed to the geometry kernel.
102
81
 
@@ -104,11 +83,7 @@ Winding order is normalized automatically — clockwise (CW) input is silently r
104
83
  polygon([[0, 0], [50, 0], [25, 40]]).extrude(5); // triangle
105
84
  ```
106
85
 
107
- ```ts
108
- polygon(points: ([ number, number ] | Point2D)[]): Sketch
109
- ```
110
-
111
- #### `ngon()` — Create a regular polygon inscribed in a circle of the given radius.
86
+ #### `ngon(sides: number, radius: number): Sketch` — Create a regular polygon inscribed in a circle of the given radius.
112
87
 
113
88
  `radius` is the center-to-vertex (circumradius) distance. Use `sides` of `3` for a triangle, `6` for a hexagon, etc. The first vertex is at the top (−90° from +X).
114
89
 
@@ -116,32 +91,20 @@ polygon(points: ([ number, number ] | Point2D)[]): Sketch
116
91
  ngon(6, 20).extrude(10); // hexagonal prism, circumradius 20
117
92
  ```
118
93
 
119
- ```ts
120
- ngon(sides: number, radius: number): Sketch
121
- ```
122
-
123
- #### `ellipse()` — Create a 2D ellipse centered at the origin.
94
+ #### `ellipse(rx: number, ry: number, segments?: number): Sketch` — Create a 2D ellipse centered at the origin.
124
95
 
125
96
  ```ts
126
97
  ellipse(30, 15).extrude(5);
127
98
  ellipse(30, 15, 32).extrude(5); // lower-resolution approximation
128
99
  ```
129
100
 
130
- ```ts
131
- ellipse(rx: number, ry: number, segments?: number): Sketch
132
- ```
133
-
134
- #### `slot()` — Create a slot (oblong / stadium shape) — a rectangle with semicircular ends, centered at the origin.
101
+ #### `slot(length: number, width: number): Sketch` — Create a slot (oblong / stadium shape) — a rectangle with semicircular ends, centered at the origin.
135
102
 
136
103
  ```ts
137
104
  slot(40, 10).extrude(3); // 40mm long, 10mm wide slot
138
105
  ```
139
106
 
140
- ```ts
141
- slot(length: number, width: number): Sketch
142
- ```
143
-
144
- #### `arcSlot()` — Create an arc-shaped slot (banana / annular sector) centered at the origin.
107
+ #### `arcSlot(pitchRadius: number, sweepDeg: number, thickness: number): Sketch` — Create an arc-shaped slot (banana / annular sector) centered at the origin.
145
108
 
146
109
  The slot is symmetric about the +X axis. The two ends are closed with semicircular caps. `pitchRadius` is the distance from the origin to the centerline of the slot, and `thickness` is the radial width of the slot.
147
110
 
@@ -149,23 +112,9 @@ The slot is symmetric about the +X axis. The two ends are closed with semicircul
149
112
  arcSlot(135, 74, 40).extrude(5); // pitch R135, 74° sweep, 40mm wide
150
113
  ```
151
114
 
152
- ```ts
153
- arcSlot(pitchRadius: number, sweepDeg: number, thickness: number): Sketch
154
- ```
155
-
156
- #### `star()` — Create a star shape with alternating outer and inner radii.
157
-
158
- ```ts
159
- star(5, 30, 12).extrude(4); // five-pointed star
160
- ```
161
-
162
- ```ts
163
- star(points: number, outerR: number, innerR: number): Sketch
164
- ```
165
-
166
115
  ### 2D Sketch Booleans
167
116
 
168
- #### `union2d()` — Combine 2D sketches into a single profile using an additive boolean union.
117
+ #### `union2d(...inputs: SketchOperandInput[]): Sketch` — Combine 2D sketches into a single profile using an additive boolean union.
169
118
 
170
119
  Accepts individual sketches or arrays: `union2d(a, b, c)` or `union2d([a, b, c])`. Uses Manifold's batch operation — faster than chaining `.add()` one by one when combining many sketches.
171
120
 
@@ -173,11 +122,7 @@ Accepts individual sketches or arrays: `union2d(a, b, c)` or `union2d([a, b, c])
173
122
  const cross = union2d(rect(60, 10), rect(10, 60));
174
123
  ```
175
124
 
176
- ```ts
177
- union2d(...inputs: SketchOperandInput[]): Sketch
178
- ```
179
-
180
- #### `difference2d()` — Subtract one or more 2D sketches from a base sketch.
125
+ #### `difference2d(...inputs: SketchOperandInput[]): Sketch` — Subtract one or more 2D sketches from a base sketch.
181
126
 
182
127
  The first sketch is the base; all subsequent sketches are subtracted from it. Accepts individual sketches or arrays: `difference2d(base, c1, c2)` or `difference2d([base, c1, c2])`. Uses Manifold's batch operation — faster than chaining `.subtract()` one by one.
183
128
 
@@ -185,11 +130,7 @@ The first sketch is the base; all subsequent sketches are subtracted from it. Ac
185
130
  const donut = difference2d(circle2d(50), circle2d(30));
186
131
  ```
187
132
 
188
- ```ts
189
- difference2d(...inputs: SketchOperandInput[]): Sketch
190
- ```
191
-
192
- #### `intersection2d()` — Keep only the area where all input sketches overlap (intersection boolean).
133
+ #### `intersection2d(...inputs: SketchOperandInput[]): Sketch` — Keep only the area where all input sketches overlap (intersection boolean).
193
134
 
194
135
  Accepts individual sketches or arrays: `intersection2d(a, b)` or `intersection2d([a, b, c])`. Uses Manifold's batch operation — faster than chaining `.intersect()` one by one.
195
136
 
@@ -197,92 +138,9 @@ Accepts individual sketches or arrays: `intersection2d(a, b)` or `intersection2d
197
138
  const lens = intersection2d(circle2d(30).translate(-10, 0), circle2d(30).translate(10, 0));
198
139
  ```
199
140
 
200
- ```ts
201
- intersection2d(...inputs: SketchOperandInput[]): Sketch
202
- ```
203
-
204
- ### 2D Sketch Features
205
-
206
- #### `filletCorners()` — Create a polygon from points with specific corners rounded to arc fillets.
207
-
208
- Each corner spec identifies a vertex by its index in the `points` array and the desired fillet `radius`. Both convex and concave corners are supported.
209
-
210
- Constraints:
211
-
212
- - Collinear corners cannot be filleted (throws an error)
213
- - Two neighboring fillets whose tangent lengths overlap the same edge will throw
214
- - Radius must be positive and small enough to fit within the adjacent edge lengths
215
-
216
- Use `offset(-r).offset(+r)` instead if you want to round **all** convex corners uniformly. Use `filletCorners` when you need selective or mixed sharp/rounded profiles.
217
-
218
- ```ts
219
- const roof = filletCorners(roofPoints, [
220
- { index: 3, radius: 19 },
221
- { index: 4, radius: 19 },
222
- { index: 5, radius: 19 },
223
- ]);
224
- ```
225
-
226
- ```ts
227
- filletCorners(points: PointInput[], corners: FilletCornerSpec[]): Sketch
228
- ```
229
-
230
- `FilletCornerSpec`: `{ index: number, radius: number, segments?: number }`
231
-
232
- ### Tracked Solid Edge Features
233
-
234
- #### `filletTrackedEdge()` — Round a tracked vertical solid edge with a circular fillet.
235
-
236
- Compiler-owned fillet for a narrow tracked-edge subset on solids.
237
-
238
- This is **not** a general 2D sketch-corner fillet. It currently works only on tracked vertical edges from [`box()`](/docs/core#box) or `Rectangle2D` extrusions (plus rigid transforms and supported preserved descendants of those). Generic sketch extrudes, including `rect(...).extrude(...)`, are outside the supported subset right now.
239
-
240
- **Supported edges:**
241
-
242
- - Tracked vertical edges from [`box()`](/docs/core#box) or `Rectangle2D.extrude()`
243
- - Rigid transforms between tracked source and target
244
- - Untouched sibling tracked vertical edges after earlier `filletTrackedEdge`/`chamferTrackedEdge`
245
-
246
- **Not supported:** edges after shell, hole, cut, trim, difference, intersection, generic sketch extrudes, or tapered extrudes.
247
-
248
- Canonical quadrants: `vert-bl → [1,-1]`, `vert-br → [-1,-1]`, `vert-tr → [-1,1]`, `vert-tl → [1,1]`
249
-
250
- ```ts
251
- const base = Rectangle2D.fromDimensions(0, 0, 50, 50).extrude(20);
252
- const filleted = filletTrackedEdge(base, base.edge('vert-br'), 5, [-1, -1]);
253
- ```
254
-
255
- ```ts
256
- filletTrackedEdge(shape: Shape, edge: EdgeRef, radius: number, quadrant?: [ number, number ], segments?: number): Shape
257
- ```
258
-
259
- **`EdgeRef`**
260
-
261
- | Option | Type | Description |
262
- |--------|------|-------------|
263
- | `start` | `[ number, number, number ]` | Start point |
264
- | `end` | `[ number, number, number ]` | End point |
265
- | `query?` | `EdgeQueryRef` | Compiler-owned edge query when available. |
266
- | `curve?` | `EdgeCurve` | Exact or parametric curve family when the backend/source can identify one. |
267
- | `faceName?` | `string` | Owning face name when the edge is associated with one face in a larger topology. |
268
- | `name` | | — |
269
-
270
- #### `chamferTrackedEdge()` — Bevel a tracked vertical solid edge with a 45° chamfer.
271
-
272
- Compiler-owned chamfer for tracked vertical edges. Requires a compile-plan-covered target. This is not a general 2D sketch-corner tool; supported subset and quadrant semantics are the same as `filletTrackedEdge()` - see that function for details.
273
-
274
- ```ts
275
- const base = Rectangle2D.fromDimensions(0, 0, 50, 50).extrude(20);
276
- const chamfered = chamferTrackedEdge(base, base.edge('vert-br'), 3, [-1, -1]);
277
- ```
278
-
279
- ```ts
280
- chamferTrackedEdge(shape: Shape, edge: EdgeRef, size: number, quadrant?: [ number, number ]): Shape
281
- ```
282
-
283
141
  ### 2D Text
284
142
 
285
- #### `loadFont()` — Pre-load and cache a font for use with `text2d()`.
143
+ #### `loadFont(source: string | ArrayBuffer, cacheKey?: string): opentype.Font` — Pre-load and cache a font for use with `text2d()`.
286
144
 
287
145
  Fonts are cached by their source string (or `cacheKey` for `ArrayBuffer` sources), so repeated calls with the same path are free. Pre-loading is useful when you call `text2d()` many times with the same font — it avoids repeated disk reads.
288
146
 
@@ -296,11 +154,7 @@ text2d('Title', { size: 12, font }).extrude(1.5);
296
154
  text2d('Subtitle', { size: 8, font }).extrude(1);
297
155
  ```
298
156
 
299
- ```ts
300
- loadFont(source: string | ArrayBuffer, cacheKey?: string): opentype.Font
301
- ```
302
-
303
- #### `text2d()` — Build a filled 2D Sketch from a text string.
157
+ #### `text2d(content: string, options?: TextOptions): Sketch` — Build a filled 2D Sketch from a text string.
304
158
 
305
159
  The Sketch origin is at the left end of the text baseline by default. Use `align` and `baseline` options to adjust placement. Text is rendered using the bundled Inter font by default, or any TTF/OTF/WOFF font you provide.
306
160
 
@@ -333,10 +187,6 @@ const font = loadFont('/path/to/Arial Bold.ttf');
333
187
  text2d('Title', { size: 12, font }).extrude(1.5);
334
188
  ```
335
189
 
336
- ```ts
337
- text2d(content: string, options?: TextOptions): Sketch
338
- ```
339
-
340
190
  **`TextOptions`**
341
191
 
342
192
  | Option | Type | Description |
@@ -348,7 +198,7 @@ text2d(content: string, options?: TextOptions): Sketch
348
198
  | `font?` | `string \| opentype.Font` | Font to use for text rendering. - `'sans-serif'` or `'inter'` — bundled Inter font (works everywhere, including browser) - **file path** — path to a TTF, OTF, or WOFF font file (CLI/Node only) - **Font object** — a previously loaded opentype.js Font (from `loadFont()`) - **omitted** — uses the bundled Inter font (same as `'sans-serif'`) |
349
199
  | `flattenTolerance?` | `number` | Bezier flattening tolerance in model units. Smaller = more polygon segments = smoother curves. |
350
200
 
351
- #### `textWidth()` — Measure the rendered advance width of a string without creating any geometry.
201
+ #### `textWidth(content: string, options?: Pick<TextOptions, "size" | "letterSpacing" | "font">): number` — Measure the rendered advance width of a string without creating any geometry.
352
202
 
353
203
  Uses the same font metrics as `text2d()`. Useful for computing layout dimensions before building the actual sketch — e.g. sizing a plate to fit a label.
354
204
 
@@ -357,13 +207,9 @@ const w = textWidth('SERIAL: 001', { size: 6 });
357
207
  const plate = box(w + 10, 12, 2);
358
208
  ```
359
209
 
360
- ```ts
361
- textWidth(content: string, options?: Pick<TextOptions, "size" | "letterSpacing" | "font">): number
362
- ```
363
-
364
210
  ### Constrained Sketches
365
211
 
366
- #### `constrainedSketch()` — Create a parametric 2D sketch driven by geometric constraints and a nonlinear solver.
212
+ #### `constrainedSketch(options?: ConstrainedSketchOptions): ConstrainedSketchBuilder` — Create a parametric 2D sketch driven by geometric constraints and a nonlinear solver.
367
213
 
368
214
  **Workflow**
369
215
 
@@ -394,183 +240,9 @@ result.inspect(); // human-readable summary
394
240
  result.withUpdatedConstraint('cst-5', 120); // update a dimension without rebuilding
395
241
  ```
396
242
 
397
- ```ts
398
- constrainedSketch(options?: ConstrainedSketchOptions): ConstrainedSketchBuilder
399
- ```
400
-
401
243
  **`ConstrainedSketchOptions`**
402
244
  - `strict?: boolean` — When true, adding a constraint that cannot be satisfied throws instead of silently discarding it.
403
245
 
404
- #### `addRect()` — Add an axis-aligned rectangle concept to the builder.
405
-
406
- Creates 4 vertices (CCW: bl→br→tr→tl), 4 sides, 4 structural constraints (`horizontal`/`vertical` on each side), CCW winding, a center point, a loop, and a shape. Returns a `ConstrainedRect` handle with 4 DOF (x, y, width, height).
407
-
408
- Use `sk.rect()` as the shorthand builder method.
409
-
410
- ```ts
411
- const sk = constrainedSketch();
412
- const r = sk.rect({ x: 0, y: 0, width: 100, height: 50 });
413
- sk.fix(r.bottomLeft, 0, 0);
414
- sk.length(r.bottom, 120); // override initial width
415
- return sk.solve().extrude(10);
416
- ```
417
-
418
- ```ts
419
- addRect(sk: ConstrainedSketchBuilder, options?: RectOptions): ConstrainedRect
420
- ```
421
-
422
- **`RectOptions`**
423
-
424
- | Option | Type | Description |
425
- |--------|------|-------------|
426
- | `x?` | `number` | Bottom-left x coordinate. Default: 0. |
427
- | `y?` | `number` | Bottom-left y coordinate. Default: 0. |
428
- | `width?` | `number` | Width (along x). Default: 10. |
429
- | `height?` | `number` | Height (along y). Default: 10. |
430
- | `blockRotation?` | `boolean` | Prevent 180° rotation (ensures bottom edge points rightward). Default: false. |
431
-
432
- **`ConstrainedRect`**
433
-
434
- | Option | Type | Description |
435
- |--------|------|-------------|
436
- | `bottom` | `LineId` | bottom-left → bottom-right |
437
- | `right` | `LineId` | bottom-right → top-right |
438
- | `top` | `LineId` | top-right → top-left |
439
- | `left` | `LineId` | top-left → bottom-left |
440
- | `center` | `PointId` | Center point constrained to the geometric center via `midpoint` on the diagonal. Can be used in further constraints: `sk.fix(rect.center, 0, 0)`, `sk.coincident(rect.center, other)`. |
441
- | `shape` | `ShapeId` | ShapeId for `shapeWidth`, `shapeHeight`, `shapeArea`, `shapeCentroidX/Y`. |
442
- | `vertices` | `[ PointId, PointId, PointId, PointId ]` | CCW-ordered vertex array: [bottomLeft, bottomRight, topRight, topLeft]. |
443
- | `sides` | `[ LineId, LineId, LineId, LineId ]` | CCW-ordered side array: [bottom, right, top, left]. |
444
- | `bottomLeft`, `bottomRight`, `topRight`, `topLeft` | | — |
445
-
446
- #### `addPolygon()` — Add a general polygon concept to the builder.
447
-
448
- Creates n vertices and n sides (CCW: `sides[i]` from `vertices[i]` → `vertices[(i+1) % n]`). Applies a `ccw` constraint to enforce winding. All dimensional constraints (lengths, angles, position) are left to the caller.
449
-
450
- Use `sk.addPolygon()` as the shorthand builder method.
451
-
452
- ```ts
453
- const sk = constrainedSketch();
454
- const tri = sk.addPolygon({ points: [[0,0],[100,0],[50,80]] });
455
- sk.fix(tri.vertex(0), 0, 0);
456
- sk.length(tri.side(0), 100);
457
- return sk.solve().extrude(5);
458
- ```
459
-
460
- ```ts
461
- addPolygon(sk: ConstrainedSketchBuilder, options: PolygonOptions): ConstrainedPolygon
462
- ```
463
-
464
- **`PolygonOptions`**
465
- - `points: ReadonlyArray<readonly [ number, number ]>` — Initial vertex coordinates. Minimum 3 points.
466
- - `addLoop?: boolean` — Whether to register a closed loop for sketch generation. Default: true.
467
- - `blockRotation?: boolean` — Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false.
468
-
469
- **`ConstrainedPolygon`**
470
- - `vertices: PointId[]` — CCW-ordered PointIds.
471
- - `sides: LineId[]` — CCW-ordered LineIds. `sides[i]` runs from `vertices[i]` → `vertices[(i+1) % n]`.
472
- - `shape: ShapeId` — ShapeId for `shapeWidth`, `shapeHeight`, `shapeArea`, `shapeCentroidX/Y`.
473
-
474
- #### `addRegularPolygon()` — Add a regular n-gon concept to the builder.
475
-
476
- Vertices are placed at `(cx + r·cos(startAngle + i·2π/n), cy + r·sin(...))`. Equal-radius and equal-side constraints enforce regularity (4 DOF: center x/y, radius, rotation). The center point is tracked by the solver and exposed via the returned handle.
477
-
478
- Use `sk.regularPolygon()` as the shorthand builder method.
479
-
480
- ```ts
481
- const sk = constrainedSketch();
482
- const hex = sk.regularPolygon({ sides: 6, radius: 25 });
483
- sk.fix(hex.center, 0, 0);
484
- sk.length(hex.side(0), 30); // all sides change (equal constraint)
485
- return sk.solve().extrude(5);
486
- ```
487
-
488
- ```ts
489
- addRegularPolygon(sk: ConstrainedSketchBuilder, options: RegularPolygonOptions): ConstrainedRegularPolygon
490
- ```
491
-
492
- **`RegularPolygonOptions`**
493
-
494
- | Option | Type | Description |
495
- |--------|------|-------------|
496
- | `sides` | `number` | Number of sides (minimum 3). |
497
- | `radius?` | `number` | Circumradius — distance from center to vertex. Default: 10. |
498
- | `cx?` | `number` | Center x coordinate. Default: 0. |
499
- | `cy?` | `number` | Center y coordinate. Default: 0. |
500
- | `startAngle?` | `number` | Angle (in degrees) of vertex[0] measured from the +X axis (CCW positive). Default: 0 (rightmost vertex). |
501
- | `blockRotation?` | `boolean` | Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false. |
502
-
503
- **`ConstrainedRegularPolygon`** extends ConstrainedPolygon
504
- - `center: PointId` — Center point. Use `sk.fix(poly.center, x, y)` to pin location, or `sk.coincident(poly.center, other)` to align with other geometry.
505
-
506
- ### 2D Geometry Helpers
507
-
508
- #### `point()` — Create an analytic 2D point for measurement and construction geometry.
509
-
510
- ```ts
511
- const p = point(10, 20);
512
- p.distanceTo(point(30, 40)); // Euclidean distance
513
- p.midpointTo(point(30, 40)); // midpoint
514
- p.translate(5, 5); // new shifted point
515
- p.toTuple(); // [10, 20]
516
- ```
517
-
518
- ```ts
519
- point(x: number, y: number): Point2D
520
- ```
521
-
522
- #### `line()` — Create an analytic 2D line segment between two points.
523
-
524
- ```ts
525
- const l = line(0, 0, 50, 0);
526
- l.length; l.midpoint; l.angle; l.direction;
527
- l.parallel(10); // parallel line offset 10 (positive = left)
528
- l.intersect(l2); // Point2D — treats lines as infinite
529
- l.intersectSegment(l2); // Point2D or null — segments only
530
-
531
- Line2D.fromPointAndAngle(point(0, 0), 45, 100);
532
- Line2D.fromPointAndDirection(point(0, 0), [1, 1], 50);
533
- ```
534
-
535
- ```ts
536
- line(x1: number, y1: number, x2: number, y2: number): Line2D
537
- ```
538
-
539
- #### `circle()` — Create an analytic 2D circle for measurement, construction, and extrusion.
540
-
541
- ```ts
542
- const c = circle(0, 0, 25);
543
- c.diameter; c.circumference; c.area;
544
- c.pointAtAngle(90); // Point2D at top (90° CCW from +X)
545
-
546
- // Extrude to cylinder with named faces
547
- const cyl = c.extrude(30);
548
- cyl.face('top'); // FaceRef (planar)
549
- cyl.face('side'); // FaceRef (curved)
550
-
551
- Circle2D.fromDiameter(point(0, 0), 50);
552
- ```
553
-
554
- ```ts
555
- circle(cx: number, cy: number, radius: number): Circle2D
556
- ```
557
-
558
- #### `degrees()` — Identity function that returns degrees unchanged.
559
-
560
- Use for clarity when the unit of an angle value would otherwise be ambiguous — e.g. `param("Angle", degrees(45))`.
561
-
562
- ```ts
563
- degrees(deg: number): number
564
- ```
565
-
566
- #### `radians()` — Convert radians to degrees.
567
-
568
- ForgeCAD's public API uses degrees throughout. Use this when you have a radian value (e.g. from `Math.atan2`) that you want to express in degrees.
569
-
570
- ```ts
571
- radians(rad: number): number
572
- ```
573
-
574
246
  ---
575
247
 
576
248
  ## Classes
@@ -585,7 +257,7 @@ Supported operations:
585
257
 
586
258
  - **Transforms** — `translate`, `rotate`, `rotateAround`, `scale`, `mirror`
587
259
  - **Booleans** — `add` (union), `subtract` (difference), `intersect`
588
- - **Operations** — `offset`, `simplify`
260
+ - **Operations** — `offset`, `simplify`, `filletCorners`, `filletCorner`, `chamferCorners`, `chamferCorner`
589
261
  - **Queries** — `area`, `bounds`, `isEmpty`, `numVert`
590
262
  - **3D operations** — `extrude`, `revolve`, `onFace`
591
263
  - **Regions** — `regions`, `region`
@@ -601,59 +273,31 @@ Named anchor positions used by `attachTo()`: `'center'` | `'top-left'` | `'top-r
601
273
 
602
274
  **Transforms**
603
275
 
604
- #### `translate()` — Move the sketch by the given X and Y offset.
276
+ #### `translate(x: number, y?: number): Sketch` — Move the sketch by the given X and Y offset.
605
277
 
606
- ```ts
607
- translate(x: number, y?: number): Sketch
608
- ```
609
-
610
- #### `rotate()` — Rotate the sketch around its bounding-box center.
611
-
612
- ```ts
613
- rotate(degrees: number): Sketch
614
- ```
278
+ #### `rotate(degrees: number): Sketch` — Rotate the sketch around its bounding-box center.
615
279
 
616
- #### `rotateAround()` — Rotate the sketch around a specific pivot point.
280
+ #### `rotateAround(degrees: number, pivot: Vec2): Sketch` — Rotate the sketch around a specific pivot point.
617
281
 
618
282
  ```ts
619
283
  rect(20, 20).rotateAround(45, [0, 0]);
620
284
  ```
621
285
 
622
- ```ts
623
- rotateAround(degrees: number, pivot: [ number, number ]): Sketch
624
- ```
625
-
626
- #### `scale()` — Scale the sketch relative to its bounding-box center.
286
+ #### `scale(v: number | Vec2): Sketch` — Scale the sketch relative to its bounding-box center.
627
287
 
628
288
  Pass a single number for uniform scaling, or `[sx, sy]` for per-axis scaling.
629
289
 
630
- ```ts
631
- scale(v: number | [ number, number ]): Sketch
632
- ```
633
-
634
- #### `scaleAround()` — Scale the sketch relative to an arbitrary pivot point.
290
+ #### `scaleAround(pivot: Vec2, v: number | Vec2): Sketch` — Scale the sketch relative to an arbitrary pivot point.
635
291
 
636
- ```ts
637
- scaleAround(pivot: [ number, number ], v: number | [ number, number ]): Sketch
638
- ```
639
-
640
- #### `mirror()` — Mirror the sketch across a line through its bounding-box center.
292
+ #### `mirror(normal: Vec2): Sketch` — Mirror the sketch across a line through its bounding-box center.
641
293
 
642
294
  `normal` is the normal vector of the mirror line (not the line direction). For example, `[1, 0]` mirrors across a vertical line (Y axis direction), and `[0, 1]` mirrors across a horizontal line.
643
295
 
644
- ```ts
645
- mirror(normal: [ number, number ]): Sketch
646
- ```
647
-
648
- #### `mirrorThrough()` — Mirror the sketch across a line defined by a point and a normal direction.
649
-
650
- ```ts
651
- mirrorThrough(point: [ number, number ], normal: [ number, number ]): Sketch
652
- ```
296
+ #### `mirrorThrough(point: Vec2, normal: Vec2): Sketch` — Mirror the sketch across a line defined by a point and a normal direction.
653
297
 
654
298
  **Booleans**
655
299
 
656
- #### `add()` — Add (union) one or more sketches to this sketch.
300
+ #### `add(...others: SketchOperandInput[]): Sketch` — Add (union) one or more sketches to this sketch.
657
301
 
658
302
  Accepts individual sketches or arrays: `sketch.add(a, b)` or `sketch.add([a, b])`. For combining many sketches at once, prefer the free function `union2d()` which uses Manifold's batch operation and is faster than chaining.
659
303
 
@@ -661,11 +305,7 @@ Accepts individual sketches or arrays: `sketch.add(a, b)` or `sketch.add([a, b])
661
305
  circle2d(20).add(rect(10, 30)).extrude(5);
662
306
  ```
663
307
 
664
- ```ts
665
- add(...others: SketchOperandInput[]): Sketch
666
- ```
667
-
668
- #### `subtract()` — Subtract one or more sketches from this sketch.
308
+ #### `subtract(...others: SketchOperandInput[]): Sketch` — Subtract one or more sketches from this sketch.
669
309
 
670
310
  Accepts individual sketches or arrays: `sketch.subtract(a, b)` or `sketch.subtract([a, b])`. For subtracting many cutters at once, prefer the free function `difference2d()`.
671
311
 
@@ -673,81 +313,91 @@ Accepts individual sketches or arrays: `sketch.subtract(a, b)` or `sketch.subtra
673
313
  rect(40, 40).subtract(circle2d(10)).extrude(5);
674
314
  ```
675
315
 
676
- ```ts
677
- subtract(...others: SketchOperandInput[]): Sketch
678
- ```
679
-
680
- #### `intersect()` — Intersect this sketch with one or more others (keep overlapping area only).
316
+ #### `intersect(...others: SketchOperandInput[]): Sketch` — Intersect this sketch with one or more others (keep overlapping area only).
681
317
 
682
318
  Accepts individual sketches or arrays: `sketch.intersect(a, b)` or `sketch.intersect([a, b])`. For intersecting many sketches, prefer the free function `intersection2d()`.
683
319
 
684
- ```ts
685
- intersect(...others: SketchOperandInput[]): Sketch
686
- ```
687
-
688
320
  **Features**
689
321
 
690
- #### `offset()` — Inflate (positive delta) or deflate (negative delta) the sketch contour.
322
+ #### `offset(delta: number, join?: "Square" | "Round" | "Miter"): Sketch` — Inflate (positive delta) or deflate (negative delta) the sketch contour.
691
323
 
692
- Use `offset(-r).offset(+r)` to round every convex corner of a closed sketch.
324
+ For rounding corners, prefer `filletCorners(radius)` (all corners) or `filletCorner([x, y], radius)` (one corner) — they round only true corners and keep concave geometry exact.
693
325
 
694
326
  - `'Round'` — smooth arc at each corner (default)
695
327
  - `'Square'` — flat mitered extension
696
328
  - `'Miter'` — sharp pointed extension
697
329
 
698
330
  ```ts
699
- rect(40, 20).offset(3); // expand by 3
700
- rect(40, 20).offset(-2).offset(2); // round all convex corners
331
+ rect(40, 20).offset(3); // expand by 3
701
332
  ```
702
333
 
703
- ```ts
704
- offset(delta: number, join?: "Square" | "Round" | "Miter"): Sketch
705
- ```
334
+ #### `filletCorners(radius: number): Sketch` — Round every significant corner of this sketch with the same fillet radius.
706
335
 
707
- #### `regions()`Decompose this sketch into its distinct filled regions, sorted largest-first by area.
336
+ Works on any sketch primitives, boolean results, attached or composed profiles. A vertex counts as a corner when its turn angle is at least 30°, so vertices that belong to tessellated circles or earlier fillets are left untouched. Both convex and concave corners are rounded. Holes are preserved, and their corners are rounded too.
708
337
 
709
- A single sketch can contain several disconnected filled areas (e.g., two separate rectangles, or a ring shape with a hole). This method enumerates all top-level connected regions as independent `Sketch` objects, each with its own outer boundary and associated holes.
338
+ Throws if the sketch has no significant corners, or if the radius does not fit a corner (the error names the corner and the maximum radius).
710
339
 
711
340
  ```ts
712
- const pair = union2d(rect(40, 40), rect(40, 40).translate(60, 0));
713
- const [left, right] = pair.regions(); // largest first
714
- left.extrude(5);
341
+ rect(60, 30).filletCorners(5).extrude(4); // rounded plate
342
+ polygon(bracketPts).filletCorners(3); // every corner of an outline
715
343
  ```
716
344
 
345
+ #### `filletCorner(at: Vec2, radius: number): Sketch` — Round the single corner of this sketch nearest to a seed point.
346
+
347
+ Selects the significant corner (turn angle ≥ 30°) closest to `at` — the seed does not need to be exact, just nearer to the intended corner than to any other (like `region([x, y])` seed selection). Throws if two corners are equidistant from the seed, naming both so you can move the seed.
348
+
349
+ Chain calls to round several corners with different radii.
350
+
717
351
  ```ts
718
- regions(): Sketch[]
352
+ polygon(roofPts)
353
+ .filletCorner([45, 86], 14) // peak
354
+ .filletCorner([24, 74], 8); // left shoulder
719
355
  ```
720
356
 
721
- #### `region()` — Select the single filled region that contains the given 2D seed point.
357
+ #### `chamferCorners(size: number): Sketch` — Bevel every significant corner of this sketch with a straight chamfer.
722
358
 
723
- The seed must lie strictly inside the filled area not on a boundary edge and not inside a hole. Throws a descriptive error if the seed is outside all regions. If unsure where regions are, use `.regions()` first each result has `.bounds()`.
359
+ Replaces each significant corner (turn angle 30°) with a straight cut set back `size` along both adjacent edges. Tessellated arcs are left untouched; holes are preserved. Throws if the sketch has no significant corners or the size does not fit a corner.
724
360
 
725
361
  ```ts
726
- const donut = circle2d(50).subtract(circle2d(30));
727
- donut.region([40, 0]).extrude(10); // seed at radius 40, inside the ring
362
+ rect(60, 30).chamferCorners(4).extrude(4); // beveled plate outline
728
363
  ```
729
364
 
365
+ #### `chamferCorner(at: Vec2, size: number): Sketch` — Bevel the single corner of this sketch nearest to a seed point.
366
+
367
+ Selects the significant corner (turn angle ≥ 30°) closest to `at` and replaces it with a straight cut set back `size` along both adjacent edges. Throws if two corners are equidistant from the seed. Chain calls to bevel several corners with different sizes.
368
+
730
369
  ```ts
731
- region(seed: [ number, number ]): Sketch
370
+ rect(60, 30).chamferCorner([30, 15], 6); // bevel only the top-right corner
732
371
  ```
733
372
 
734
- **Promotion**
373
+ #### `regions(): Sketch[]` — Decompose this sketch into its distinct filled regions, sorted largest-first by area.
735
374
 
736
- #### `extrude()` Extrude this 2D sketch along Z to create a 3D solid. Supports twist and scale tapering.
375
+ A single sketch can contain several disconnected filled areas (e.g., two separate rectangles, or a ring shape with a hole). This method enumerates all top-level connected regions as independent `Sketch` objects, each with its own outer boundary and associated holes.
737
376
 
738
377
  ```ts
739
- extrude(height: number, opts?: { twist?: number; divisions?: number; scaleTop?: number | [ number, number ]; }): Shape
378
+ const pair = union2d(rect(40, 40), rect(40, 40).translate(60, 0));
379
+ const [left, right] = pair.regions(); // largest first
380
+ left.extrude(5);
740
381
  ```
741
382
 
742
- #### `revolve()` — Revolve this 2D sketch around the world Z axis. Sketch X is radius; sketch Y becomes world Z height.
383
+ #### `region(seed: Vec2): Sketch` — Select the single filled region that contains the given 2D seed point.
384
+
385
+ The seed must lie strictly inside the filled area — not on a boundary edge and not inside a hole. Throws a descriptive error if the seed is outside all regions. If unsure where regions are, use `.regions()` first — each result has `.bounds()`.
743
386
 
744
387
  ```ts
745
- revolve(degrees?: number, segments?: number): Shape
388
+ const donut = circle2d(50).subtract(circle2d(30));
389
+ donut.region([40, 0]).extrude(10); // seed at radius 40, inside the ring
746
390
  ```
747
391
 
392
+ **Promotion**
393
+
394
+ #### `extrude(height: number, opts?: { twist?: number; divisions?: number; scaleTop?: number | Vec2; }): Shape` — Extrude this 2D sketch along Z to create a 3D solid. Supports twist and scale tapering.
395
+
396
+ #### `revolve(degrees?: number, segments?: number): Shape` — Revolve this 2D sketch around the world Z axis. Sketch X is radius; sketch Y becomes world Z height. Keep the profile at X > 0 unless it intentionally touches the axis.
397
+
748
398
  **Placement**
749
399
 
750
- #### `attachTo()` — Position this sketch relative to another using named anchor points.
400
+ #### `attachTo(target: Sketch, targetAnchor: Anchor, selfAnchor?: Anchor, offset?: Vec2): Sketch` — Position this sketch relative to another using named anchor points.
751
401
 
752
402
  Computes the translation needed to align `selfAnchor` on this sketch with `targetAnchor` on the target sketch, then applies an optional pixel-exact offset.
753
403
 
@@ -758,117 +408,47 @@ const arm = rect(4, 70).attachTo(plate, 'bottom-left', 'top-left');
758
408
  const shifted = rect(4, 70).attachTo(plate, 'bottom-left', 'top-left', [5, 0]);
759
409
  ```
760
410
 
761
- ```ts
762
- attachTo(target: Sketch, targetAnchor: Anchor, selfAnchor?: Anchor, offset?: [ number, number ]): Sketch
763
- ```
764
-
765
- #### `onFace()` — Place this sketch on a face or planar target in 3D space.
411
+ #### `onFace(parentOrFace: Shape | { toShape(): Shape; } | { _bbox(): { min: number[]; max: number[]; }; } | FaceRef, faceOrOpts?: "front" | "back" | "left" | "right" | "top" | "bottom" | string | FaceRef | { u?: number; v?: number; protrude?: number; selfAnchor?: Anchor; }, opts?: { u?: number; v?: number; protrude?: number; selfAnchor?: Anchor; }): Sketch` — Place this sketch on a face or planar target in 3D space.
766
412
 
767
413
  Use this when a 2D profile should be oriented onto a 3D face before extrusion or other downstream operations.
768
414
 
769
- ```ts
770
- onFace(parentOrFace: Shape | { toShape(): Shape; } | { _bbox(): { min: number[]; max: number[]; }; } | FaceRef, faceOrOpts?: "front" | "back" | "left" | "right" | "top" | "bottom" | string | FaceRef | { u?: number; v?: number; protrude?: number; selfAnchor?: Anchor; }, opts?: { u?: number; v?: number; protrude?: number; selfAnchor?: Anchor; }): Sketch
771
- ```
415
+ `FaceRef` — defined in [core](/docs/core).
772
416
 
773
- **`FaceRef`**
417
+ **Labels**
774
418
 
775
- | Option | Type | Description |
776
- |--------|------|-------------|
777
- | `normal` | `[ number, number, number ]` | Normal direction of the face |
778
- | `center` | `[ number, number, number ]` | Center point of the face |
779
- | `query?` | `FaceQueryRef` | Compiler-owned face query when available. |
780
- | `planar?` | `boolean` | True when the face can host a 2D sketch placement frame |
781
- | `uAxis?` | `[ number, number, number ]` | Face-local horizontal axis for planar faces |
782
- | `vAxis?` | `[ number, number, number ]` | Face-local vertical axis for planar faces |
783
- | `surface?` | `FaceSurface` | Analytic surface family when the backend can identify one. |
784
- | `descendant?` | `FaceDescendantMetadata` | Shared descendant-resolution metadata when this face is a semantic region/set. |
785
- | `name` | | — |
786
-
787
- **`FaceDescendantMetadata`**: `kind: "single" | "face-set"`, `semantic: FaceDescendantSemantic`, `memberCount: number`, `memberNames: string[]`, `coplanar: boolean`
788
-
789
- **Labels**
790
-
791
- #### `labelEdge()` — Label the single boundary edge (for circles, single-loop profiles). Returns a new sketch.
792
-
793
- ```ts
794
- labelEdge(name: string): Sketch
795
- ```
419
+ #### `labelEdge(name: string): Sketch` Label the single boundary edge (for circles, single-loop profiles). Returns a new sketch.
796
420
 
797
- #### `labelEdges()` — Label edges in winding order, or by named map for rect.
421
+ #### `labelEdges(...args: (string | null)[] | [ Record<string, string> ]): Sketch` — Label edges in winding order, or by named map for rect.
798
422
 
799
423
  Positional: `labelEdges('bottom', 'right', 'top', 'left')` — one per edge, `null` to skip. Named (rect only): `labelEdges({ bottom: 'floor', top: 'ceiling' })`. Returns a new sketch.
800
424
 
801
- ```ts
802
- labelEdges(...args: (string | null)[] | [ Record<string, string> ]): Sketch
803
- ```
804
-
805
- #### `edgeLabels()` — List current edge label names.
806
-
807
- ```ts
808
- edgeLabels(): string[]
809
- ```
810
-
811
- #### `prefixLabels()` — Prefix all edge labels. Returns a new sketch with prefixed labels.
425
+ #### `edgeLabels(): string[]` — List current edge label names.
812
426
 
813
- ```ts
814
- prefixLabels(prefix: string): Sketch
815
- ```
816
-
817
- #### `renameLabel()` — Rename a single edge label. Returns a new sketch.
818
-
819
- ```ts
820
- renameLabel(from: string, to: string): Sketch
821
- ```
822
-
823
- #### `dropLabels()` — Remove specific labels. Returns a new sketch.
427
+ #### `prefixLabels(prefix: string): Sketch` — Prefix all edge labels. Returns a new sketch with prefixed labels.
824
428
 
825
- ```ts
826
- dropLabels(...names: string[]): Sketch
827
- ```
429
+ #### `renameLabel(from: string, to: string): Sketch` — Rename a single edge label. Returns a new sketch.
828
430
 
829
- #### `dropAllLabels()` — Remove all labels. Returns a new sketch.
431
+ #### `dropLabels(...names: string[]): Sketch` — Remove specific labels. Returns a new sketch.
830
432
 
831
- ```ts
832
- dropAllLabels(): Sketch
833
- ```
433
+ #### `dropAllLabels(): Sketch` — Remove all labels. Returns a new sketch.
834
434
 
835
435
  **Measurement**
836
436
 
837
- #### `area()` — Return the total filled area of the sketch.
838
-
839
- ```ts
840
- area(): number
841
- ```
842
-
843
- #### `bounds()` — Return the axis-aligned bounding box of the sketch.
844
-
845
- ```ts
846
- bounds(): ProfileBounds
847
- ```
437
+ #### `area(): number` — Return the total filled area of the sketch.
848
438
 
849
- #### `isEmpty()` — Return `true` if the sketch contains no filled area.
850
-
851
- ```ts
852
- isEmpty(): boolean
853
- ```
439
+ #### `bounds(): ProfileBounds` — Return the axis-aligned bounding box of the sketch.
854
440
 
855
- #### `numVert()` — Return the number of vertices in the polygon representation of the sketch contours.
441
+ #### `isEmpty(): boolean` — Return `true` if the sketch contains no filled area.
856
442
 
857
- ```ts
858
- numVert(): number
859
- ```
443
+ #### `numVert(): number` — Return the number of vertices in the polygon representation of the sketch contours.
860
444
 
861
- #### `toPolygons()` — Return the sketch as a list of polygons matching its contour topology.
445
+ #### `toPolygons(): number[][][]` — Return the sketch as a list of polygons matching its contour topology.
862
446
 
863
447
  Useful when you need raw polygon data for inspection or custom export.
864
448
 
865
- ```ts
866
- toPolygons(): number[][][]
867
- ```
868
-
869
449
  **Other**
870
450
 
871
- #### `color()` — Set the display color of this sketch.
451
+ #### `color(value: string | undefined): Sketch` — Set the display color of this sketch.
872
452
 
873
453
  Color is preserved through all transforms and boolean operations. Pass `undefined` to clear the color.
874
454
 
@@ -876,129 +456,53 @@ Color is preserved through all transforms and boolean operations. Pass `undefine
876
456
  circle2d(20).color('#ff0000').extrude(5);
877
457
  ```
878
458
 
879
- ```ts
880
- color(value: string | undefined): Sketch
881
- ```
882
-
883
- #### `clone()` — Create an explicit copy of this sketch for branching variants.
459
+ #### `clone(): Sketch` — Create an explicit copy of this sketch for branching variants.
884
460
 
885
461
  Because all Sketch operations are immutable, `clone()` is rarely needed. Use it when you want to assign the same sketch to multiple names and continue modifying each independently without confusion.
886
462
 
887
- ```ts
888
- clone(): Sketch
889
- ```
890
-
891
463
  ### `ConstrainedSketchBuilder`
892
464
 
893
465
  **Drawing**
894
466
 
895
- #### `moveTo()` — Move the cursor to `(x, y)` and start a new profile loop.
896
-
897
- ```ts
898
- moveTo(x: number, y: number): this
899
- ```
900
-
901
- #### `lineTo()` — Draw a line from the current cursor to `(x, y)`.
902
-
903
- ```ts
904
- lineTo(x: number, y: number): this
905
- ```
906
-
907
- #### `lineH()` — Draw a horizontal line of length `dx` from the current cursor.
908
-
909
- ```ts
910
- lineH(dx: number): this
911
- ```
912
-
913
- #### `lineV()` — Draw a vertical line of length `dy` from the current cursor.
914
-
915
- ```ts
916
- lineV(dy: number): this
917
- ```
918
-
919
- #### `lineAngled()` — Draw a line of the given `length` at `degrees` from +X.
920
-
921
- ```ts
922
- lineAngled(length: number, degrees: number): this
923
- ```
924
-
925
- #### `arcTo()` — Draw a circular arc from the current cursor to `(x, y)` with the given radius.
926
-
927
- ```ts
928
- arcTo(x: number, y: number, radius: number, clockwise?: boolean): this
929
- ```
930
-
931
- #### `arcByCenter()` — Create an arc from an explicit center point and endpoint IDs.
467
+ #### `moveTo(x: number, y: number): this` — Move the cursor to `(x, y)` and start a new profile loop.
932
468
 
933
- ```ts
934
- arcByCenter(centerId: PointId, startId: PointId, endId: PointId, clockwise?: boolean, name?: string, fixedRadius?: boolean): ArcId
935
- ```
936
-
937
- #### `bezier()` — Create a cubic Bezier curve from four control points.
938
-
939
- ```ts
940
- bezier(p0: any, p1: any, p2: any, p3: any, name?: string): BezierId
941
- ```
942
-
943
- #### `bezierTo()` — Draw a cubic Bezier from the current cursor to `(x3, y3)`.
469
+ #### `lineTo(x: number, y: number): this` — Draw a line from the current cursor to `(x, y)`.
944
470
 
945
- ```ts
946
- bezierTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): this
947
- ```
471
+ #### `lineH(dx: number): this` — Draw a horizontal line of length `dx` from the current cursor.
948
472
 
949
- #### `blendTo()` — Draw a smooth Bezier tangent to the previous arc.
473
+ #### `lineV(dy: number): this` — Draw a vertical line of length `dy` from the current cursor.
950
474
 
951
- ```ts
952
- blendTo(x: number, y: number, weight?: number): this
953
- ```
475
+ #### `lineAngled(length: number, degrees: number): this` — Draw a line of the given `length` at `degrees` from +X.
954
476
 
955
- #### `label()` — Label the current path segment.
477
+ #### `arcTo(x: number, y: number, radius: number, clockwise?: boolean): this` — Draw a circular arc from the current cursor to `(x, y)` with the given radius.
956
478
 
957
- ```ts
958
- label(name: string): this
959
- ```
479
+ #### `arcByCenter(centerId: PointId, startId: PointId, endId: PointId, clockwise?: boolean, name?: string, fixedRadius?: boolean): ArcId` — Create an arc from an explicit center point and endpoint IDs.
960
480
 
961
- #### `close()` — Close the current path and register the loop.
481
+ #### `bezier(p0: any, p1: any, p2: any, p3: any, name?: string): BezierId` — Create a cubic Bezier curve from four control points.
962
482
 
963
- ```ts
964
- close(): this
965
- ```
483
+ #### `bezierTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): this` — Draw a cubic Bezier from the current cursor to `(x3, y3)`.
966
484
 
967
- #### `addLoopCircle()` — Add a circle loop to the path.
485
+ #### `blendTo(x: number, y: number, weight?: number): this` — Draw a smooth Bezier tangent to the previous arc.
968
486
 
969
- ```ts
970
- addLoopCircle(center: PointId, radius: number, segments?: number): this
971
- ```
487
+ #### `label(name: string): this` — Label the current path segment.
972
488
 
973
- #### `addLoop()` — Add a closed polygon loop from point IDs.
489
+ #### `close(): this` — Close the current path and register the loop.
974
490
 
975
- ```ts
976
- addLoop(points: any[]): this
977
- ```
491
+ #### `addLoopCircle(center: PointId, radius: number, segments?: number): this` — Add a circle loop to the path.
978
492
 
979
- #### `addProfileLoop()` — Add a profile loop from prebuilt line/arc/bezier segments.
493
+ #### `addLoop(points: any[]): this` — Add a closed polygon loop from point IDs.
980
494
 
981
- ```ts
982
- addProfileLoop(segments: Array<{ kind: "line"; line: any; } | { kind: "arc"; arc: any; } | { kind: "bezier"; bezier: any; }>): this
983
- ```
495
+ #### `addProfileLoop(segments: Array<{ kind: "line"; line: any; } | { kind: "arc"; arc: any; } | { kind: "bezier"; bezier: any; }>): this` — Add a profile loop from prebuilt line/arc/bezier segments.
984
496
 
985
497
  **Entities**
986
498
 
987
- #### `point()` — Add a free point to the sketch at `(x, y)`.
499
+ #### `point(x?: number, y?: number, fixed?: boolean): PointId` — Add a free point to the sketch at `(x, y)`.
988
500
 
989
501
  If `x` or `y` are omitted, the point is placed at the bounding-box center of existing geometry so it starts near other entities rather than at the origin. Throws if either coordinate is `NaN` or `Infinity`.
990
502
 
991
- ```ts
992
- point(x?: number, y?: number, fixed?: boolean): PointId
993
- ```
503
+ #### `pointAt(index: number): PointId` — Return the `PointId` of the point created at the given insertion index.
994
504
 
995
- #### `pointAt()` Return the `PointId` of the point created at the given insertion index.
996
-
997
- ```ts
998
- pointAt(index: number): PointId
999
- ```
1000
-
1001
- #### `line()` — Connect two existing points with a line segment.
505
+ #### `line(a: PointId, b: PointId, construction?: boolean, name?: string): LineId` Connect two existing points with a line segment.
1002
506
 
1003
507
  Pass `construction = true` for a helper line that participates in constraints but is excluded from the solved sketch output (not part of any profile loop).
1004
508
 
@@ -1007,39 +511,19 @@ const axis = sk.line(sk.point(0, -50), sk.point(0, 50), true);
1007
511
  sk.symmetric(p1, p2, axis);
1008
512
  ```
1009
513
 
1010
- ```ts
1011
- line(a: PointId, b: PointId, construction?: boolean, name?: string): LineId
1012
- ```
1013
-
1014
- #### `lineAt()` — Return the `LineId` of the line created at the given insertion index.
514
+ #### `lineAt(index: number): LineId` — Return the `LineId` of the line created at the given insertion index.
1015
515
 
1016
- ```ts
1017
- lineAt(index: number): LineId
1018
- ```
1019
-
1020
- #### `circle()` — Add a circle to the sketch with the given center point and initial radius.
516
+ #### `circle(center: PointId, radius: number, construction?: boolean, segments?: number, name?: string): CircleId` — Add a circle to the sketch with the given center point and initial radius.
1021
517
 
1022
518
  The radius is a starting value — if you add a `radius()` or `diameter()` constraint, the solver will adjust it. Non-construction circles automatically register a loop.
1023
519
 
1024
- ```ts
1025
- circle(center: PointId, radius: number, construction?: boolean, segments?: number, name?: string): CircleId
1026
- ```
1027
-
1028
- #### `circleAt()` — Return the `CircleId` of the circle created at the given insertion index.
1029
-
1030
- ```ts
1031
- circleAt(index: number): CircleId
1032
- ```
520
+ #### `circleAt(index: number): CircleId` — Return the `CircleId` of the circle created at the given insertion index.
1033
521
 
1034
- #### `shape()` — Register a named shape (closed polygon) from an ordered list of line IDs.
522
+ #### `shape(lines: LineId[]): ShapeId` — Register a named shape (closed polygon) from an ordered list of line IDs.
1035
523
 
1036
524
  The `ShapeId` can be passed to `shapeWidth()`, `shapeHeight()`, `shapeArea()`, `shapeCentroidX()`, `shapeCentroidY()`, and `shapeEqualCentroid()` constraints. Shape registration is done automatically by concept factories like `rect()` and `addPolygon()`.
1037
525
 
1038
- ```ts
1039
- shape(lines: LineId[]): ShapeId
1040
- ```
1041
-
1042
- #### [`group()`](/docs/core#group) — Create a rigid-body group with a local coordinate frame.
526
+ #### `group(opts?: { x?: number; y?: number; theta?: number; id?: string; }): SketchGroupBuilder` — Create a rigid-body group with a local coordinate frame.
1043
527
 
1044
528
  Points and lines added to the group move together as a unit — the solver sees 3 DOF (x, y, θ) instead of 2N per point. After configuring the group, call `.done()` to register it and receive a `SketchGroupHandle`.
1045
529
 
@@ -1056,33 +540,39 @@ const handle = g.done();
1056
540
  sk.coincident(p0, someExternalPoint);
1057
541
  ```
1058
542
 
1059
- ```ts
1060
- group(opts?: { x?: number; y?: number; theta?: number; id?: string; }): SketchGroupBuilder
1061
- ```
543
+ #### `rect(options?: RectOptions): ConstrainedRect` — Add an axis-aligned rectangle concept. Returns a `ConstrainedRect` handle with named vertices, sides, and center.
1062
544
 
1063
- #### `rect()` — Add an axis-aligned rectangle concept. Returns a `ConstrainedRect` handle with named vertices, sides, and center.
545
+ **`RectOptions`**
1064
546
 
1065
- ```ts
1066
- rect(options?: RectOptions): ConstrainedRect
1067
- ```
547
+ | Option | Type | Description |
548
+ |--------|------|-------------|
549
+ | `x?` | `number` | Bottom-left x coordinate. Default: 0. |
550
+ | `y?` | `number` | Bottom-left y coordinate. Default: 0. |
551
+ | `width?` | `number` | Width (along x). Default: 10. |
552
+ | `height?` | `number` | Height (along y). Default: 10. |
553
+ | `blockRotation?` | `boolean` | Prevent 180° rotation (ensures bottom edge points rightward). Default: false. |
1068
554
 
1069
- #### `addPolygon()` — Add a general polygon concept (CCW winding enforced). Returns a `ConstrainedPolygon` handle.
555
+ #### `addPolygon(options: PolygonOptions): ConstrainedPolygon` — Add a general polygon concept (CCW winding enforced). Returns a `ConstrainedPolygon` handle.
1070
556
 
1071
- ```ts
1072
- addPolygon(options: PolygonOptions): ConstrainedPolygon
1073
- ```
557
+ **`PolygonOptions`**
558
+ - `points: ReadonlyArray<readonly Vec2>` — Initial vertex coordinates. Minimum 3 points.
559
+ - `addLoop?: boolean` — Whether to register a closed loop for sketch generation. Default: true.
560
+ - `blockRotation?: boolean` — Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false.
1074
561
 
1075
- #### `regularPolygon()` — Add a regular n-gon concept (equal sides, CCW winding). Returns a `ConstrainedRegularPolygon` handle with a center point.
562
+ #### `regularPolygon(options: RegularPolygonOptions): ConstrainedRegularPolygon` — Add a regular n-gon concept (equal sides, CCW winding). Returns a `ConstrainedRegularPolygon` handle with a center point.
1076
563
 
1077
- ```ts
1078
- regularPolygon(options: RegularPolygonOptions): ConstrainedRegularPolygon
1079
- ```
564
+ **`RegularPolygonOptions`**
1080
565
 
1081
- #### `groupRect()` Add a rigid rectangle as a group concept. Returns a `ConstrainedGroupRect` handle with named vertices and sides. The rectangle is fixed in shape — only position (and optionally rotation) varies.
566
+ | Option | Type | Description |
567
+ |--------|------|-------------|
568
+ | `sides` | `number` | Number of sides (minimum 3). |
569
+ | `radius?` | `number` | Circumradius — distance from center to vertex. Default: 10. |
570
+ | `cx?` | `number` | Center x coordinate. Default: 0. |
571
+ | `cy?` | `number` | Center y coordinate. Default: 0. |
572
+ | `startAngle?` | `number` | Angle (in degrees) of vertex[0] measured from the +X axis (CCW positive). Default: 0 (rightmost vertex). |
573
+ | `blockRotation?` | `boolean` | Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false. |
1082
574
 
1083
- ```ts
1084
- groupRect(options: GroupRectOptions): ConstrainedGroupRect
1085
- ```
575
+ #### `groupRect(options: GroupRectOptions): ConstrainedGroupRect` — Add a rigid rectangle as a group concept. Returns a `ConstrainedGroupRect` handle with named vertices and sides. The rectangle is fixed in shape — only position (and optionally rotation) varies.
1086
576
 
1087
577
  **`GroupRectOptions`**
1088
578
 
@@ -1096,325 +586,115 @@ groupRect(options: GroupRectOptions): ConstrainedGroupRect
1096
586
 
1097
587
  **Geometric Constraints**
1098
588
 
1099
- #### `horizontal()` — Constrain a line to be horizontal (parallel to the X axis).
1100
-
1101
- ```ts
1102
- horizontal(line: any): this
1103
- ```
1104
-
1105
- #### `vertical()` — Constrain a line to be vertical (parallel to the Y axis).
1106
-
1107
- ```ts
1108
- vertical(line: any): this
1109
- ```
1110
-
1111
- #### `parallel()` — Constrain two lines to be parallel.
1112
-
1113
- ```ts
1114
- parallel(a: any, b: any): this
1115
- ```
1116
-
1117
- #### `sameDirection()` — Constrain two lines to point in the same direction.
589
+ #### `horizontal(line: any): this` — Constrain a line to be horizontal (parallel to the X axis).
1118
590
 
1119
- ```ts
1120
- sameDirection(a: any, b: any): this
1121
- ```
1122
-
1123
- #### `oppositeDirection()` — Constrain two lines to point in opposite directions.
1124
-
1125
- ```ts
1126
- oppositeDirection(a: any, b: any): this
1127
- ```
1128
-
1129
- #### `perpendicular()` — Constrain two lines to be perpendicular.
591
+ #### `vertical(line: any): this` — Constrain a line to be vertical (parallel to the Y axis).
1130
592
 
1131
- ```ts
1132
- perpendicular(a: any, b: any): this
1133
- ```
593
+ #### `parallel(a: any, b: any): this` — Constrain two lines to be parallel.
1134
594
 
1135
- #### `tangent()` — Constrain a line/circle or circle/circle tangency relationship.
595
+ #### `sameDirection(a: any, b: any): this` — Constrain two lines to point in the same direction.
1136
596
 
1137
- ```ts
1138
- tangent(a: any, b: any): this
1139
- ```
597
+ #### `oppositeDirection(a: any, b: any): this` — Constrain two lines to point in opposite directions.
1140
598
 
1141
- #### `collinear()` — Constrain a point to lie on the infinite extension of a line.
1142
-
1143
- ```ts
1144
- collinear(point: any, line: any): this
1145
- ```
599
+ #### `perpendicular(a: any, b: any): this` — Constrain two lines to be perpendicular.
1146
600
 
1147
- #### `symmetric()` — Constrain two points to be symmetric about an axis line.
601
+ #### `tangent(a: any, b: any): this` — Constrain a line/circle or circle/circle tangency relationship.
1148
602
 
1149
- ```ts
1150
- symmetric(a: any, b: any, axis: any): this
1151
- ```
603
+ #### `collinear(point: any, line: any): this` — Constrain a point to lie on the infinite extension of a line.
1152
604
 
1153
- #### `blockRotation()` — Prevent 180° rotation of a polygon by anchoring its first edge.
605
+ #### `symmetric(a: any, b: any, axis: any): this` — Constrain two points to be symmetric about an axis line.
1154
606
 
1155
- ```ts
1156
- blockRotation(points: any[], axis?: "x" | "y"): this
1157
- ```
607
+ #### `blockRotation(points: any[], axis?: "x" | "y"): this` — Prevent 180° rotation of a polygon by anchoring its first edge.
1158
608
 
1159
609
  **Dimensional Constraints**
1160
610
 
1161
- #### `distance()` — Constrain the Euclidean distance between two points.
1162
-
1163
- ```ts
1164
- distance(a: any, b: any, value: number): this
1165
- ```
1166
-
1167
- #### `length()` — Constrain the length of a line segment.
1168
-
1169
- ```ts
1170
- length(line: any, value: number): this
1171
- ```
1172
-
1173
- #### `angle()` — Constrain the signed angle from line `a` to line `b`.
1174
-
1175
- ```ts
1176
- angle(a: any, b: any, value: number): this
1177
- ```
1178
-
1179
- #### `radius()` — Constrain the radius of a circle.
1180
-
1181
- ```ts
1182
- radius(circle: any, value: number): this
1183
- ```
1184
-
1185
- #### `diameter()` — Constrain the diameter of a circle.
1186
-
1187
- ```ts
1188
- diameter(circle: any, value: number): this
1189
- ```
1190
-
1191
- #### `hDistance()` — Constrain the horizontal distance between two points.
1192
-
1193
- ```ts
1194
- hDistance(a: any, b: any, value: number): this
1195
- ```
1196
-
1197
- #### `vDistance()` — Constrain the vertical distance between two points.
611
+ #### `distance(a: any, b: any, value: number): this` — Constrain the Euclidean distance between two points.
1198
612
 
1199
- ```ts
1200
- vDistance(a: any, b: any, value: number): this
1201
- ```
613
+ #### `length(line: any, value: number): this` — Constrain the length of a line segment.
1202
614
 
1203
- #### `pointLineDistance()` — Constrain the signed perpendicular distance from a point to a line.
615
+ #### `angle(a: any, b: any, value: number): this` — Constrain the signed angle from line `a` to line `b`.
1204
616
 
1205
- ```ts
1206
- pointLineDistance(point: any, line: any, value: number): this
1207
- ```
617
+ #### `radius(circle: any, value: number): this` — Constrain the radius of a circle.
1208
618
 
1209
- #### `lineDistance()` — Constrain the perpendicular offset distance between two lines.
1210
-
1211
- ```ts
1212
- lineDistance(a: any, b: any, value: number): this
1213
- ```
619
+ #### `diameter(circle: any, value: number): this` — Constrain the diameter of a circle.
1214
620
 
1215
- #### `absoluteAngle()` — Constrain the absolute angle of a line measured from +X.
621
+ #### `hDistance(a: any, b: any, value: number): this` — Constrain the horizontal distance between two points.
1216
622
 
1217
- ```ts
1218
- absoluteAngle(line: any, value: number): this
1219
- ```
623
+ #### `vDistance(a: any, b: any, value: number): this` — Constrain the vertical distance between two points.
1220
624
 
1221
- #### `arcLength()` — Constrain the arc length of an arc.
625
+ #### `pointLineDistance(point: any, line: any, value: number): this` — Constrain the signed perpendicular distance from a point to a line.
1222
626
 
1223
- ```ts
1224
- arcLength(arc: any, value: number): this
1225
- ```
627
+ #### `lineDistance(a: any, b: any, value: number): this` — Constrain the perpendicular offset distance between two lines.
1226
628
 
1227
- #### `equalRadius()` — Constrain two circles to have equal radii.
629
+ #### `absoluteAngle(line: any, value: number): this` — Constrain the absolute angle of a line measured from +X.
1228
630
 
1229
- ```ts
1230
- equalRadius(a: any, b: any): this
1231
- ```
631
+ #### `arcLength(arc: any, value: number): this` — Constrain the arc length of an arc.
1232
632
 
1233
- #### `angleBetween()` — Constrain the unsigned angle between two lines.
633
+ #### `equalRadius(a: any, b: any): this` — Constrain two circles to have equal radii.
1234
634
 
1235
- ```ts
1236
- angleBetween(a: any, b: any, value: number): this
1237
- ```
635
+ #### `angleBetween(a: any, b: any, value: number): this` — Constrain the unsigned angle between two lines.
1238
636
 
1239
637
  **Coincidence & Equality**
1240
638
 
1241
- #### `equal()` — Constrain two lines to have equal length.
1242
-
1243
- ```ts
1244
- equal(a: any, b: any): this
1245
- ```
1246
-
1247
- #### `coincident()` — Constrain two points to coincide.
1248
-
1249
- ```ts
1250
- coincident(a: any, b: any): this
1251
- ```
1252
-
1253
- #### `concentric()` — Constrain two circles to share a center.
1254
-
1255
- ```ts
1256
- concentric(a: any, b: any): this
1257
- ```
1258
-
1259
- #### `fix()` — Pin a point at a specific world location.
1260
-
1261
- ```ts
1262
- fix(point: any, x?: number, y?: number): this
1263
- ```
639
+ #### `equal(a: any, b: any): this` — Constrain two lines to have equal length.
1264
640
 
1265
- #### `midpoint()` — Constrain a point to lie at the midpoint of a line.
641
+ #### `coincident(a: any, b: any): this` — Constrain two points to coincide.
1266
642
 
1267
- ```ts
1268
- midpoint(point: any, line: any): this
1269
- ```
643
+ #### `concentric(a: any, b: any): this` — Constrain two circles to share a center.
1270
644
 
1271
- #### `pointOnCircle()` — Constrain a point to lie on the perimeter of a circle.
1272
-
1273
- ```ts
1274
- pointOnCircle(point: any, circle: any): this
1275
- ```
645
+ #### `fix(point: any, x?: number, y?: number): this` — Pin a point at a specific world location.
1276
646
 
1277
- #### `pointOnLine()` — Constrain a point to lie on the bounded segment of a line.
647
+ #### `midpoint(point: any, line: any): this` — Constrain a point to lie at the midpoint of a line.
1278
648
 
1279
- ```ts
1280
- pointOnLine(point: any, line: any): this
1281
- ```
649
+ #### `pointOnCircle(point: any, circle: any): this` — Constrain a point to lie on the perimeter of a circle.
1282
650
 
1283
- #### `ccw()` — Constrain all given points to be in counter-clockwise order.
651
+ #### `pointOnLine(point: any, line: any): this` — Constrain a point to lie on the bounded segment of a line.
1284
652
 
1285
- ```ts
1286
- ccw(...points: any[]): this
1287
- ```
653
+ #### `ccw(...points: any[]): this` — Constrain all given points to be in counter-clockwise order.
1288
654
 
1289
655
  **Tangent Transitions**
1290
656
 
1291
- #### `lineTangentArc()` — Constrain a line to be tangent to an arc at its start or end point.
1292
-
1293
- ```ts
1294
- lineTangentArc(line: any, arc: any, atStart: boolean): this
1295
- ```
1296
-
1297
- #### `arcTangentArc()` — Constrain two arcs to be tangent at their shared junction point.
1298
-
1299
- ```ts
1300
- arcTangentArc(arcA: any, arcB: any, aAtStart?: boolean, bAtStart?: boolean): this
1301
- ```
657
+ #### `lineTangentArc(line: any, arc: any, atStart: boolean): this` — Constrain a line to be tangent to an arc at its start or end point.
1302
658
 
1303
- #### `bezierTangentArc()` — Constrain a Bezier to be tangent to an arc at one endpoint.
1304
-
1305
- ```ts
1306
- bezierTangentArc(bezier: any, arc: any, atBezierStart: boolean, atArcStart: boolean): this
1307
- ```
659
+ #### `arcTangentArc(arcA: any, arcB: any, aAtStart?: boolean, bAtStart?: boolean): this` — Constrain two arcs to be tangent at their shared junction point.
1308
660
 
1309
- #### `smoothBlend()` — Create a Bezier blend between two arcs.
661
+ #### `bezierTangentArc(bezier: any, arc: any, atBezierStart: boolean, atArcStart: boolean): this` — Constrain a Bezier to be tangent to an arc at one endpoint.
1310
662
 
1311
- ```ts
1312
- smoothBlend(arc1: any, arc2: any, options?: { weight?: number; arc1End?: "start" | "end"; arc2End?: "start" | "end"; }): BezierId
1313
- ```
663
+ #### `smoothBlend(arc1: any, arc2: any, options?: { weight?: number; arc1End?: "start" | "end"; arc2End?: "start" | "end"; }): BezierId` — Create a Bezier blend between two arcs.
1314
664
 
1315
665
  **Shape Constraints**
1316
666
 
1317
- #### `shapeWidth()` — Constrain a shape's width.
1318
-
1319
- ```ts
1320
- shapeWidth(shape: any, value: number): this
1321
- ```
1322
-
1323
- #### `shapeHeight()` — Constrain a shape's height.
1324
-
1325
- ```ts
1326
- shapeHeight(shape: any, value: number): this
1327
- ```
1328
-
1329
- #### `shapeCentroidX()` — Constrain a shape's centroid X position.
1330
-
1331
- ```ts
1332
- shapeCentroidX(shape: any, value: number): this
1333
- ```
1334
-
1335
- #### `shapeCentroidY()` — Constrain a shape's centroid Y position.
667
+ #### `shapeWidth(shape: any, value: number): this` — Constrain a shape's width.
1336
668
 
1337
- ```ts
1338
- shapeCentroidY(shape: any, value: number): this
1339
- ```
669
+ #### `shapeHeight(shape: any, value: number): this` — Constrain a shape's height.
1340
670
 
1341
- #### `shapeArea()` — Constrain a shape's area.
671
+ #### `shapeCentroidX(shape: any, value: number): this` — Constrain a shape's centroid X position.
1342
672
 
1343
- ```ts
1344
- shapeArea(shape: any, value: number): this
1345
- ```
673
+ #### `shapeCentroidY(shape: any, value: number): this` — Constrain a shape's centroid Y position.
1346
674
 
1347
- #### `shapeEqualCentroid()` — Constrain two shapes to have the same centroid.
675
+ #### `shapeArea(shape: any, value: number): this` — Constrain a shape's area.
1348
676
 
1349
- ```ts
1350
- shapeEqualCentroid(a: any, b: any): this
1351
- ```
677
+ #### `shapeEqualCentroid(a: any, b: any): this` — Constrain two shapes to have the same centroid.
1352
678
 
1353
679
  **Positioning**
1354
680
 
1355
- #### `offsetX()` — Constrain the horizontal (X-axis) offset between two lines. Uses the start-point of each line to measure horizontal distance. `value` is the signed distance: b.startPt.x − a.startPt.x = value.
1356
-
1357
- ```ts
1358
- offsetX(a: any, b: any, value: number): this
1359
- ```
1360
-
1361
- #### `offsetY()` — Constrain the vertical (Y-axis) offset between two lines. Uses the start-point of each line to measure vertical distance. `value` is the signed distance: b.startPt.y − a.startPt.y = value.
1362
-
1363
- ```ts
1364
- offsetY(a: any, b: any, value: number): this
1365
- ```
1366
-
1367
- #### `importPoint()` — Import a `Point2D` object into the sketch.
1368
-
1369
- ```ts
1370
- importPoint(pt: { x: number; y: number; }, fixed?: boolean): PointId
1371
- ```
1372
-
1373
- #### `importLine()` — Import a `Line2D` object into the sketch.
1374
-
1375
- ```ts
1376
- importLine(l: { start: { x: number; y: number; }; end: { x: number; y: number; }; }, fixed?: boolean): LineId
1377
- ```
1378
-
1379
- #### `importRectangle()` — Import a `Rectangle2D` as four points and four lines.
1380
-
1381
- ```ts
1382
- importRectangle(r: { vertices: [ { x: number; y: number; }, { x: number; y: number; }, { x: number; y: number; }, { x: number; y: number; } ]; }, fixed?: boolean): { ... }
1383
- ```
1384
-
1385
- #### `referencePoint()` — Add a fixed reference point at `(x, y)`.
1386
-
1387
- ```ts
1388
- referencePoint(x: number, y: number): PointId
1389
- ```
1390
-
1391
- #### `referenceLine()` — Add a fixed reference line from `(x1, y1)` to `(x2, y2)`.
681
+ #### `offsetX(a: any, b: any, value: number): this` — Constrain the horizontal (X-axis) offset between two lines. Uses the start-point of each line to measure horizontal distance. `value` is the signed distance: b.startPt.x − a.startPt.x = value.
1392
682
 
1393
- ```ts
1394
- referenceLine(x1: number, y1: number, x2: number, y2: number): LineId
1395
- ```
683
+ #### `offsetY(a: any, b: any, value: number): this` — Constrain the vertical (Y-axis) offset between two lines. Uses the start-point of each line to measure vertical distance. `value` is the signed distance: b.startPt.y − a.startPt.y = value.
1396
684
 
1397
- #### `referenceFrom()` Import a single named entity from a solved sketch as fixed reference geometry.
685
+ #### `referencePoint(x: number, y: number): PointId` Add a fixed reference point at `(x, y)`.
1398
686
 
1399
- ```ts
1400
- referenceFrom(source: ConstraintSketch, entityId: string): PointId | LineId | null
1401
- ```
687
+ #### `referenceLine(x1: number, y1: number, x2: number, y2: number): LineId` — Add a fixed reference line from `(x1, y1)` to `(x2, y2)`.
1402
688
 
1403
- #### `referenceAllFrom()` — Import all non-construction entities from a solved sketch as fixed references.
689
+ #### `referenceFrom(source: ConstraintSketch, entityId: string): PointId | LineId | null` — Import a single named entity from a solved sketch as fixed reference geometry.
1404
690
 
1405
- ```ts
1406
- referenceAllFrom(source: ConstraintSketch): { points: Map<string, PointId>; lines: Map<string, LineId>; }
1407
- ```
691
+ #### `referenceAllFrom(source: ConstraintSketch): { points: Map<string, PointId>; lines: Map<string, LineId>; }` — Import all non-construction entities from a solved sketch as fixed references.
1408
692
 
1409
693
  **Solving**
1410
694
 
1411
- #### `constrain()` — Add a raw constraint object to the builder.
1412
-
1413
- ```ts
1414
- constrain(constraint: Omit<SketchConstraint, "id">): this
1415
- ```
695
+ #### `constrain(constraint: Omit<SketchConstraint, "id">): this` — Add a raw constraint object to the builder.
1416
696
 
1417
- #### `solve()` — Run the constraint solver and return a solved sketch.
697
+ #### `solve(options?: SolveOptions): ConstraintSketch | Sketch` — Run the constraint solver and return a solved sketch.
1418
698
 
1419
699
  The returned `ConstraintSketch` extends `Sketch` and can be used directly in all 3D operations (`extrude`, `revolve`, etc.). It also exposes `constraintMeta` with the solver status:
1420
700
 
@@ -1433,10 +713,6 @@ result.withUpdatedConstraint('cst-5', 120); // update a dimension without rebuil
1433
713
  - **Over-constrained** — conflicting constraints are auto-rejected. Check `result.constraintMeta.constraints` and `result.inspect()`.
1434
714
  - **maxError > 1e-6** — solver did not converge; check for contradictory constraints.
1435
715
 
1436
- ```ts
1437
- solve(options?: SolveOptions): ConstraintSketch | Sketch
1438
- ```
1439
-
1440
716
  **`SolveOptions`**
1441
717
 
1442
718
  | Option | Type | Description |
@@ -1454,15 +730,11 @@ solve(options?: SolveOptions): ConstraintSketch | Sketch
1454
730
  | `debugConstructiveTranscript?` | `boolean` | Capture a readable constructive transcript in `constraintMeta.debug`. |
1455
731
  | `debugSvgSnapshots?` | `boolean` | Capture SVG snapshots for constructive steps in `constraintMeta.debug`. |
1456
732
 
1457
- #### `solveConstraintsOnly()` — Run the solver without building a full `ConstraintSketch`.
733
+ #### `solveConstraintsOnly(options?: SolveOptions): { maxError: number; rejectedCount: number; definition: ConstraintDefinition; }` — Run the solver without building a full `ConstraintSketch`.
1458
734
 
1459
735
  Lighter than `solve()` — skips profile and DOF analysis. Useful for lightweight constraint validation or progress monitoring mid-construction.
1460
736
 
1461
- ```ts
1462
- solveConstraintsOnly(options?: SolveOptions): { maxError: number; rejectedCount: number; definition: ConstraintDefinition; }
1463
- ```
1464
-
1465
- #### `route()` — Start a directional route from coordinates.
737
+ #### `route(x: number, y: number): RouteBuilder` — Start a directional route from coordinates.
1466
738
 
1467
739
  Returns a [`RouteBuilder`](/docs/viewport#routebuilder) - describe the path with up/down/left/right/arcLeft/arcRight. Each method returns the entity ID (`LineId` or `ArcId`) for use in `sk.*` constraints.
1468
740
 
@@ -1475,10 +747,6 @@ r.done();
1475
747
  sk.offsetX(stem, neck, 10.8);
1476
748
  ```
1477
749
 
1478
- ```ts
1479
- route(x: number, y: number): RouteBuilder
1480
- ```
1481
-
1482
750
  ### `ConstraintSketch`
1483
751
 
1484
752
  **Properties:**
@@ -1490,71 +758,31 @@ route(x: number, y: number): RouteBuilder
1490
758
 
1491
759
  **Methods:**
1492
760
 
1493
- #### `detectArrangement()` — Enumerate all bounded regions formed by the line arrangement of this sketch. Construction lines are excluded. Regions are returned largest-first by area.
1494
-
1495
- ```ts
1496
- detectArrangement(): Sketch[]
1497
- ```
761
+ #### `detectArrangement(): Sketch[]` — Enumerate all bounded regions formed by the line arrangement of this sketch. Construction lines are excluded. Regions are returned largest-first by area.
1498
762
 
1499
- #### `detectArrangementRegion()` — Select the single arrangement region that contains the given seed point. Throws if no region contains the seed.
763
+ #### `detectArrangementRegion(_seed: Vec2): Sketch` — Select the single arrangement region that contains the given seed point. Throws if no region contains the seed.
1500
764
 
1501
- ```ts
1502
- detectArrangementRegion(_seed: [ number, number ]): Sketch
1503
- ```
1504
-
1505
- #### `toPolyline()` — Return the solved constrained path as a sampled 2D polyline.
765
+ #### `toPolyline(samples?: number): Vec2[]` — Return the solved constrained path as a sampled 2D polyline.
1506
766
 
1507
767
  Use this when a construction rail was authored with `constrainedSketch()` and should feed another operation such as `Loft.pathOnXz(...)`. The sketch must contain exactly one profile path.
1508
768
 
1509
- ```ts
1510
- toPolyline(samples?: number): [ number, number ][]
1511
- ```
1512
-
1513
- #### `withUpdatedConstraint()` — Re-solve the sketch after changing the value of one existing constraint.
769
+ #### `withUpdatedConstraint(constraintId: string, value: number): ConstraintSketch` — Re-solve the sketch after changing the value of one existing constraint.
1514
770
 
1515
771
  Use this for interactive dimension edits without rebuilding the whole sketch graph. It attempts a warm-started solve first, then falls back to a full solve if needed.
1516
772
 
1517
- ```ts
1518
- withUpdatedConstraint(constraintId: string, value: number): ConstraintSketch
1519
- ```
1520
-
1521
- #### `inspect()` — Return a human-readable diagnostic string of the solved state.
1522
-
1523
- ```ts
1524
- inspect(): string
1525
- ```
773
+ #### `inspect(): string` — Return a human-readable diagnostic string of the solved state.
1526
774
 
1527
775
  ### `SketchGroupBuilder`
1528
776
 
1529
- #### `point()` — Add a point in local coordinates. Returns its globally-addressable PointId.
777
+ #### `point(lx: number, ly: number): PointId` — Add a point in local coordinates. Returns its globally-addressable PointId.
1530
778
 
1531
- ```ts
1532
- point(lx: number, ly: number): PointId
1533
- ```
1534
-
1535
- #### `line()` — Connect two group points with a line. Both must be PointIds from this group.
1536
-
1537
- ```ts
1538
- line(a: PointId, b: PointId, name?: string): LineId
1539
- ```
1540
-
1541
- #### `fixRotation()` — Freeze rotation (theta). Group can still translate - 2 DOF remain.
779
+ #### `line(a: PointId, b: PointId, name?: string): LineId` — Connect two group points with a line. Both must be PointIds from this group.
1542
780
 
1543
- ```ts
1544
- fixRotation(): this
1545
- ```
781
+ #### `fixRotation(): this` — Freeze rotation (theta). Group can still translate - 2 DOF remain.
1546
782
 
1547
- #### `fix()` — Freeze all 3 DOF - group is completely fixed.
783
+ #### `fix(): this` — Freeze all 3 DOF - group is completely fixed.
1548
784
 
1549
- ```ts
1550
- fix(): this
1551
- ```
1552
-
1553
- #### `done()` — Finalize and register the group with the builder.
1554
-
1555
- ```ts
1556
- done(): SketchGroupHandle
1557
- ```
785
+ #### `done(): SketchGroupHandle` — Finalize and register the group with the builder.
1558
786
 
1559
787
  ### `Point2D`
1560
788
 
@@ -1571,29 +799,13 @@ Used as construction geometry in sketches, constraints, and analytic measurement
1571
799
 
1572
800
  **Methods:**
1573
801
 
1574
- #### `distanceTo()` — Measure straight-line distance to another point.
1575
-
1576
- ```ts
1577
- distanceTo(other: Point2D): number
1578
- ```
1579
-
1580
- #### `midpointTo()` — Compute the midpoint between this point and another point.
1581
-
1582
- ```ts
1583
- midpointTo(other: Point2D): Point2D
1584
- ```
1585
-
1586
- #### `translate()` — Return a point shifted by the given delta.
802
+ #### `distanceTo(other: Point2D): number` — Measure straight-line distance to another point.
1587
803
 
1588
- ```ts
1589
- translate(dx: number, dy: number): Point2D
1590
- ```
804
+ #### `midpointTo(other: Point2D): Point2D` — Compute the midpoint between this point and another point.
1591
805
 
1592
- #### `toTuple()` — Convert this point to a plain `[x, y]` tuple.
806
+ #### `translate(dx: number, dy: number): Point2D` — Return a point shifted by the given delta.
1593
807
 
1594
- ```ts
1595
- toTuple(): [ number, number ]
1596
- ```
808
+ #### `toTuple(): Vec2` — Convert this point to a plain `[x, y]` tuple.
1597
809
 
1598
810
  ### `Line2D`
1599
811
 
@@ -1610,67 +822,27 @@ Provides both segment-only (`intersectSegment`) and infinite-line (`intersect`)
1610
822
 
1611
823
  **Methods:**
1612
824
 
1613
- #### `length()` — Length of the line segment.
1614
-
1615
- ```ts
1616
- get length(): number
1617
- ```
1618
-
1619
- #### `midpoint()` — Midpoint of the line segment.
1620
-
1621
- ```ts
1622
- get midpoint(): Point2D
1623
- ```
1624
-
1625
- #### `angle()` — Direction angle in degrees, measured CCW from +X.
825
+ #### `get length(): number` — Length of the line segment.
1626
826
 
1627
- ```ts
1628
- get angle(): number
1629
- ```
827
+ #### `get midpoint(): Point2D` — Midpoint of the line segment.
1630
828
 
1631
- #### `direction()` — Unit direction vector from start to end.
829
+ #### `get angle(): number` — Direction angle in degrees, measured CCW from +X.
1632
830
 
1633
- ```ts
1634
- get direction(): [ number, number ]
1635
- ```
831
+ #### `get direction(): Vec2` — Unit direction vector from start to end.
1636
832
 
1637
- #### `parallel()` — Create a parallel line offset by the given distance.
833
+ #### `parallel(distance: number): Line2D` — Create a parallel line offset by the given distance.
1638
834
 
1639
835
  Positive distance shifts to the left of the line direction.
1640
836
 
1641
- ```ts
1642
- parallel(distance: number): Line2D
1643
- ```
1644
-
1645
- #### `intersect()` — Intersect this line with another infinite line.
837
+ #### `intersect(other: Line2D): Point2D | null` — Intersect this line with another infinite line.
1646
838
 
1647
- ```ts
1648
- intersect(other: Line2D): Point2D | null
1649
- ```
1650
-
1651
- #### `intersectSegment()` — Intersect this line with another as bounded segments.
1652
-
1653
- ```ts
1654
- intersectSegment(other: Line2D): Point2D | null
1655
- ```
1656
-
1657
- #### `fromCoordinates()` — Create a line from raw coordinates.
839
+ #### `intersectSegment(other: Line2D): Point2D | null` — Intersect this line with another as bounded segments.
1658
840
 
1659
- ```ts
1660
- static fromCoordinates(x1: number, y1: number, x2: number, y2: number): Line2D
1661
- ```
841
+ #### `static fromCoordinates(x1: number, y1: number, x2: number, y2: number): Line2D` — Create a line from raw coordinates.
1662
842
 
1663
- #### `fromPointAndAngle()` — Create a line from a start point, angle, and length.
843
+ #### `static fromPointAndAngle(origin: Point2D, angleDeg: number, length: number): Line2D` — Create a line from a start point, angle, and length.
1664
844
 
1665
- ```ts
1666
- static fromPointAndAngle(origin: Point2D, angleDeg: number, length: number): Line2D
1667
- ```
1668
-
1669
- #### `fromPointAndDirection()` — Create a line from a start point, direction vector, and length.
1670
-
1671
- ```ts
1672
- static fromPointAndDirection(origin: Point2D, dir: [ number, number ], length: number): Line2D
1673
- ```
845
+ #### `static fromPointAndDirection(origin: Point2D, dir: Vec2, length: number): Line2D` — Create a line from a start point, direction vector, and length.
1674
846
 
1675
847
  ### `Circle2D`
1676
848
 
@@ -1687,59 +859,23 @@ Extruding a `Circle2D` produces a cylinder with named `top`, `bottom`, and `side
1687
859
 
1688
860
  **Methods:**
1689
861
 
1690
- #### `diameter()` — Diameter of the circle.
1691
-
1692
- ```ts
1693
- get diameter(): number
1694
- ```
1695
-
1696
- #### `circumference()` — Circumference of the circle.
1697
-
1698
- ```ts
1699
- get circumference(): number
1700
- ```
1701
-
1702
- #### `area()` — Area of the circle.
1703
-
1704
- ```ts
1705
- get area(): number
1706
- ```
1707
-
1708
- #### `pointAtAngle()` — Return a point on the circle at the given angle.
1709
-
1710
- ```ts
1711
- pointAtAngle(angleDeg: number): Point2D
1712
- ```
862
+ #### `get diameter(): number` — Diameter of the circle.
1713
863
 
1714
- #### `translate()` — Return a translated circle.
864
+ #### `get circumference(): number` — Circumference of the circle.
1715
865
 
1716
- ```ts
1717
- translate(dx: number, dy: number): Circle2D
1718
- ```
1719
-
1720
- #### `toSketch()` — Convert this circle to a sketch profile.
1721
-
1722
- ```ts
1723
- toSketch(segments?: number): Sketch
1724
- ```
866
+ #### `get area(): number` — Area of the circle.
1725
867
 
1726
- #### `extrude()` — Extrude the circle into a solid cylinder.
868
+ #### `pointAtAngle(angleDeg: number): Point2D` — Return a point on the circle at the given angle.
1727
869
 
1728
- ```ts
1729
- extrude(height: number, segments?: number): Shape
1730
- ```
870
+ #### `translate(dx: number, dy: number): Circle2D` — Return a translated circle.
1731
871
 
1732
- #### `fromCenterAndRadius()` — Create a circle from its center and radius.
872
+ #### `toSketch(segments?: number): Sketch` — Convert this circle to a sketch profile.
1733
873
 
1734
- ```ts
1735
- static fromCenterAndRadius(center: Point2D, radius: number): Circle2D
1736
- ```
874
+ #### `extrude(height: number, segments?: number): Shape` — Extrude the circle into a solid cylinder.
1737
875
 
1738
- #### `fromDiameter()` — Create a circle from its center and diameter.
876
+ #### `static fromCenterAndRadius(center: Point2D, radius: number): Circle2D` — Create a circle from its center and radius.
1739
877
 
1740
- ```ts
1741
- static fromDiameter(center: Point2D, diameter: number): Circle2D
1742
- ```
878
+ #### `static fromDiameter(center: Point2D, diameter: number): Circle2D` — Create a circle from its center and diameter.
1743
879
 
1744
880
  ### `Rectangle2D`
1745
881
 
@@ -1761,93 +897,37 @@ const [d1, d2] = r.diagonals(); // [bl-tr, br-tl]
1761
897
  r.toSketch(); // Sketch (for 2D operations)
1762
898
  r.extrude(20); // Shape with named faces
1763
899
 
1764
- Rectangle2D.fromCenterAndDimensions(point(50, 30), 100, 60);
1765
- Rectangle2D.from2Corners(point(0, 0), point(100, 60));
900
+ Rectangle2D.fromCenterAndDimensions(new Point2D(50, 30), 100, 60);
901
+ Rectangle2D.from2Corners(new Point2D(0, 0), new Point2D(100, 60));
1766
902
  Rectangle2D.from3Points(p1, p2, p3); // free-angle rectangle
1767
903
  ```
1768
904
 
1769
- #### `width()` — Width of the rectangle.
1770
-
1771
- ```ts
1772
- get width(): number
1773
- ```
1774
-
1775
- #### `height()` — Height of the rectangle.
1776
-
1777
- ```ts
1778
- get height(): number
1779
- ```
1780
-
1781
- #### `center()` — Geometric center of the rectangle.
1782
-
1783
- ```ts
1784
- get center(): Point2D
1785
- ```
1786
-
1787
- #### `side()` — Return a named side of the rectangle.
1788
-
1789
- ```ts
1790
- side(name: RectSide): Line2D
1791
- ```
1792
-
1793
- #### `sideAt()` — Return a side by index.
1794
-
1795
- ```ts
1796
- sideAt(index: number): Line2D
1797
- ```
1798
-
1799
- #### `vertex()` — Return a named vertex of the rectangle.
1800
-
1801
- ```ts
1802
- vertex(name: RectVertex): Point2D
1803
- ```
1804
-
1805
- #### `diagonals()` — Return the two diagonals of the rectangle.
905
+ #### `get width(): number` — Width of the rectangle.
1806
906
 
1807
- ```ts
1808
- diagonals(): [ Line2D, Line2D ]
1809
- ```
907
+ #### `get height(): number` — Height of the rectangle.
1810
908
 
1811
- #### `toSketch()` — Convert the rectangle to a sketch profile.
909
+ #### `get center(): Point2D` — Geometric center of the rectangle.
1812
910
 
1813
- ```ts
1814
- toSketch(): Sketch
1815
- ```
911
+ #### `side(name: RectSide): Line2D` — Return a named side of the rectangle.
1816
912
 
1817
- #### `translate()` — Return a translated rectangle.
913
+ #### `sideAt(index: number): Line2D` — Return a side by index.
1818
914
 
1819
- ```ts
1820
- translate(dx: number, dy: number): Rectangle2D
1821
- ```
915
+ #### `vertex(name: RectVertex): Point2D` — Return a named vertex of the rectangle.
1822
916
 
1823
- #### `fromDimensions()` Create an axis-aligned rectangle from origin corner plus width and height.
917
+ #### `diagonals(): [ Line2D, Line2D ]` Return the two diagonals of the rectangle.
1824
918
 
1825
- ```ts
1826
- static fromDimensions(x: number, y: number, width: number, height: number): Rectangle2D
1827
- ```
919
+ #### `toSketch(): Sketch` — Convert the rectangle to a sketch profile.
1828
920
 
1829
- #### `fromCenterAndDimensions()` — Create a rectangle centered on a point.
921
+ #### `translate(dx: number, dy: number): Rectangle2D` — Return a translated rectangle.
1830
922
 
1831
- ```ts
1832
- static fromCenterAndDimensions(center: Point2D, width: number, height: number): Rectangle2D
1833
- ```
923
+ #### `static fromDimensions(x: number, y: number, width: number, height: number): Rectangle2D` — Create an axis-aligned rectangle from origin corner plus width and height.
1834
924
 
1835
- #### `from2Corners()` — Create an axis-aligned rectangle from two opposite corners.
925
+ #### `static fromCenterAndDimensions(center: Point2D, width: number, height: number): Rectangle2D` — Create a rectangle centered on a point.
1836
926
 
1837
- ```ts
1838
- static from2Corners(p1: Point2D, p2: Point2D): Rectangle2D
1839
- ```
927
+ #### `static from2Corners(p1: Point2D, p2: Point2D): Rectangle2D` — Create an axis-aligned rectangle from two opposite corners.
1840
928
 
1841
- #### `from3Points()` — Create a free-angle rectangle from three points.
929
+ #### `static from3Points(p1: Point2D, p2: Point2D, p3: Point2D): Rectangle2D` — Create a free-angle rectangle from three points.
1842
930
 
1843
931
  `p1` and `p2` define one edge, and `p3` chooses the perpendicular side.
1844
932
 
1845
- ```ts
1846
- static from3Points(p1: Point2D, p2: Point2D, p3: Point2D): Rectangle2D
1847
- ```
1848
-
1849
- #### `extrude()` — Extrude the rectangle into a solid prism with named topology.
1850
-
1851
- ```ts
1852
- extrude(height: number, up?: boolean): Shape
1853
- ```
933
+ #### `extrude(height: number, up?: boolean): Shape` — Extrude the rectangle into a solid prism with named topology.