forgecad 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +2 -11
  2. package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-DAu1C1ST.js} +250 -151
  3. package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
  4. package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-Gc_BCdqC.js} +269 -143
  5. package/dist/assets/EditorApp-D9bJvtf7.js +11338 -0
  6. package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-DG1-oUSV.css} +459 -87
  7. package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-CEO8XbV8.js} +2 -4
  8. package/dist/assets/LandingPage-CdCuEOdC.js +451 -0
  9. package/dist/assets/PricingPage-BSrxu6d7.js +232 -0
  10. package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-FUCSIRq6.js} +129 -5
  11. package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-KoR0SNKq.js} +6770 -2914
  12. package/dist/assets/{index-2hfs_ub0.css → index-CyVd1D4D.css} +227 -53
  13. package/dist/assets/{Viewport-CoB46f5R.js → index-wTEK39at.js} +31385 -6439
  14. package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
  15. package/dist/assets/{manifold-CqNMHHKO.js → manifold-B1sGWdYk.js} +4 -3
  16. package/dist/assets/{manifold-Cce9wRFz.js → manifold-D7o0N50J.js} +1 -1
  17. package/dist/assets/{manifold-D6BeHIOo.js → manifold-G5sBaXzi.js} +1 -1
  18. package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-DYcRHhv9.js} +6798 -3341
  19. package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
  20. package/dist/docs-raw/generated/assembly.md +691 -112
  21. package/dist/docs-raw/generated/concepts.md +1225 -1400
  22. package/dist/docs-raw/generated/core.md +464 -1412
  23. package/dist/docs-raw/generated/curves.md +593 -117
  24. package/dist/docs-raw/generated/lib.md +38 -748
  25. package/dist/docs-raw/generated/output.md +139 -245
  26. package/dist/docs-raw/generated/sheet-metal.md +473 -21
  27. package/dist/docs-raw/generated/sketch.md +553 -349
  28. package/dist/docs-raw/generated/viewport.md +345 -303
  29. package/dist/docs-raw/generated/wood.md +104 -0
  30. package/dist/index.html +2 -2
  31. package/dist/sitemap.xml +6 -6
  32. package/dist-cli/chunk-PZ5AY32C.js +10 -0
  33. package/dist-cli/chunk-PZ5AY32C.js.map +1 -0
  34. package/dist-cli/forgecad.js +9435 -5407
  35. package/dist-cli/forgecad.js.map +1 -0
  36. package/dist-cli/solver-FV7TJZGI.js +365 -0
  37. package/dist-cli/solver-FV7TJZGI.js.map +1 -0
  38. package/dist-skill/CONTEXT.md +3186 -7145
  39. package/dist-skill/SKILL-dev.md +21 -63
  40. package/dist-skill/SKILL.md +12 -56
  41. package/dist-skill/docs/API/core/concepts.md +16 -98
  42. package/dist-skill/docs/CLI/export.md +91 -0
  43. package/dist-skill/docs/CLI/projects.md +107 -0
  44. package/dist-skill/docs/CLI/studio_publishing.md +52 -0
  45. package/dist-skill/docs/CLI/validation.md +66 -0
  46. package/dist-skill/docs/generated/assembly.md +691 -112
  47. package/dist-skill/docs/generated/core.md +464 -1412
  48. package/dist-skill/docs/generated/curves.md +593 -117
  49. package/dist-skill/docs/generated/lib.md +38 -748
  50. package/dist-skill/docs/generated/output.md +139 -245
  51. package/dist-skill/docs/generated/sheet-metal.md +473 -21
  52. package/dist-skill/docs/generated/sketch.md +553 -349
  53. package/dist-skill/docs/generated/viewport.md +345 -303
  54. package/dist-skill/docs/generated/wood.md +104 -0
  55. package/dist-skill/docs/guides/coordinate-system.md +11 -17
  56. package/dist-skill/docs/guides/geometry-conventions.md +13 -70
  57. package/dist-skill/docs/guides/modeling-recipes.md +22 -195
  58. package/dist-skill/docs/guides/positioning.md +88 -147
  59. package/dist-skill/docs-dev/API/core/concepts.md +51 -0
  60. package/dist-skill/docs-dev/API/core/sdf-advanced.md +92 -0
  61. package/dist-skill/docs-dev/API/core/sdf-primitives.md +58 -0
  62. package/dist-skill/docs-dev/API/core/sdf-workflow.md +42 -0
  63. package/dist-skill/docs-dev/CLI/export.md +91 -0
  64. package/dist-skill/docs-dev/CLI/projects.md +107 -0
  65. package/dist-skill/docs-dev/CLI/studio_publishing.md +52 -0
  66. package/dist-skill/docs-dev/CLI/validation.md +66 -0
  67. package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
  68. package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
  69. package/dist-skill/{docs → docs-dev}/coding.md +1 -3
  70. package/dist-skill/docs-dev/generated/assembly.md +771 -0
  71. package/dist-skill/docs-dev/generated/core.md +775 -0
  72. package/dist-skill/docs-dev/generated/curves.md +688 -0
  73. package/dist-skill/docs-dev/generated/lib.md +50 -0
  74. package/dist-skill/docs-dev/generated/output.md +234 -0
  75. package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
  76. package/dist-skill/docs-dev/generated/sketch.md +801 -0
  77. package/dist-skill/docs-dev/generated/viewport.md +486 -0
  78. package/dist-skill/docs-dev/generated/wood.md +104 -0
  79. package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
  80. package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
  81. package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
  82. package/dist-skill/docs-dev/guides/positioning.md +151 -0
  83. package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
  84. package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
  85. package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
  86. package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
  87. package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
  88. package/examples/api/attachTo-basics.forge.js +5 -5
  89. package/examples/api/boolean-operations.forge.js +3 -3
  90. package/examples/api/bounding-box-visualizer.forge.js +2 -2
  91. package/examples/api/clone-duplicate.forge.js +1 -1
  92. package/examples/api/colors-union-vs-array.forge.js +6 -6
  93. package/examples/api/connector-assembly.forge.js +4 -4
  94. package/examples/api/connector-basics.forge.js +2 -2
  95. package/examples/api/extrude-options.forge.js +4 -10
  96. package/examples/api/feature-created-faces.forge.js +6 -10
  97. package/examples/api/fillet-showcase.forge.js +1 -1
  98. package/examples/api/folded-service-panel-cover.forge.js +2 -2
  99. package/examples/api/group-test.forge.js +1 -1
  100. package/examples/api/group-vs-union.forge.js +1 -1
  101. package/examples/api/highlight-debug.forge.js +4 -0
  102. package/examples/api/js-module-pillars.js +1 -1
  103. package/examples/api/js-module-scene.js +2 -2
  104. package/examples/api/mesh-import-slats.forge.js +1 -1
  105. package/examples/api/pointAlong-orientation.forge.js +1 -1
  106. package/examples/api/profile-2020-b-slot6.forge.js +0 -1
  107. package/examples/api/route-perimeter-flange.forge.js +1 -1
  108. package/examples/api/sdf-rover-demo.forge.js +10 -10
  109. package/examples/api/sketch-on-face-demo.forge.js +2 -2
  110. package/examples/api/sketch-regions.forge.js +4 -4
  111. package/examples/api/transition-curves.forge.js +1 -1
  112. package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
  113. package/examples/api/variable-sweep-test.forge.js +2 -2
  114. package/examples/api/wood-joinery.forge.js +60 -0
  115. package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
  116. package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
  117. package/examples/experiments/drone-arm.forge.js +53 -0
  118. package/examples/furniture/adjustable-table.forge.js +2 -2
  119. package/examples/furniture/bathroom.forge.js +11 -11
  120. package/examples/furniture/chair.forge.js +1 -1
  121. package/examples/generative/crystal-growth.forge.js +2 -2
  122. package/examples/generative/frost-spires.forge.js +3 -3
  123. package/examples/generative/golden-spiral-tower.forge.js +3 -3
  124. package/examples/mechanical/3d-printer.forge.js +28 -28
  125. package/examples/mechanical/5-finger-robot-hand.forge.js +15 -15
  126. package/examples/mechanical/airplane-propeller.forge.js +2 -2
  127. package/examples/mechanical/fillet-enclosure.forge.js +1 -1
  128. package/examples/mechanical/headphone-hanger-v2.forge.js +2 -2
  129. package/examples/mechanical/robot_hand.forge.js +15 -15
  130. package/examples/mechanical/robot_hand_2.forge.js +9 -9
  131. package/examples/products/bottle.forge.js +1 -1
  132. package/examples/products/chess-set.forge.js +19 -19
  133. package/examples/products/classical-piano.forge.js +11 -11
  134. package/examples/products/clock.forge.js +12 -12
  135. package/examples/products/iphone.forge.js +8 -8
  136. package/examples/products/laptop.forge.js +15 -15
  137. package/examples/products/liquid-soap-dispenser.forge.js +18 -18
  138. package/examples/products/origami-fish.forge.js +8 -6
  139. package/examples/products/spiderman-cake.forge.js +4 -4
  140. package/examples/toolbox/bolted-joint.forge.js +2 -2
  141. package/package.json +7 -4
  142. package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
  143. package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
  144. package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
  145. package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
  146. package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
  147. package/dist/assets/index-1CYp3zUp.js +0 -1455
  148. package/dist/docs-raw/CLI.md +0 -865
  149. package/dist-skill/docs/API/API.md +0 -1666
  150. package/dist-skill/docs/API/README.md +0 -37
  151. package/dist-skill/docs/API/assembly/assembly.md +0 -617
  152. package/dist-skill/docs/API/core/edge-queries.md +0 -130
  153. package/dist-skill/docs/API/core/parameters.md +0 -122
  154. package/dist-skill/docs/API/core/reserved-terms.md +0 -137
  155. package/dist-skill/docs/API/core/sdf.md +0 -326
  156. package/dist-skill/docs/API/core/skill-cli.md +0 -194
  157. package/dist-skill/docs/API/core/skill-guide.md +0 -205
  158. package/dist-skill/docs/API/core/specs.md +0 -186
  159. package/dist-skill/docs/API/core/topology.md +0 -372
  160. package/dist-skill/docs/API/entities.md +0 -268
  161. package/dist-skill/docs/API/output/bom.md +0 -58
  162. package/dist-skill/docs/API/output/brep-export.md +0 -87
  163. package/dist-skill/docs/API/output/dimensions.md +0 -67
  164. package/dist-skill/docs/API/output/export.md +0 -110
  165. package/dist-skill/docs/API/output/gcode.md +0 -195
  166. package/dist-skill/docs/API/runtime/viewport.md +0 -420
  167. package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
  168. package/dist-skill/docs/API/sketch/anchor.md +0 -37
  169. package/dist-skill/docs/API/sketch/booleans.md +0 -91
  170. package/dist-skill/docs/API/sketch/core.md +0 -73
  171. package/dist-skill/docs/API/sketch/extrude.md +0 -62
  172. package/dist-skill/docs/API/sketch/on-face.md +0 -104
  173. package/dist-skill/docs/API/sketch/operations.md +0 -78
  174. package/dist-skill/docs/API/sketch/path.md +0 -75
  175. package/dist-skill/docs/API/sketch/primitives.md +0 -146
  176. package/dist-skill/docs/API/sketch/regions.md +0 -80
  177. package/dist-skill/docs/API/sketch/text.md +0 -108
  178. package/dist-skill/docs/API/sketch/transforms.md +0 -65
  179. package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
  180. package/dist-skill/docs/CLI.md +0 -865
  181. package/dist-skill/docs/INDEX.md +0 -94
  182. package/dist-skill/docs/RELEASING.md +0 -55
  183. package/dist-skill/docs/cli-monetization.md +0 -111
  184. package/dist-skill/docs/deployment.md +0 -281
  185. package/dist-skill/docs/generated/concepts.md +0 -2112
  186. package/dist-skill/docs/internals/shape-from-slices.md +0 -152
  187. package/dist-skill/docs/platform/admin.md +0 -45
  188. package/dist-skill/docs/platform/architecture.md +0 -79
  189. package/dist-skill/docs/platform/auth.md +0 -110
  190. package/dist-skill/docs/platform/email.md +0 -67
  191. package/dist-skill/docs/platform/projects.md +0 -111
  192. package/dist-skill/docs/platform/sharing.md +0 -90
  193. package/dist-skill/docs/runbook.md +0 -345
@@ -5,440 +5,482 @@ skill-order: 100
5
5
 
6
6
  # Viewport & Runtime
7
7
 
8
- > **Auto-generated** from `src/forge/forge-public-api.ts`. Do not edit by hand — run `npm run gen:docs` to regenerate.
9
-
10
8
  Cut planes, exploded views, joint animations, and scene configuration.
11
9
 
10
+ ## Contents
11
+
12
+ - [Viewport & Runtime](#viewport-runtime) — `jointsView`, `explodeView`, `cutPlane`, `cutPlane`, `scene`, `viewConfig`, `showLabels`, `highlight`, `highlight`, `highlight`, `highlight`, `highlight`, `highlight`, `highlight`, `highlight`
13
+ - [RouteBuilder](#routebuilder)
14
+ - [route](#route)
15
+
12
16
  ## Functions
13
17
 
14
18
  ### Viewport & Runtime
15
19
 
16
- Configure viewport behavior: cut planes, exploded views, joint controls.
20
+ #### `jointsView()` — Register viewport-only mechanism controls that animate returned objects without re-running the script.
17
21
 
18
- #### `jointsView()`
22
+ Defines joints (revolute or prismatic), optional gear/rack couplings, and named animations. The viewport resolves transforms through the joint chain at display time — the script geometry is computed only once at rest pose.
19
23
 
20
- ```ts
21
- jointsView(options?: JointsViewOptions): void
24
+ **Critical:** Solve the assembly at **rest pose** (all animated joints = 0). The viewport applies `jointsView` transforms on top of the returned scene. If geometry is already solved at non-zero angles, animation will double-rotate everything.
25
+
26
+ ```js
27
+ // BAD — double rotation
28
+ const solved = mech.solve({ shoulder: 45, elbow: 30 });
29
+ jointsView({ joints: [{ name: 'shoulder', ... }] });
30
+ return solved;
31
+
32
+ // GOOD — rest pose, jointsView controls all posing
33
+ const solved = mech.solve({ shoulder: 0, elbow: 0 });
34
+ jointsView({
35
+ joints: [
36
+ { name: 'shoulder', child: 'Upper Arm', default: 45, ... },
37
+ { name: 'elbow', child: 'Forearm', parent: 'Upper Arm', default: 30, ... },
38
+ ],
39
+ });
40
+ return solved;
22
41
  ```
23
42
 
24
- Configure runtime joint controls that animate object transforms in the viewport without re-running the script.
43
+ **Pivot coordinates** are world-space positions of each joint origin at rest pose. For `addRevolute('shoulder', 'Base', 'Link', { frame: Transform.identity().translate(0, 0, 20) })` where "Base" is at world origin, the pivot is `[0, 0, 20]`.
25
44
 
26
- <details><summary><code>JointsViewOptions</code></summary>
45
+ **Fixed attachments** that must follow a parent during animation need a zero-angle revolute joint in the chain:
27
46
 
28
- ```ts
29
- interface JointsViewOptions {
30
- enabled?: boolean;
31
- joints?: JointViewInput[];
32
- couplings?: JointViewCouplingInput[];
33
- animations?: JointViewAnimationInput[];
34
- defaultAnimation?: string;
35
- }
47
+ ```js
48
+ { name: 'EE_Follow', child: 'End Effector', parent: 'Last Link',
49
+ type: 'revolute', axis: [0, 0, 1], pivot: [linkLength, 0, 0],
50
+ min: 0, max: 0, default: 0 }
36
51
  ```
37
52
 
38
- </details>
53
+ Animation values are interpolated linearly between keyframes. ForgeCAD does **not** auto-wrap revolute values across `-180/180`. Keep keyframe values continuous — a `-180 -> 171` jump spins the part the long way around. Use `-180 -> -189` instead. Author high-speed multi-turn joints as accumulating angles (`0, 360, 720, ...`) with `continuous: true`.
39
54
 
40
- <details><summary><code>JointViewInput</code></summary>
55
+ **Tick-based keyframes:** Omit `at` from all keyframes to auto-distribute by tick weight:
41
56
 
42
- ```ts
43
- interface JointViewInput {
44
- name: string;
45
- child: string;
46
- parent?: string;
47
- type?: JointViewType;
48
- axis?: JointViewAxis;
49
- min?: number;
50
- max?: number;
51
- default?: number;
52
- unit?: string;
53
- hidden?: boolean;
54
- }
57
+ ```js
58
+ keyframes: [
59
+ { ticks: 3, values: { Shoulder: 20 } }, // slow segment (3x weight)
60
+ { ticks: 1, values: { Shoulder: -10 } }, // fast segment (1x weight)
61
+ { values: { Shoulder: 20 } }, // last keyframe; ticks ignored
62
+ ]
63
+ // positions: 0, 0.75, 1.0
55
64
  ```
56
65
 
57
- </details>
58
-
59
- <details><summary><code>JointViewCouplingInput</code></summary>
66
+ Mixing explicit `at` and omitted `at` in the same animation is not allowed.
67
+
68
+ ```js
69
+ jointsView({
70
+ joints: [{
71
+ name: 'Shoulder', child: 'Upper Arm', parent: 'Base',
72
+ type: 'revolute', axis: [0, -1, 0], pivot: [0, 0, 46],
73
+ min: -30, max: 110, default: 15,
74
+ }],
75
+ animations: [{
76
+ name: 'Walk Cycle', duration: 1.6, loop: true,
77
+ keyframes: [
78
+ { values: { Shoulder: 20 } },
79
+ { values: { Shoulder: -10 } },
80
+ { values: { Shoulder: 20 } },
81
+ ],
82
+ }],
83
+ });
84
+ ```
60
85
 
61
86
  ```ts
62
- interface JointViewCouplingInput {
63
- joint: string;
64
- terms: JointViewCouplingTermInput[];
65
- offset?: number;
66
- }
87
+ jointsView(options?: JointsViewOptions): void
67
88
  ```
68
89
 
69
- </details>
90
+ **`JointsViewOptions`**: `enabled?: boolean`, `joints?: JointViewInput[]`, `couplings?: JointViewCouplingInput[]`, `animations?: JointViewAnimationInput[]`, `defaultAnimation?: string`
70
91
 
71
- <details><summary><code>JointViewCouplingTermInput</code></summary>
92
+ **`JointViewInput`**: `name: string`, `child: string`, `parent?: string`, `type?: JointViewType`, `axis?: JointViewAxis`, `min?: number`, `max?: number`, `default?: number`, `unit?: string`, `hidden?: boolean`
93
+
94
+ `JointViewCouplingInput`: `{ joint: string, terms: JointViewCouplingTermInput[], offset?: number }`
95
+
96
+ `JointViewCouplingTermInput`: `{ joint: string, ratio?: number }`
97
+
98
+ `JointViewAnimationInput`: `{ name: string, duration?: number, loop?: boolean, continuous?: boolean, keyframes: JointViewAnimationKeyframeInput[] }`
99
+
100
+ **`JointViewAnimationKeyframeInput`**
101
+ - `at?: number` — Timeline position [0, 1]. If omitted from ALL keyframes, positions are auto-computed from tick weights.
102
+ - `ticks?: number` — Relative weight of the segment from this keyframe to the next (default 1). Only used in tick-based mode (when `at` is omitted). Last keyframe's ticks value is ignored.
103
+ - Also: `values: Record<string, number>`
104
+
105
+ #### `explodeView()` — Configure how the viewport explode slider offsets returned objects.
106
+
107
+ Offsets are resolved from the returned object tree, not a flat list. In `radial` mode each node follows its parent branch direction, then fans locally from the immediate parent center — nested assemblies peel apart level by level. In fixed-axis or fixed-vector modes, the branch follows that axis/vector but nested descendants fan out perpendicular by default.
108
+
109
+ Multiple calls merge — later values override earlier ones on a per-key basis. `byName` and `byPath` maps are merged entry-by-entry.
110
+
111
+ For programmatic explode applied before returning (without the slider), use `lib.explode()` instead.
112
+
113
+ ```js
114
+ explodeView({
115
+ amountScale: 1.2,
116
+ stages: [0.35, 0.8],
117
+ mode: 'radial',
118
+ byPath: { 'Drive/Shaft': { direction: [1, 0, 0], stage: 1.6 } },
119
+ });
120
+ ```
72
121
 
73
122
  ```ts
74
- interface JointViewCouplingTermInput {
75
- joint: string;
76
- ratio?: number;
77
- }
123
+ explodeView(options?: ExplodeViewOptions): void
78
124
  ```
79
125
 
80
- </details>
126
+ **`ExplodeViewOptions`**
127
+
128
+ | Option | Type | Description |
129
+ |--------|------|-------------|
130
+ | `enabled?` | `boolean` | Set false to disable viewport explode offsets for this script output. |
131
+ | `amountScale?` | `number` | Scales the UI explode amount. Default: 1 |
132
+ | `stages?` | `number[]` | Per-depth stage multipliers (depth 1 = first level). If depth exceeds this array, the last value is reused. Default when omitted: reciprocal depth (1, 1/2, 1/3, ...) |
133
+ | `mode?` | `ExplodeViewDirection` | Global direction mode fallback. Default: 'radial' |
134
+ | `axisLock?` | `ExplodeAxis` | Global axis lock fallback. |
135
+ | `byName?` | `Record<string, ExplodeViewDirective>` | Per-object overrides by final object name. |
136
+ | `byPath?` | `Record<string, ExplodeViewDirective>` | Per-tree-path overrides using slash-separated object tree segments. |
81
137
 
82
- <details><summary><code>JointViewAnimationInput</code></summary>
138
+ **`ExplodeDirective`**
139
+ - `stage?: number` — Multiplier applied to `amount` for this node
140
+ - `direction?: ExplodeDirection` — Direction mode for this node
141
+ - `axisLock?: ExplodeAxis` — Optional axis lock after direction is resolved
142
+
143
+ #### `cutPlane()` — Define a named section plane for inspecting internal geometry.
144
+
145
+ Registers a cut plane that appears as a toggle in the viewport View Panel. When enabled, geometry on the positive side of the plane (the side the normal points toward) is clipped away, revealing the internal cross-section. The newly exposed section faces render with a hatched overlay; pre-existing coplanar boundary faces are left unhatched.
146
+
147
+ Planes are registered once per script run. The viewport toggle state (on/off) persists across parameter changes without re-running the script. The `exclude` option only works correctly when the excluded object names are stable across parameter changes.
148
+
149
+ Accepts two overloads: `cutPlane(name, normal, offset?, options?)` or `cutPlane(name, normal, options?)` where options may include `offset`.
150
+
151
+ ```js
152
+ const cutZ = param('Cut Height', 10, { min: -50, max: 50, unit: 'mm' });
153
+ cutPlane('Inspection', [0, 0, 1], cutZ, { exclude: ['Probe', 'Fasteners'] });
154
+ ```
83
155
 
84
156
  ```ts
85
- interface JointViewAnimationInput {
86
- name: string;
87
- duration?: number;
88
- loop?: boolean;
89
- continuous?: boolean;
90
- keyframes: JointViewAnimationKeyframeInput[];
91
- }
157
+ cutPlane(name: string, normal: [ number, number, number ], offset?: number, options?: CutPlaneOptions): void
92
158
  ```
93
159
 
94
- </details>
160
+ **`CutPlaneOptions`**
161
+ - `offset?: number` — Optional offset along the plane normal (primarily for object-form overload).
162
+ - `exclude?: CutPlaneExcludeInput` — Object names to keep uncut for this plane.
95
163
 
96
- <details><summary><code>JointViewAnimationKeyframeInput</code></summary>
164
+ #### `cutPlane()`
97
165
 
98
166
  ```ts
99
- interface JointViewAnimationKeyframeInput {
100
- /** Timeline position [0, 1]. If omitted from ALL keyframes, positions are auto-computed from tick weights. */
101
- at?: number;
102
- /** Relative weight of the segment from this keyframe to the next (default 1). Only used in tick-based mode (when `at` is omitted). Last keyframe's ticks value is ignored. */
103
- ticks?: number;
104
- values: Record<string, number>;
105
- }
167
+ cutPlane(name: string, normal: [ number, number, number ], options?: CutPlaneOptions): void
106
168
  ```
107
169
 
108
- </details>
109
-
110
- #### `explodeView()`
170
+ #### `scene()` — Configure the scene environment for the current script execution.
171
+
172
+ Controls camera position, lighting rig, background color or gradient, atmospheric fog, environment maps, post-processing effects, and capture parameters for the `forgecad capture` command. Multiple calls merge — later values override earlier ones on a per-key basis, so you can split configuration across multiple `scene()` calls.
173
+
174
+ When `lights` is specified, **all** default lights are removed. You must include your own ambient light or the scene will be fully dark.
175
+
176
+ Setting `camera.position` overrides auto-framing — the viewport will no longer auto-fit the geometry on script reload.
177
+
178
+ Post-processing effects (`bloom`, `vignette`, `grain`) work in the browser viewport only. The CLI applies camera, lights, background, fog, and `toneMappingExposure` but skips shader effects.
179
+
180
+ All numeric values accept [`param()`](/docs/core#param) expressions.
181
+
182
+ ```js
183
+ scene({
184
+ background: { top: '#000814', bottom: '#001d3d' },
185
+ camera: { position: [160, -120, 100], target: [0, 0, 50], fov: 52 },
186
+ lights: [
187
+ { type: 'ambient', color: '#001233', intensity: 0.08 },
188
+ { type: 'point', position: [120, -80, 130], color: '#00f5d4', intensity: 4, distance: 400, decay: 1 },
189
+ { type: 'point', position: [-100, 60, 20], color: '#f72585', intensity: 3, distance: 350 },
190
+ { type: 'directional', position: [50, -30, 200], color: '#ffd60a', intensity: 1.2 },
191
+ { type: 'hemisphere', skyColor: '#003566', groundColor: '#000814', intensity: 0.2 },
192
+ ],
193
+ fog: { color: '#000814', near: 100, far: 450 },
194
+ postProcessing: {
195
+ bloom: { intensity: param('bloom', 1.5, 0, 4), threshold: 0.5, radius: 0.7 },
196
+ vignette: { darkness: 0.8, offset: 0.25 },
197
+ grain: { intensity: 0.08 },
198
+ toneMappingExposure: param('exposure', 1.5, 0.5, 4),
199
+ },
200
+ });
201
+ ```
111
202
 
112
203
  ```ts
113
- explodeView(options?: ExplodeViewOptions): void
204
+ scene(options: SceneOptions): void
114
205
  ```
115
206
 
116
- Configure viewport exploded-view behavior for the current script execution. Multiple calls merge; later values override earlier ones.
207
+ **`SceneOptions`**
117
208
 
118
- <details><summary><code>ExplodeViewOptions</code></summary>
209
+ | Option | Type | Description |
210
+ |--------|------|-------------|
211
+ | `capture?` | `SceneCaptureConfig` | Default capture parameters for `forgecad capture` — CLI flags override these. |
212
+ | `background?`, `camera?`, `lights?`, `environment?`, `fog?`, `postProcessing?`, `ground?` | | — |
119
213
 
120
- ```ts
121
- interface ExplodeViewOptions {
122
- /** Set false to disable viewport explode offsets for this script output. */
123
- enabled?: boolean;
124
- /** Scales the UI explode amount. Default: 1 */
125
- amountScale?: number;
126
- /** Per-depth stage multipliers (depth 1 = first level). If depth exceeds this array, the last value is reused. Default when omitted: reciprocal depth (1, 1/2, 1/3, ...) */
127
- stages?: number[];
128
- /** Global direction mode fallback. Default: 'radial' */
129
- mode?: ExplodeViewDirection;
130
- /** Global axis lock fallback. */
131
- axisLock?: ExplodeAxis;
132
- /** Per-object overrides by final object name. */
133
- byName?: Record<string, ExplodeViewDirective>;
134
- /** Per-tree-path overrides using slash-separated object tree segments. */
135
- byPath?: Record<string, ExplodeViewDirective>;
136
- }
137
- ```
138
-
139
- </details>
140
-
141
- <details><summary><code>ExplodeDirective</code></summary>
214
+ `SceneBackgroundGradient`: `{ top: string, bottom: string }`
215
+
216
+ `SceneCameraConfig`: `{ fov?: number, type?: "perspective" | "orthographic" }`
217
+
218
+ **`SceneLightConfig`**
219
+
220
+ | Option | Type | Description |
221
+ |--------|------|-------------|
222
+ | `groundColor?` | `string` | Ground color for hemisphere lights |
223
+ | `skyColor?` | `string` | Sky color alias for hemisphere lights (same as color) |
224
+ | `angle?` | `number` | Spot light cone angle in radians |
225
+ | `penumbra?` | `number` | Spot light penumbra (0–1) |
226
+ | `decay?` | `number` | Point/spot light decay |
227
+ | `distance?` | `number` | Point/spot light distance (0 = infinite) |
228
+ | `castShadow?` | `boolean` | Whether this light casts shadows |
229
+ | `type`, `color?`, `intensity?` | | — |
230
+
231
+ **`SceneEnvironmentConfig`**
232
+ - `preset?: "studio" | "sunset" | "dawn" | "warehouse" | "forest" | "apartment" | "lobby" | "city" | "park" | "night" | "none"` — Built-in preset name or 'none' to disable
233
+ - `intensity?: number` — Environment map intensity
234
+ - `background?: boolean` — Use environment map as scene background
235
+
236
+ **`SceneFogConfig`**
237
+ - `near?: number` — Linear fog near distance
238
+ - `far?: number` — Linear fog far distance
239
+ - `density?: number` — Exponential fog density (if set, uses FogExp2 instead of linear Fog)
240
+ - Also: `color?: string`
241
+
242
+ `ScenePostProcessingConfig`: `{ bloom?: SceneBloomConfig, vignette?: SceneVignetteConfig, grain?: SceneGrainConfig, toneMappingExposure?: number }`
243
+
244
+ `SceneBloomConfig`: `{ intensity?: number, threshold?: number, radius?: number }`
245
+
246
+ `SceneVignetteConfig`: `{ darkness?: number, offset?: number }`
247
+
248
+ `SceneGrainConfig`: `{ intensity?: number }`
249
+
250
+ **`SceneGroundConfig`**
251
+
252
+ | Option | Type | Description |
253
+ |--------|------|-------------|
254
+ | `visible?` | `boolean` | Show a ground plane |
255
+ | `color?` | `string` | Ground color |
256
+ | `offset?` | `number` | Offset below the model's bounding box minimum Z. Default 0 (flush with model bottom). |
257
+ | `receiveShadow?` | `boolean` | Receive shadows on the ground |
258
+
259
+ **`SceneCaptureConfig`**
260
+
261
+ | Option | Type | Description |
262
+ |--------|------|-------------|
263
+ | `framesPerTurn?` | `number` | Frames for one full orbit rotation (default: 72) |
264
+ | `holdFrames?` | `number` | Frozen frames before motion starts (default: 6) |
265
+ | `pitchDeg?` | `number` | Orbit pitch angle in degrees (default: auto from camera) |
266
+ | `fps?` | `number` | Output frame rate (default: 24) |
267
+ | `size?` | `number` | Output frame size in pixels (default: 960) |
268
+ | `background?` | `string` | Canvas background color for capture (default: '#252526') |
269
+
270
+ #### `viewConfig()` — Configure viewport helper visuals for the current script execution.
271
+
272
+ Controls renderer-only overlays that appear in the viewport but are not part of the geometry. Currently supports the joint overlay that renders axis arrows and arc indicators when `jointsView` is active. Multiple calls merge — later values override earlier ones per key.
273
+
274
+ This does **not** trigger a geometry recompute; it only affects the visual helpers drawn on top of the 3D scene.
275
+
276
+ ```js
277
+ viewConfig({
278
+ jointOverlay: {
279
+ axisColor: '#13dfff',
280
+ arcColor: '#ff7a1a',
281
+ axisLineRadiusScale: 0.03,
282
+ arcLineRadiusScale: 0.022,
283
+ },
284
+ });
285
+ ```
142
286
 
143
287
  ```ts
144
- interface ExplodeDirective {
145
- /** Multiplier applied to `amount` for this node */
146
- stage?: number;
147
- /** Direction mode for this node */
148
- direction?: ExplodeDirection;
149
- /** Optional axis lock after direction is resolved */
150
- axisLock?: ExplodeAxis;
151
- }
288
+ viewConfig(options?: ViewConfigOptions): void
152
289
  ```
153
290
 
154
- </details>
291
+ `ViewConfigOptions`: `{ jointOverlay?: JointOverlayViewConfigOptions }`
155
292
 
156
- <details><summary><code>ExplodeViewDirective</code> extends ExplodeDirective</summary>
293
+ **`JointOverlayViewConfigOptions`**: `enabled?: boolean`, `axisColor?: string`, `axisCoreColor?: string`, `arcColor?: string`, `zeroColor?: string`, `arcVisualLimitDeg?: number`, `axisLengthScale?: number`, `axisLengthMin?: number`, `axisLineRadiusScale?: number`, `axisLineRadiusMin?: number`, `axisLineRadiusMax?: number`, `spokeLineRadiusScale?: number`, `spokeLineRadiusMin?: number`, `spokeLineRadiusMax?: number`, `arcLineRadiusScale?: number`, `arcLineRadiusMin?: number`, `arcLineRadiusMax?: number`, `axisDotRadiusScale?: number`, `axisDotRadiusMin?: number`, `axisArrowRadiusScale?: number`, `axisArrowRadiusMin?: number`, `axisArrowLengthScale?: number`, `axisArrowLengthMin?: number`, `axisArrowOffsetFactor?: number`, `arcRadiusScale?: number`, `arcRadiusMin?: number`, `arcDotRadiusScale?: number`, `arcDotRadiusMin?: number`, `arcArrowRadiusScale?: number`, `arcArrowRadiusMin?: number`, `arcArrowLengthScale?: number`, `arcArrowLengthMin?: number`, `arcArrowOffsetFactor?: number`, `arcStepDeg?: number`, `arcMinSteps?: number`, `arcTubeSegmentsMin?: number`, `arcTubeSegmentsFactor?: number`, `arcTubeRadialSegments?: number`
294
+
295
+ #### `showLabels()` — Highlight all user-labeled faces on a shape for visual debugging.
296
+
297
+ Shows each user-authored label name in the viewport for visual debugging. Returns the shape unchanged for chaining: `return showLabels(myShape)`.
157
298
 
158
299
  ```ts
159
- interface ExplodeViewDirective extends ExplodeDirective {
160
- }
300
+ showLabels(shape: Shape): Shape
161
301
  ```
162
302
 
163
- </details>
303
+ #### `highlight()` — Highlight any geometry for visual debugging in the viewport.
164
304
 
165
- #### `cutPlane()`
305
+ Supported inputs:
306
+
307
+ - `string` — sketch entity ID (e.g. `'L0'`, `'P0'`, `'C0'`)
308
+ - `[x, y, z]` — 3D point
309
+ - `[[x1,y1,z1], [x2,y2,z2]]` — edge (line segment)
310
+ - `{ normal: [x,y,z], offset: number }` — plane by normal + distance from origin
311
+ - `{ normal: [x,y,z], point: [x,y,z] }` — plane by normal + point on plane
312
+ - [`Shape`](/docs/core#shape) — highlight entire 3D shape
313
+ - `FaceRef` (from `shape.face('top')`) — highlight as plane at face center
314
+ - `EdgeRef` (from `shape.edge('left')`) — highlight as edge segment
166
315
 
167
316
  ```ts
168
- cutPlane(name: string, normal: [ number, number, number ], offset?: number, options?: CutPlaneOptions): void
317
+ highlight(entityId: string, opts?: HighlightOptions): void
169
318
  ```
170
319
 
171
- Define a named section/cut plane. Appears as a toggle in the View Panel. When enabled, geometry on the positive side of the plane is clipped away.
320
+ **`HighlightOptions`**
321
+ - `size?: number` — Size hint for points (radius in mm) or planes (disc radius in mm).
322
+ - Also: `color?: string, label?: string, pulse?: boolean`
172
323
 
173
- <details><summary><code>CutPlaneOptions</code></summary>
324
+ #### `highlight()`
174
325
 
175
326
  ```ts
176
- interface CutPlaneOptions {
177
- /** Optional offset along the plane normal (primarily for object-form overload). */
178
- offset?: number;
179
- /** Object names to keep uncut for this plane. */
180
- exclude?: CutPlaneExcludeInput;
181
- }
327
+ highlight(point: [ number, number, number ], opts?: HighlightOptions): void
182
328
  ```
183
329
 
184
- </details>
330
+ #### `highlight()`
185
331
 
186
- #### `cutPlane()`
332
+ ```ts
333
+ highlight(edge: [ [ number, number, number ], [ number, number, number ] ], opts?: HighlightOptions): void
334
+ ```
335
+
336
+ #### `highlight()`
187
337
 
188
338
  ```ts
189
- cutPlane(name: string, normal: [ number, number, number ], options?: CutPlaneOptions): void
339
+ highlight(plane: { normal: [ number, number, number ]; offset: number; }, opts?: HighlightOptions): void
190
340
  ```
191
341
 
192
- #### `scene()`
342
+ #### `highlight()`
193
343
 
194
344
  ```ts
195
- scene(options: SceneOptions): void
345
+ highlight(plane: { normal: [ number, number, number ]; point: [ number, number, number ]; }, opts?: HighlightOptions): void
196
346
  ```
197
347
 
198
- Configure the scene environment for the current script execution. Controls camera, lighting, background, fog, and post-processing. Multiple calls merge; later values override earlier ones. ```js scene({ background: '#0a0a0a', camera: { position: [200, 100, 150], target: [0, 0, 30], fov: 60 }, lights: [ { type: 'ambient', color: '#1a1a2e', intensity: 0.2 }, { type: 'point', position: [0, 0, 100], color: '#ff6b35', intensity: 2 }, ], fog: { color: '#0a0a0a', near: 100, far: 500 }, postProcessing: { bloom: { intensity: 1.5, threshold: 0.8, radius: 0.4 }, }, }); ```
348
+ #### `highlight()`
349
+
350
+ ```ts
351
+ highlight(shape: Shape, opts?: HighlightOptions): void
352
+ ```
199
353
 
200
- <details><summary><code>SceneOptions</code></summary>
354
+ #### `highlight()`
201
355
 
202
356
  ```ts
203
- interface SceneOptions {
204
- background?: string | SceneBackgroundGradient;
205
- camera?: SceneCameraConfig;
206
- lights?: SceneLightConfig[];
207
- environment?: SceneEnvironmentConfig;
208
- fog?: SceneFogConfig;
209
- postProcessing?: ScenePostProcessingConfig;
210
- ground?: SceneGroundConfig;
211
- /** Default capture parameters for `forgecad capture` — CLI flags override these. */
212
- capture?: SceneCaptureConfig;
213
- }
357
+ highlight(face: FaceRef, opts?: HighlightOptions): void
214
358
  ```
215
359
 
216
- </details>
360
+ **`FaceRef`**
361
+ - `query?: FaceQueryRef` — Compiler-owned face query when available.
362
+ - `planar?: boolean` — True when the face can host a 2D sketch placement frame
363
+ - `descendant?: FaceDescendantMetadata` — Shared descendant-resolution metadata when this face is a semantic region/set.
364
+ - Also: `name: FaceName`
365
+
366
+ **`FaceDescendantMetadata`**: `kind: "single" | "face-set"`, `semantic: FaceDescendantSemantic`, `memberCount: number`, `memberNames: string[]`, `coplanar: boolean`
217
367
 
218
- <details><summary><code>SceneBackgroundGradient</code></summary>
368
+ #### `highlight()`
219
369
 
220
370
  ```ts
221
- interface SceneBackgroundGradient {
222
- top: string;
223
- bottom: string;
224
- }
371
+ highlight(edge: EdgeRef, opts?: HighlightOptions): void
225
372
  ```
226
373
 
227
- </details>
374
+ **`EdgeRef`**
375
+ - `query?: EdgeQueryRef` — Compiler-owned edge query when available.
376
+ - Also: `name: EdgeName`
228
377
 
229
- <details><summary><code>SceneCameraConfig</code></summary>
378
+ ---
379
+
380
+ ## Classes
381
+
382
+ ### `RouteBuilder`
383
+
384
+ #### `up()` — Vertical line going +Y. Length is optional (solver determines it from constraints).
230
385
 
231
386
  ```ts
232
- interface SceneCameraConfig {
233
- fov?: number;
234
- type?: "perspective" | "orthographic";
235
- }
387
+ up(length?: number): LineId
236
388
  ```
237
389
 
238
- </details>
239
-
240
- <details><summary><code>SceneLightConfig</code></summary>
390
+ #### `down()` — Vertical line going -Y. Length is optional.
241
391
 
242
392
  ```ts
243
- interface SceneLightConfig {
244
- type: SceneLightType;
245
- color?: string;
246
- intensity?: number;
247
- /** Ground color for hemisphere lights */
248
- groundColor?: string;
249
- /** Sky color alias for hemisphere lights (same as color) */
250
- skyColor?: string;
251
- /** Spot light cone angle in radians */
252
- angle?: number;
253
- /** Spot light penumbra (0–1) */
254
- penumbra?: number;
255
- /** Point/spot light decay */
256
- decay?: number;
257
- /** Point/spot light distance (0 = infinite) */
258
- distance?: number;
259
- /** Whether this light casts shadows */
260
- castShadow?: boolean;
261
- }
262
- ```
263
-
264
- </details>
265
-
266
- <details><summary><code>SceneEnvironmentConfig</code></summary>
393
+ down(length?: number): LineId
394
+ ```
395
+
396
+ #### `right()` — Horizontal line going +X. Length is optional.
267
397
 
268
398
  ```ts
269
- interface SceneEnvironmentConfig {
270
- /** Built-in preset name or 'none' to disable */
271
- preset?: "studio" | "sunset" | "dawn" | "warehouse" | "forest" | "apartment" | "lobby" | "city" | "park" | "night" | "none";
272
- /** Environment map intensity */
273
- intensity?: number;
274
- /** Use environment map as scene background */
275
- background?: boolean;
276
- }
399
+ right(length?: number): LineId
277
400
  ```
278
401
 
279
- </details>
402
+ #### `left()` — Horizontal line going -X. Length is optional.
403
+
404
+ ```ts
405
+ left(length?: number): LineId
406
+ ```
280
407
 
281
- <details><summary><code>SceneFogConfig</code></summary>
408
+ #### `lineAt()` — Line at an arbitrary angle (degrees from +X). Length is optional.
282
409
 
283
410
  ```ts
284
- interface SceneFogConfig {
285
- color?: string;
286
- /** Linear fog near distance */
287
- near?: number;
288
- /** Linear fog far distance */
289
- far?: number;
290
- /** Exponential fog density (if set, uses FogExp2 instead of linear Fog) */
291
- density?: number;
292
- }
411
+ lineAt(angleDeg: number, length?: number): LineId
293
412
  ```
294
413
 
295
- </details>
414
+ #### [`line()`](/docs/sketch#line) — Line with solver-determined direction. Length is optional. Direction comes from tangency to previous arc or from constraints.
415
+
416
+ ```ts
417
+ line(length?: number): LineId
418
+ ```
296
419
 
297
- <details><summary><code>ScenePostProcessingConfig</code></summary>
420
+ #### `toward()` — Line toward a specific point. Length defaults to the distance to that point.
298
421
 
299
422
  ```ts
300
- interface ScenePostProcessingConfig {
301
- bloom?: SceneBloomConfig;
302
- vignette?: SceneVignetteConfig;
303
- grain?: SceneGrainConfig;
304
- toneMappingExposure?: number;
305
- }
423
+ toward(x: number, y: number): LineId
306
424
  ```
307
425
 
308
- </details>
426
+ #### `arcLeft()` — Tangent arc turning left relative to travel direction.
309
427
 
310
- <details><summary><code>SceneBloomConfig</code></summary>
428
+ or `{ minSweep: degrees }` to seed the geometry without constraining. `minSweep` guides the solver to the correct branch for arcs that sweep more than the default 90° seed.
311
429
 
312
430
  ```ts
313
- interface SceneBloomConfig {
314
- intensity?: number;
315
- threshold?: number;
316
- radius?: number;
317
- }
431
+ arcLeft(radius?: number, sweepDegOrOpts?: number | { minSweep: number; }): ArcId
318
432
  ```
319
433
 
320
- </details>
434
+ #### `arcRight()` — Tangent arc turning right relative to travel direction.
321
435
 
322
- <details><summary><code>SceneVignetteConfig</code></summary>
436
+ or `{ minSweep: degrees }` to seed without constraining.
323
437
 
324
438
  ```ts
325
- interface SceneVignetteConfig {
326
- darkness?: number;
327
- offset?: number;
328
- }
439
+ arcRight(radius?: number, sweepDegOrOpts?: number | { minSweep: number; }): ArcId
329
440
  ```
330
441
 
331
- </details>
332
-
333
- <details><summary><code>SceneGrainConfig</code></summary>
442
+ #### `close()` — Close the route with a straight line back to the start point.
334
443
 
335
444
  ```ts
336
- interface SceneGrainConfig {
337
- intensity?: number;
338
- }
445
+ close(): void
339
446
  ```
340
447
 
341
- </details>
448
+ #### `done()` — Close the route back to its start point and register as a profile loop.
342
449
 
343
- <details><summary><code>SceneGroundConfig</code></summary>
450
+ No extra line segment is added. A coincident constraint connects the last point to the start, and tangency is added for G1 smoothness when arcs are at the junction. The session's incremental solver processes these constraints, keeping seed positions accurate for the final solve.
344
451
 
345
452
  ```ts
346
- interface SceneGroundConfig {
347
- /** Show a ground plane */
348
- visible?: boolean;
349
- /** Ground color */
350
- color?: string;
351
- /** Offset below the model's bounding box minimum Z. Default 0 (flush with model bottom). */
352
- offset?: number;
353
- /** Receive shadows on the ground */
354
- receiveShadow?: boolean;
355
- }
453
+ done(): void
356
454
  ```
357
455
 
358
- </details>
359
-
360
- <details><summary><code>SceneCaptureConfig</code></summary>
456
+ #### `start()` — PointId of the route's start point.
361
457
 
362
458
  ```ts
363
- interface SceneCaptureConfig {
364
- /** Frames for one full orbit rotation (default: 72) */
365
- framesPerTurn?: number;
366
- /** Frozen frames before motion starts (default: 6) */
367
- holdFrames?: number;
368
- /** Orbit pitch angle in degrees (default: auto from camera) */
369
- pitchDeg?: number;
370
- /** Output frame rate (default: 24) */
371
- fps?: number;
372
- /** Output frame size in pixels (default: 960) */
373
- size?: number;
374
- /** Canvas background color for capture (default: '#252526') */
375
- background?: string;
376
- }
377
- ```
378
-
379
- </details>
380
-
381
- #### `viewConfig()`
459
+ get start(): PointId
460
+ ```
461
+
462
+ #### `end()` PointId of the current cursor (route's end).
382
463
 
383
464
  ```ts
384
- viewConfig(options?: ViewConfigOptions): void
465
+ get end(): PointId
385
466
  ```
386
467
 
387
- Configure runtime viewport visuals for the current script execution. Multiple calls merge; later values override earlier ones.
468
+ #### `startOf()` Get the start point of a segment.
388
469
 
389
- <details><summary><code>ViewConfigOptions</code></summary>
470
+ ```ts
471
+ startOf(segId: LineId | ArcId): PointId
472
+ ```
473
+
474
+ #### `endOf()` — Get the end point of a segment.
390
475
 
391
476
  ```ts
392
- interface ViewConfigOptions {
393
- jointOverlay?: JointOverlayViewConfigOptions;
394
- }
477
+ endOf(segId: LineId | ArcId): PointId
395
478
  ```
396
479
 
397
- </details>
480
+ ---
398
481
 
399
- <details><summary><code>JointOverlayViewConfigOptions</code></summary>
482
+ ## Constants
400
483
 
401
- ```ts
402
- interface JointOverlayViewConfigOptions {
403
- enabled?: boolean;
404
- axisColor?: string;
405
- axisCoreColor?: string;
406
- arcColor?: string;
407
- zeroColor?: string;
408
- arcVisualLimitDeg?: number;
409
- axisLengthScale?: number;
410
- axisLengthMin?: number;
411
- axisLineRadiusScale?: number;
412
- axisLineRadiusMin?: number;
413
- axisLineRadiusMax?: number;
414
- spokeLineRadiusScale?: number;
415
- spokeLineRadiusMin?: number;
416
- spokeLineRadiusMax?: number;
417
- arcLineRadiusScale?: number;
418
- arcLineRadiusMin?: number;
419
- arcLineRadiusMax?: number;
420
- axisDotRadiusScale?: number;
421
- axisDotRadiusMin?: number;
422
- axisArrowRadiusScale?: number;
423
- axisArrowRadiusMin?: number;
424
- axisArrowLengthScale?: number;
425
- axisArrowLengthMin?: number;
426
- axisArrowOffsetFactor?: number;
427
- arcRadiusScale?: number;
428
- arcRadiusMin?: number;
429
- arcDotRadiusScale?: number;
430
- arcDotRadiusMin?: number;
431
- arcArrowRadiusScale?: number;
432
- arcArrowRadiusMin?: number;
433
- arcArrowLengthScale?: number;
434
- arcArrowLengthMin?: number;
435
- arcArrowOffsetFactor?: number;
436
- arcStepDeg?: number;
437
- arcMinSteps?: number;
438
- arcTubeSegmentsMin?: number;
439
- arcTubeSegmentsFactor?: number;
440
- arcTubeRadialSegments?: number;
441
- }
442
- ```
443
-
444
- </details>
484
+ ### `route`
485
+
486
+ Route step factories. Access via `route.line()`, `route.fillet()`, etc.