forgecad 0.9.13 → 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/LICENSE +6 -4
  2. package/README.md +8 -4
  3. package/dist/assets/{AdminPage-DramHHDf.js → AdminPage-CDyGUinA.js} +2 -2
  4. package/dist/assets/{BenchmarkPage-Bjgkh5m9.js → BenchmarkPage-DfPMY_-d.js} +4 -15
  5. package/dist/assets/{BlogPage-n_HGP3Qm.js → BlogPage-kF0fkdJT.js} +2 -2
  6. package/dist/assets/{DocsPage-WCIkPmzC.js → DocsPage-B954L3YN.js} +9 -3
  7. package/dist/assets/EditorApp-Beb-IZ0y.js +14014 -0
  8. package/dist/assets/{EditorApp-BAnckbsk.css → EditorApp-CuDLxKqL.css} +698 -0
  9. package/dist/assets/{EmbedViewer-DEZKqdfW.js → EmbedViewer-C77B-TrF.js} +3 -3
  10. package/dist/assets/{LandingPageProofDriven-CeRIctuj.js → LandingPageProofDriven-Cr6fXMDj.js} +35 -37
  11. package/dist/assets/LegalPage-BRlScr9A.css +91 -0
  12. package/dist/assets/LegalPage-Dzklqmmg.js +39 -0
  13. package/dist/assets/{PricingPage-BMedqFef.css → PricingPage-BPF6HKyO.css} +25 -0
  14. package/dist/assets/{PricingPage-rIRa8p4Y.js → PricingPage-zWXkvlwl.js} +19 -19
  15. package/dist/assets/{SettingsPage-BqCUvEXM.js → SettingsPage-Bz0of4KQ.js} +2 -2
  16. package/dist/assets/app-CE3sYcV7.css +3890 -0
  17. package/dist/assets/{app-BUZqJvSO.js → app-D3kDkggg.js} +2305 -960
  18. package/dist/assets/cli/{render-lhGxj50Y.js → render-DSY3mMQa.js} +423 -30
  19. package/dist/assets/{constructionHistoryWorker-ipD1jcIv.js → constructionHistoryWorker-gpDo-uH2.js} +927 -243
  20. package/dist/assets/{evalWorker-CHXSe_-u.js → evalWorker-CU0Ke6DP.js} +7799 -4163
  21. package/dist/assets/{forgecad_geometry-BVnIeXMG.js → forgecad_geometry-Dgceylq9.js} +43 -1
  22. package/dist/assets/{forgecad_geometry_bg-DufhhCBV.wasm → forgecad_geometry_bg-dD4RNQF1.wasm} +0 -0
  23. package/dist/assets/{inspectWorker-DeRnMVv1.js → inspectWorker-COyp8XXA.js} +927 -243
  24. package/dist/assets/{javascript-70-4uGcz.js → javascript-1kQXfVaz.js} +1 -1
  25. package/dist/assets/landing-proof-driven-DiGqdtWa.js +18 -0
  26. package/dist/assets/{landing-proof-driven-oFYW6mjz.css → landing-proof-driven-ORyigZ6p.css} +13 -7
  27. package/dist/assets/legalContent-ZfFGMmi4.js +251 -0
  28. package/dist/assets/{manifold-D1LZIHqn.js → manifold-BRI5prcH.js} +1 -1
  29. package/dist/assets/{manifold-C2fwoTgd.js → manifold-C-3h2M7p.js} +2 -2
  30. package/dist/assets/{manifold-BTkzxi9V.js → manifold-DNkrUWpA.js} +1 -1
  31. package/dist/assets/{reportWorker-Cq1qGmg0.js → reportWorker-CdBz5bNg.js} +7537 -10856
  32. package/dist/assets/{scalar-sampling-budget-D9Qv_UlJ.js → scalar-sampling-budget-wJF98aY9.js} +6943 -4345
  33. package/dist/assets/{scanProxyWorker-Bs2TDgLw.js → scanProxyWorker-B-9VbLIs.js} +32 -1
  34. package/dist/assets/{renderSceneState-Dr0xPq1A.js → targets-B9sGB5nB.js} +27 -1
  35. package/dist/assets/{vendor-react-Da3A2QmU.js → vendor-react-6j1Kke-Y.js} +6 -5
  36. package/dist/cli/render.html +1 -1
  37. package/dist/docs/index.html +2 -2
  38. package/dist/docs-raw/AI/ai-native-cad.md +50 -0
  39. package/dist/docs-raw/AI/usage.md +9 -17
  40. package/dist/docs-raw/CLI.md +71 -21
  41. package/dist/docs-raw/component-model.md +27 -11
  42. package/dist/docs-raw/generated/assembly.md +301 -212
  43. package/dist/docs-raw/generated/concepts.md +238 -240
  44. package/dist/docs-raw/generated/core.md +283 -6
  45. package/dist/docs-raw/generated/curves.md +274 -361
  46. package/dist/docs-raw/generated/lib.md +7 -1
  47. package/dist/docs-raw/generated/output.md +19 -4
  48. package/dist/docs-raw/generated/runtime-names.md +41 -0
  49. package/dist/docs-raw/generated/sdf.md +31 -0
  50. package/dist/docs-raw/generated/sheet-metal.md +9 -0
  51. package/dist/docs-raw/generated/sketch.md +44 -1
  52. package/dist/docs-raw/generated/viewport.md +14 -6
  53. package/dist/docs-raw/guides/coordinate-system.md +20 -16
  54. package/dist/docs-raw/guides/geometry-conventions.md +2 -2
  55. package/dist/docs-raw/guides/inspection-bundles.md +2 -1
  56. package/dist/docs-raw/guides/joint-design.md +24 -0
  57. package/dist/docs-raw/guides/positioning.md +13 -3
  58. package/dist/docs-raw/legal/privacy.md +63 -0
  59. package/dist/docs-raw/legal/software-license.md +55 -0
  60. package/dist/docs-raw/legal/terms.md +87 -0
  61. package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +3 -3
  62. package/dist/docs-raw/skills/forgecad-blockout-model.md +1 -1
  63. package/dist/docs-raw/skills/forgecad-component-model.md +11 -2
  64. package/dist/docs-raw/skills/forgecad-high-level-spec.md +1 -1
  65. package/dist/docs-raw/skills/forgecad-image-replicator.md +8 -8
  66. package/dist/docs-raw/skills/forgecad-lld.md +1 -1
  67. package/dist/docs-raw/skills/forgecad-make-a-model.md +4 -4
  68. package/dist/docs-raw/skills/forgecad-model-grader.md +2 -2
  69. package/dist/docs-raw/skills/forgecad-prepare-prompt.md +2 -2
  70. package/dist/docs-raw/skills/forgecad-project.md +1 -1
  71. package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +4 -4
  72. package/dist/docs-raw/skills/forgecad-render-inspect.md +4 -2
  73. package/dist/docs-raw/skills/forgecad-visual-spec.md +1 -1
  74. package/dist/docs-raw/skills/forgecad.md +4 -3
  75. package/dist/index.html +40 -12
  76. package/dist/llms.txt +8 -0
  77. package/dist/site.webmanifest +1 -1
  78. package/dist/sitemap.xml +49 -13
  79. package/dist-cli/{check-compiler-LOXCPEOI.js → check-compiler-SDX5QIXI.js} +1 -2
  80. package/dist-cli/{check-query-propagation-BAKNVWXR.js → check-query-propagation-EAYEFT77.js} +1 -2
  81. package/dist-cli/{chunk-RY43WF46.js → chunk-N4O47JLF.js} +13772 -9938
  82. package/dist-cli/forgecad.js +2387 -899
  83. package/dist-cli/{forgecad_geometry-GYVNKPIE.js → forgecad_geometry-QOQIIP53.js} +42 -1
  84. package/dist-cli/forgecad_geometry_bg.wasm +0 -0
  85. package/dist-cli/{solver-46FFSK2U.js → solver-OK4HECRH.js} +0 -1
  86. package/dist-skill/CONTEXT.md +1120 -724
  87. package/dist-skill/SKILL.md +3 -2
  88. package/dist-skill/docs/API/core/concepts.md +64 -1
  89. package/dist-skill/docs/CLI.md +71 -21
  90. package/dist-skill/docs/generated/assembly.md +277 -229
  91. package/dist-skill/docs/generated/core.md +283 -6
  92. package/dist-skill/docs/generated/curves.md +272 -362
  93. package/dist-skill/docs/generated/lib.md +7 -1
  94. package/dist-skill/docs/generated/output.md +19 -4
  95. package/dist-skill/docs/generated/runtime-names.md +41 -0
  96. package/dist-skill/docs/generated/sdf.md +31 -0
  97. package/dist-skill/docs/generated/sheet-metal.md +9 -0
  98. package/dist-skill/docs/generated/sketch.md +44 -2
  99. package/dist-skill/docs/generated/viewport.md +5 -90
  100. package/dist-skill/docs/guides/coordinate-system.md +20 -16
  101. package/dist-skill/docs/guides/geometry-conventions.md +2 -2
  102. package/dist-skill/docs/guides/inspection-bundles.md +2 -1
  103. package/dist-skill/docs/guides/joint-design.md +24 -0
  104. package/dist-skill/docs/guides/positioning.md +13 -3
  105. package/dist-skill/library/forgecad-3d-reconstruction/SKILL.md +2 -2
  106. package/dist-skill/library/forgecad-component-model/SKILL.md +10 -1
  107. package/dist-skill/library/forgecad-image-replicator/SKILL.md +6 -6
  108. package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.py +166 -0
  109. package/dist-skill/library/forgecad-make-a-model/SKILL.md +3 -3
  110. package/dist-skill/library/forgecad-model-grader/SKILL.md +1 -1
  111. package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +1 -1
  112. package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +3 -3
  113. package/dist-skill/library/forgecad-render-inspect/SKILL.md +3 -1
  114. package/examples/api/assembly-kinematics-foundation.forge.js +65 -0
  115. package/examples/api/assembly-kinematics-four-bar.forge.js +115 -0
  116. package/examples/api/assembly-kinematics-limb.forge.js +116 -0
  117. package/examples/api/connector-frame-rig-chain.forge.js +102 -0
  118. package/examples/api/exact-sheet-shell-assembly.forge.js +0 -2
  119. package/examples/api/exact-surface-studio.forge.js +6 -8
  120. package/examples/api/helix-basics.forge.js +6 -6
  121. package/examples/api/lean-foundations/README.md +12 -0
  122. package/examples/api/lean-foundations/curve-blend-exact.forge.js +22 -0
  123. package/examples/api/lean-foundations/curve-fit-interpolation.forge.js +18 -0
  124. package/examples/api/lean-foundations/curve-helix-canonicalization.forge.js +27 -0
  125. package/examples/api/lean-foundations/curve-route-canonicalization.forge.js +16 -0
  126. package/examples/api/lean-foundations/curve-trim-reverse.forge.js +24 -0
  127. package/examples/api/lean-foundations/exact-curve-arc.forge.js +36 -0
  128. package/examples/api/mixed-edge-finishes-proof.forge.js +8 -11
  129. package/examples/api/route3d-elbow.forge.js +68 -0
  130. package/examples/api/transition-curves.forge.js +44 -15
  131. package/examples/api/y-blend-corner-showcase.forge.js +0 -2
  132. package/examples/generative/coral-vase.forge.js +1 -1
  133. package/examples/nurbs-tube.forge.js +1 -1
  134. package/package.json +14 -18
  135. package/dist/assets/EditorApp-CP9Za6tm.js +0 -13630
  136. package/dist/assets/app-CsHnaBWt.css +0 -1789
  137. package/dist/docs-raw/API/README.md +0 -16
  138. package/dist/docs-raw/API/core/concepts.md +0 -118
  139. package/dist/docs-raw/INDEX.md +0 -138
  140. package/dist/docs-raw/RELEASING.md +0 -87
  141. package/dist/docs-raw/agent-native-api.md +0 -27
  142. package/dist/docs-raw/beta-deployment.md +0 -304
  143. package/dist/docs-raw/beta-operations.md +0 -325
  144. package/dist/docs-raw/blueprint-first.md +0 -145
  145. package/dist/docs-raw/cli-monetization.md +0 -112
  146. package/dist/docs-raw/coding-best-practices.md +0 -120
  147. package/dist/docs-raw/coding.md +0 -340
  148. package/dist/docs-raw/deployment.md +0 -374
  149. package/dist/docs-raw/guides/skill-maintenance.md +0 -161
  150. package/dist/docs-raw/guides/surface-members.md +0 -82
  151. package/dist/docs-raw/internals/backend-vocabulary.md +0 -35
  152. package/dist/docs-raw/internals/compiler.md +0 -307
  153. package/dist/docs-raw/internals/constraint-solver-quality.md +0 -161
  154. package/dist/docs-raw/internals/constraint-solver.md +0 -176
  155. package/dist/docs-raw/internals/shape-from-slices.md +0 -152
  156. package/dist/docs-raw/internals/sketch-2d-pipeline.md +0 -108
  157. package/dist/docs-raw/platform/admin.md +0 -45
  158. package/dist/docs-raw/platform/architecture.md +0 -82
  159. package/dist/docs-raw/platform/auth.md +0 -139
  160. package/dist/docs-raw/platform/email.md +0 -67
  161. package/dist/docs-raw/platform/google-oauth-setup.md +0 -88
  162. package/dist/docs-raw/platform/observability.md +0 -197
  163. package/dist/docs-raw/platform/projects.md +0 -111
  164. package/dist/docs-raw/platform/sharing.md +0 -90
  165. package/dist/docs-raw/product/README.md +0 -39
  166. package/dist/docs-raw/product/api-as-product-language.md +0 -13
  167. package/dist/docs-raw/product/business-model.md +0 -15
  168. package/dist/docs-raw/product/competitive-positioning.md +0 -17
  169. package/dist/docs-raw/product/creative-manufacturing.md +0 -15
  170. package/dist/docs-raw/product/founder-story.md +0 -11
  171. package/dist/docs-raw/product/manufacturing-workflows.md +0 -15
  172. package/dist/docs-raw/product/onboarding-first-experience.md +0 -256
  173. package/dist/docs-raw/product/product-loop.md +0 -17
  174. package/dist/docs-raw/product/strategic-decisions.md +0 -22
  175. package/dist/docs-raw/product/user-outreach-email-templates.md +0 -161
  176. package/dist/docs-raw/product/user-segments.md +0 -15
  177. package/dist/docs-raw/product/vision.md +0 -26
  178. package/dist/docs-raw/rl-environments.md +0 -508
  179. package/dist/docs-raw/runbook.md +0 -611
  180. package/dist-cli/check-compiler-LOXCPEOI.js.map +0 -1
  181. package/dist-cli/check-query-propagation-BAKNVWXR.js.map +0 -1
  182. package/dist-cli/chunk-RY43WF46.js.map +0 -1
  183. package/dist-cli/forgecad.js.map +0 -1
  184. package/dist-cli/forgecad_geometry-GYVNKPIE.js.map +0 -1
  185. package/dist-cli/solver-46FFSK2U.js.map +0 -1
  186. package/dist-skill/SKILL-dev.md +0 -145
  187. package/dist-skill/docs-dev/API/core/concepts.md +0 -118
  188. package/dist-skill/docs-dev/CLI.md +0 -647
  189. package/dist-skill/docs-dev/agent-native-api.md +0 -27
  190. package/dist-skill/docs-dev/blueprint-first.md +0 -145
  191. package/dist-skill/docs-dev/coding-best-practices.md +0 -120
  192. package/dist-skill/docs-dev/coding.md +0 -340
  193. package/dist-skill/docs-dev/component-model.md +0 -164
  194. package/dist-skill/docs-dev/generated/assembly.md +0 -794
  195. package/dist-skill/docs-dev/generated/core.md +0 -2117
  196. package/dist-skill/docs-dev/generated/curves.md +0 -2583
  197. package/dist-skill/docs-dev/generated/lib.md +0 -169
  198. package/dist-skill/docs-dev/generated/output.md +0 -247
  199. package/dist-skill/docs-dev/generated/sdf.md +0 -446
  200. package/dist-skill/docs-dev/generated/sheet-metal.md +0 -504
  201. package/dist-skill/docs-dev/generated/sketch.md +0 -1811
  202. package/dist-skill/docs-dev/generated/viewport.md +0 -585
  203. package/dist-skill/docs-dev/generated/wood.md +0 -108
  204. package/dist-skill/docs-dev/guides/coordinate-system.md +0 -46
  205. package/dist-skill/docs-dev/guides/geometry-conventions.md +0 -52
  206. package/dist-skill/docs-dev/guides/inspection-bundles.md +0 -485
  207. package/dist-skill/docs-dev/guides/joint-design.md +0 -78
  208. package/dist-skill/docs-dev/guides/modeling-recipes.md +0 -78
  209. package/dist-skill/docs-dev/guides/positioning.md +0 -161
  210. package/dist-skill/docs-dev/guides/skill-maintenance.md +0 -161
  211. package/dist-skill/docs-dev/internals/backend-vocabulary.md +0 -35
  212. package/dist-skill/docs-dev/internals/compiler.md +0 -307
  213. package/dist-skill/docs-dev/internals/constraint-solver-quality.md +0 -161
  214. package/dist-skill/docs-dev/internals/constraint-solver.md +0 -176
  215. package/dist-skill/docs-dev/internals/sketch-2d-pipeline.md +0 -108
  216. package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.mjs +0 -289
@@ -0,0 +1,102 @@
1
+ // Connector-frame rig chain: serial articulated parts need full connector frames.
2
+ //
3
+ // Use link() graphs for solved point skeletons and closed loops. Use connect()
4
+ // when real geometry must inherit orientation from a joint frame. Here the upper
5
+ // leg's local +X axis is locked by connector up vectors, so the part points from
6
+ // the hip pivot toward the knee pivot at every solved pose. Return the Assembly
7
+ // itself so editor controls call solve(state) instead of stacking viewport FK.
8
+
9
+ const DEFAULT_POSE = { hip: 22, knee: -42, wheel: 0 };
10
+
11
+ const upperLength = 68;
12
+ const lowerLength = 58;
13
+ const legWidth = 10;
14
+ const legThickness = 8;
15
+ const hubRadius = 9;
16
+ const wheelRadius = 16;
17
+ const wheelThickness = 8;
18
+
19
+ function hingeConnector(origin, axis, up, type = "planar-hinge") {
20
+ return connector(type, { origin, axis, up, kind: "revolute" });
21
+ }
22
+
23
+ function legSegment(length, colorHex) {
24
+ const body = box(length, legWidth, legThickness).translate(length / 2, 0, -legThickness / 2);
25
+ const nearHub = cylinder(legThickness, hubRadius).translate(0, 0, -legThickness / 2);
26
+ const farHub = cylinder(legThickness, hubRadius).translate(length, 0, -legThickness / 2);
27
+
28
+ return group(
29
+ { name: "Body", shape: body },
30
+ { name: "Near hub", shape: nearHub },
31
+ { name: "Far hub", shape: farHub },
32
+ ).color(colorHex);
33
+ }
34
+
35
+ const hipDrum = group({
36
+ name: "Drum",
37
+ shape: cylinder(18, 14).translate(0, 0, -9).color("#495057"),
38
+ }).withConnectors({
39
+ hip: hingeConnector([0, 0, 0], [0, 0, 1], [1, 0, 0]),
40
+ });
41
+
42
+ const upperLeg = legSegment(upperLength, "#d55e5e").withConnectors({
43
+ hip: hingeConnector([0, 0, 0], [0, 0, -1], [1, 0, 0]),
44
+ knee: hingeConnector([upperLength, 0, 0], [0, 0, 1], [1, 0, 0]),
45
+ });
46
+
47
+ const lowerLeg = legSegment(lowerLength, "#3d87c7").withConnectors({
48
+ knee: hingeConnector([0, 0, 0], [0, 0, -1], [1, 0, 0]),
49
+ axle: hingeConnector([lowerLength, 0, 0], [0, 1, 0], [1, 0, 0], "wheel-axle"),
50
+ });
51
+
52
+ const wheel = group({
53
+ name: "Wheel",
54
+ shape: cylinder(wheelThickness, wheelRadius)
55
+ .pointAlong([0, 1, 0])
56
+ .translate(0, -wheelThickness / 2, 0)
57
+ .color("#212529"),
58
+ }).withConnectors({
59
+ axle: hingeConnector([0, 0, 0], [0, -1, 0], [1, 0, 0], "wheel-axle"),
60
+ });
61
+
62
+ const rig = assembly("Connector Frame Rig Chain")
63
+ .addPart("Hip Drum", hipDrum)
64
+ .addPart("Upper Leg", upperLeg)
65
+ .addPart("Lower Leg", lowerLeg)
66
+ .addPart("Wheel", wheel)
67
+ .connect("Hip Drum.hip", "Upper Leg.hip", { as: "hip", min: -35, max: 55, default: DEFAULT_POSE.hip })
68
+ .connect("Upper Leg.knee", "Lower Leg.knee", { as: "knee", min: -90, max: 20, default: DEFAULT_POSE.knee })
69
+ .connect("Lower Leg.axle", "Wheel.axle", { as: "wheel", min: -180, max: 180, default: DEFAULT_POSE.wheel });
70
+
71
+ const solved = rig.solve(DEFAULT_POSE);
72
+
73
+ const upper = solved.getTransform("Upper Leg");
74
+ const lower = solved.getTransform("Lower Leg");
75
+ const wheelTx = solved.getTransform("Wheel");
76
+
77
+ const hip = upper.point([0, 0, 0]);
78
+ const kneeFromUpper = upper.point([upperLength, 0, 0]);
79
+ const kneeFromLower = lower.point([0, 0, 0]);
80
+ const axleFromLower = lower.point([lowerLength, 0, 0]);
81
+ const axleFromWheel = wheelTx.point([0, 0, 0]);
82
+
83
+ const upperLocalX = upper.vector([1, 0, 0]);
84
+ const hipToKnee = Points.direction(hip, kneeFromUpper);
85
+
86
+ verify.equal("knee connector origins coincide", Points.distance(kneeFromUpper, kneeFromLower), 0, 0.001);
87
+ verify.equal("wheel axle connector origins coincide", Points.distance(axleFromLower, axleFromWheel), 0, 0.001);
88
+ verify.equal("upper leg local +X points hip to knee", Points.distance(upperLocalX, hipToKnee), 0, 0.001);
89
+
90
+ scene({
91
+ background: { top: "#edf2f7", bottom: "#ffffff" },
92
+ camera: { position: [115, -190, 120], target: [45, 12, 0], fov: 34 },
93
+ environment: { preset: "studio", intensity: 0.45 },
94
+ lights: [
95
+ { type: "ambient", color: "#e8edf5", intensity: 0.25 },
96
+ { type: "directional", position: [120, -140, 180], target: [35, 5, 0], color: "#fff5e6", intensity: 1.6, castShadow: true },
97
+ { type: "directional", position: [-80, 100, 120], target: [40, 15, 0], color: "#c9ddff", intensity: 0.7 },
98
+ ],
99
+ ground: { visible: true, color: "#f6f8fa", height: -wheelRadius, receiveShadow: true },
100
+ });
101
+
102
+ return rig;
@@ -1,5 +1,3 @@
1
- if (getActiveBackend() === 'manifold') setActiveBackend('truck');
2
-
3
1
  const width = param('Width', 112);
4
2
  const depth = param('Depth', 78);
5
3
  const height = param('Height', 44);
@@ -1,5 +1,3 @@
1
- if (getActiveBackend() === 'manifold') setActiveBackend('truck');
2
-
3
1
  const span = param('Span', 128);
4
2
  const depth = param('Depth', 88);
5
3
  const crown = param('Crown', 26);
@@ -41,7 +39,7 @@ const canopySheet = Surface.Nurbs(
41
39
  const canopySolid = canopySheet.thicken(wall).translate(-span * 0.82, 0, 0).color('#9fd3ff');
42
40
  const canopyGhost = canopySheet.translate(-span * 0.82, 0, wall * 2.4).color('#d9f0ff');
43
41
 
44
- const archFront = nurbs3d(
42
+ const archFront = Curve.Nurbs(
45
43
  [
46
44
  [-halfSpan * 0.55, -halfDepth * 0.58, 2],
47
45
  [-halfSpan * 0.18, -halfDepth * 0.58, crown * 0.95],
@@ -50,7 +48,7 @@ const archFront = nurbs3d(
50
48
  ],
51
49
  { degree: 3 },
52
50
  );
53
- const archBack = nurbs3d(
51
+ const archBack = Curve.Nurbs(
54
52
  [
55
53
  [-halfSpan * 0.48, halfDepth * 0.52, 0],
56
54
  [-halfSpan * 0.14, halfDepth * 0.52, crown * 0.68],
@@ -65,7 +63,7 @@ const ruledRibbon = Surface.Ruled(archFront, archBack)
65
63
 
66
64
  const boundaryPatch = Surface.Patch(
67
65
  {
68
- bottom: nurbs3d(
66
+ bottom: Curve.Nurbs(
69
67
  [
70
68
  [-halfSpan * 0.48, -halfDepth * 0.42, -2],
71
69
  [-halfSpan * 0.16, -halfDepth * 0.46, crown * 0.35],
@@ -74,7 +72,7 @@ const boundaryPatch = Surface.Patch(
74
72
  ],
75
73
  { degree: 3 },
76
74
  ),
77
- top: nurbs3d(
75
+ top: Curve.Nurbs(
78
76
  [
79
77
  [-halfSpan * 0.48, halfDepth * 0.4, 1],
80
78
  [-halfSpan * 0.16, halfDepth * 0.43, crown * 0.62],
@@ -83,7 +81,7 @@ const boundaryPatch = Surface.Patch(
83
81
  ],
84
82
  { degree: 3 },
85
83
  ),
86
- left: nurbs3d(
84
+ left: Curve.Nurbs(
87
85
  [
88
86
  [-halfSpan * 0.48, -halfDepth * 0.42, -2],
89
87
  [-halfSpan * 0.58, -halfDepth * 0.12, crown * 0.22],
@@ -92,7 +90,7 @@ const boundaryPatch = Surface.Patch(
92
90
  ],
93
91
  { degree: 3 },
94
92
  ),
95
- right: nurbs3d(
93
+ right: Curve.Nurbs(
96
94
  [
97
95
  [halfSpan * 0.48, -halfDepth * 0.42, -2],
98
96
  [halfSpan * 0.58, -halfDepth * 0.12, crown * 0.22],
@@ -1,14 +1,14 @@
1
- // Helix API basics.
1
+ // Curve.Helix API basics.
2
2
  //
3
- // Helix.path() is the reusable centerline primitive.
4
- // Helix.coil() turns the same helix definition into a solid helix-oriented coil.
3
+ // Curve.Helix.path() is the reusable centerline primitive.
4
+ // Curve.Helix.coil() turns the same helix definition into a solid helix-oriented coil.
5
5
 
6
6
  const radius = Param.number("Radius", 18, { min: 8, max: 32, step: 1, unit: "mm" });
7
7
  const pitch = Param.number("Pitch", 6, { min: 2, max: 12, step: 0.5, unit: "mm" });
8
8
  const turns = Param.number("Turns", 4, { min: 1, max: 7, step: 0.25 });
9
9
  const wireRadius = Param.number("Wire Radius", 1, { min: 0.25, max: 2.5, step: 0.25, unit: "mm" });
10
10
 
11
- const guide = Helix.path({
11
+ const guide = Curve.Helix.path({
12
12
  radius,
13
13
  pitch,
14
14
  turns,
@@ -16,7 +16,7 @@ const guide = Helix.path({
16
16
  samplesPerTurn: 48,
17
17
  });
18
18
 
19
- const circularWireCoil = Helix.coil({
19
+ const circularWireCoil = Curve.Helix.coil({
20
20
  radius,
21
21
  pitch,
22
22
  turns,
@@ -26,7 +26,7 @@ const circularWireCoil = Helix.coil({
26
26
  }).translate(-70, 0, 0);
27
27
 
28
28
  const rectangularProfile = rect(wireRadius * 2.4, wireRadius * 1.1);
29
- const rectangularWireCoil = Helix.coil(rectangularProfile, {
29
+ const rectangularWireCoil = Curve.Helix.coil(rectangularProfile, {
30
30
  radius,
31
31
  height: guide.height,
32
32
  turns,
@@ -0,0 +1,12 @@
1
+ # Selected Lean Foundations Examples
2
+
3
+ This pack contains only the currently selected lean API buckets: Curve / Route and route endpoint canonicalization. Surface, standalone Frame, FaceRef, and topology-selector expansion examples were intentionally left out of this split.
4
+
5
+ Run these with `node dist-cli/forgecad.js run <file>`:
6
+
7
+ - `curve-blend-exact.forge.js` - `Curve.Blend` and `Curve.BlendG2` as exact reference rails that also feed `sweep`.
8
+ - `curve-fit-interpolation.forge.js` - `Curve.Fit` interpolation with residual validation.
9
+ - `curve-helix-canonicalization.forge.js` - `Curve.Helix` path and coil canonicalization.
10
+ - `curve-route-canonicalization.forge.js` - `Curve.Route.fromPolyline()` segment and port preservation.
11
+ - `curve-trim-reverse.forge.js` - exact trim and reverse operations.
12
+ - `exact-curve-arc.forge.js` - exact `Curve.Arc` construction and sweep use.
@@ -0,0 +1,22 @@
1
+ const g1Rail = Curve.Blend(
2
+ { point: [0, 0, 0], tangent: [1, 0, 0], weight: 0.7 },
3
+ { point: [48, 22, 10], tangent: [0, 1, 0], weight: 0.65 },
4
+ );
5
+
6
+ const g2Rail = Curve.BlendG2(
7
+ { point: [0, 18, 0], tangent: [1, 0, 0], curvature: [0, 0.01, 0], weight: 0.55 },
8
+ { point: [48, 42, 10], tangent: [0, 1, 0], curvature: [-0.01, 0, 0], weight: 0.55 },
9
+ );
10
+
11
+ const g1Tube = sweep(circle2d(1.6), g1Rail);
12
+ const g2Tube = sweep(circle2d(1.2), g2Rail).color("#5a8f7b");
13
+
14
+ const close3d = (a, b, tolerance = 1e-6) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]) <= tolerance;
15
+
16
+ verify.equal("Curve.Blend returns a cubic NURBS", g1Rail.degree, 3);
17
+ verify.equal("Curve.BlendG2 returns a quintic NURBS", g2Rail.degree, 5);
18
+ verify.that("Curve.Blend hits directed endpoints", () => close3d(g1Rail.pointAt(0), [0, 0, 0]) && close3d(g1Rail.pointAt(1), [48, 22, 10]));
19
+ verify.that("Curve.BlendG2 hits directed endpoints", () => close3d(g2Rail.pointAt(0), [0, 18, 0]) && close3d(g2Rail.pointAt(1), [48, 42, 10]));
20
+ verify.greaterThan("Blend rails are usable as sweep paths", g1Tube.boundingBox().max[0], 45);
21
+
22
+ return group(g1Tube, g2Tube);
@@ -0,0 +1,18 @@
1
+ const fittedRail = Curve.Fit(
2
+ [
3
+ [0, 0, 0],
4
+ [16, 8, 10],
5
+ [36, -6, 18],
6
+ [58, 10, 12],
7
+ [78, 0, 0],
8
+ ],
9
+ { degree: 3, tolerance: 0.001 },
10
+ );
11
+
12
+ const tube = sweep(circle2d(2), fittedRail);
13
+
14
+ verify.equal('Curve.Fit returns a cubic NURBS for this rail', fittedRail.degree, 3);
15
+ verify.equal('Curve.Fit keeps one control point per interpolated point', fittedRail.controlPoints.length, 5);
16
+ verify.greaterThan('Curve.Fit rail has positive length', fittedRail.length(), 0);
17
+
18
+ return tube;
@@ -0,0 +1,27 @@
1
+ const guide = Curve.Helix.path({
2
+ radius: 14,
3
+ pitch: 5,
4
+ turns: 3,
5
+ samplesPerTurn: 30,
6
+ });
7
+
8
+ const roundCoil = Curve.Helix.coil({
9
+ radius: 14,
10
+ pitch: 5,
11
+ turns: 3,
12
+ wireRadius: 0.8,
13
+ profileSegments: 16,
14
+ divisionsPerTurn: 100,
15
+ });
16
+
17
+ const rectangularCoil = Curve.Helix.coil(rect(1.2, 0.8), {
18
+ radius: 20,
19
+ height: 15,
20
+ turns: 3,
21
+ divisionsPerTurn: 18,
22
+ }).translate(50, 0, 0);
23
+
24
+ verify.equal('Curve.Helix guide derives height from pitch and turns', guide.height, 15);
25
+ verify.greaterThan('Curve.Helix guide has positive centerline length', guide.length(), 0);
26
+
27
+ return union(roundCoil, rectangularCoil);
@@ -0,0 +1,16 @@
1
+ const route = Curve.Route.fromPolyline(
2
+ [
3
+ [0, 0, 0],
4
+ [0, 0, 48],
5
+ [36, 0, 48],
6
+ [36, 24, 72],
7
+ ],
8
+ { cornerRadius: 10, startPort: 'inlet', endPort: 'outlet' },
9
+ );
10
+
11
+ const tube = sweep(difference2d(circle2d(5), circle2d(3.5)), route);
12
+ verify.equal('Curve.Route keeps line-arc-line-arc-line route intent', route.segments.length, 5);
13
+ verify.equal('Curve.Route exposes named ports', Object.keys(route.ports).length, 2);
14
+ verify.greaterThan('Curve.Route remains usable as a sweep path', tube.boundingBox().max[2], 70);
15
+
16
+ return route;
@@ -0,0 +1,24 @@
1
+ const rail = Curve.Fit(
2
+ [
3
+ [0, 0, 0],
4
+ [24, 10, 8],
5
+ [54, -8, 12],
6
+ [84, 0, 0],
7
+ ],
8
+ { degree: 3 },
9
+ );
10
+
11
+ const middle = Curve.Trim(rail, 0.2, 0.8);
12
+ const reversed = Curve.Reverse(middle);
13
+
14
+ const middleTube = sweep(circle2d(1.2), middle).color("#5f8cc0");
15
+ const reversedTube = sweep(circle2d(0.8), reversed).translate(0, 18, 0).color("#c06f5f");
16
+
17
+ const close3d = (a, b, tolerance = 1e-6) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]) <= tolerance;
18
+
19
+ verify.that("Curve.Trim starts at the source subdomain", () => close3d(middle.pointAt(0), rail.pointAt(0.2)));
20
+ verify.that("Curve.Trim ends at the source subdomain", () => close3d(middle.pointAt(1), rail.pointAt(0.8)));
21
+ verify.that("Curve.Reverse preserves geometry with opposite parameter direction", () => close3d(reversed.pointAt(0), middle.pointAt(1)));
22
+ verify.greaterThan("Trimmed curves feed exact sweep rails", middleTube.boundingBox().max[0], 60);
23
+
24
+ return group(middleTube, reversedTube);
@@ -0,0 +1,36 @@
1
+ const lower = Curve.Arc({
2
+ start: [36, 0, 0],
3
+ end: [0, 36, 0],
4
+ tangent: [0, 1, 0],
5
+ });
6
+ const upper = Curve.Arc({
7
+ start: [36, 0, 10],
8
+ end: [0, 36, 10],
9
+ tangent: [0, 1, 0],
10
+ });
11
+ const half = Curve.Arc({
12
+ start: [12, 0, 18],
13
+ end: [-12, 0, 18],
14
+ tangent: [0, 1, 0],
15
+ });
16
+
17
+ const tube = sweep(circle2d(0.8), lower);
18
+ const upperTube = sweep(circle2d(0.5), upper).color("#5a8f7b");
19
+
20
+ const close3d = (a, b, tolerance = 1e-6) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]) <= tolerance;
21
+
22
+ verify.that("Curve.Arc hits start, midpoint, and end exactly", () =>
23
+ close3d(lower.pointAt(0), [36, 0, 0]) &&
24
+ close3d(lower.pointAt(0.5), [36 * Math.SQRT1_2, 36 * Math.SQRT1_2, 0]) &&
25
+ close3d(lower.pointAt(1), [0, 36, 0]));
26
+
27
+ verify.that("Curve.Arc emits stable rational spans for half circles", () =>
28
+ half.controlPoints.length === 5 && close3d(half.pointAt(0.5), [0, 12, 18]));
29
+
30
+ verify.that("Curve.Arc feeds sweep as an exact NURBS rail", () =>
31
+ tube.geometryInfo().backend !== "unknown" && tube.boundingBox().max[0] > 30 && tube.boundingBox().max[1] > 30);
32
+
33
+ verify.that("Multiple Curve.Arc rails remain reusable sweep inputs", () =>
34
+ upperTube.boundingBox().max[2] > 10 && upperTube.boundingBox().max[0] > 30);
35
+
36
+ return group(tube, upperTube);
@@ -27,17 +27,14 @@ const body = plate.subtract(cutout);
27
27
  const bodyEdges = selectEdges(body);
28
28
  const raw = body.color('#7b8490');
29
29
  const chamfered = chamfer(body, 0.75, bodyEdges).color('#d3a33a');
30
- const shapes = [
30
+ // Native Truck fillet now produces analytic rolling-ball geometry (cylinders,
31
+ // spheres, and toroidal corner blends) that exports to STEP canonically
32
+ // identical to OpenCascade. See:
33
+ // forgecad export step examples/api/mixed-edge-finishes-proof.forge.js --backend truck
34
+ const filleted = fillet(body, 0.75, bodyEdges).color('#4e8fd6');
35
+
36
+ return [
31
37
  { name: 'Raw', shape: raw.translate(-80, 0, 0) },
32
38
  { name: 'Chamfered', shape: chamfered.translate(30, 0, 0) },
39
+ { name: 'Filleted', shape: filleted.translate(140, 0, 0) },
33
40
  ];
34
-
35
- try {
36
- const filleted = fillet(body, 0.75, bodyEdges).color('#4e8fd6');
37
- filleted.volume();
38
- shapes.push({ name: 'Filleted', shape: filleted.translate(140, 0, 0) });
39
- } catch (error) {
40
- console.log(`Filleted: unsupported in native Truck (${error instanceof Error ? error.message : String(error)})`);
41
- }
42
-
43
- return shapes;
@@ -0,0 +1,68 @@
1
+ // Curve.Route elbow - demonstrates virtual 3D route corners, named route ports,
2
+ // and sweeping an annular profile without hand-computing tangent points.
3
+
4
+ const route = Curve.Route.fromPolyline(
5
+ [
6
+ [0, 0, 0],
7
+ [0, 0, 203.2],
8
+ [203.2, 0, 203.2],
9
+ ],
10
+ { cornerRadius: 114.3, startPort: 'inlet', endPort: 'outlet' },
11
+ );
12
+
13
+ const outerRadius = 44.45;
14
+ const innerRadius = 38.96;
15
+ const flangeRadius = 89.0;
16
+ const boltCircleRadius = 72.3;
17
+ const boltRadius = 5.3;
18
+ const flangeThickness = 17.8;
19
+ const neckLength = 26.645;
20
+ const neckRadius = 55.6;
21
+
22
+ const tubeProfile = difference2d(circle2d(outerRadius, 80), circle2d(innerRadius, 80));
23
+ const pipe = sweep(tubeProfile, route, { samples: 72 });
24
+
25
+ function placeAtPort(shape, port, offset) {
26
+ return shape.pointAlong(port.axis).translate(
27
+ port.origin[0] + port.axis[0] * offset,
28
+ port.origin[1] + port.axis[1] * offset,
29
+ port.origin[2] + port.axis[2] * offset,
30
+ );
31
+ }
32
+
33
+ function flangePlate() {
34
+ const bore = cylinder(flangeThickness + 2, innerRadius, undefined, 80).translate(0, 0, -1);
35
+ const firstBolt = cylinder(flangeThickness + 2, boltRadius, undefined, 24).translate(boltCircleRadius, 0, -1);
36
+ const bolts = circularPattern(firstBolt, 5);
37
+ return cylinder(flangeThickness, flangeRadius, undefined, 96).subtract(bore, bolts);
38
+ }
39
+
40
+ function neck() {
41
+ const bore = cylinder(neckLength + 2, innerRadius, undefined, 80).translate(0, 0, -1);
42
+ return cylinder(neckLength, neckRadius, undefined, 80).subtract(bore);
43
+ }
44
+
45
+ const inlet = route.port('inlet');
46
+ const outlet = route.port('outlet');
47
+ const body = union(
48
+ pipe,
49
+ placeAtPort(neck(), inlet, -4.445),
50
+ placeAtPort(flangePlate(), inlet, 20.0),
51
+ placeAtPort(neck(), outlet, -4.445),
52
+ placeAtPort(flangePlate(), outlet, 20.0),
53
+ ).color('#b9c0c8');
54
+
55
+ const bbox = body.boundingBox();
56
+ const bboxSize = [bbox.max[0] - bbox.min[0], bbox.max[1] - bbox.min[1], bbox.max[2] - bbox.min[2]];
57
+
58
+ verify.equal('Curve.Route elbow keeps line-arc-line route intent', route.segments.length, 3);
59
+ verify.equal('Curve.Route elbow exposes inlet and outlet ports', Object.keys(route.ports).length, 2);
60
+ verify.boundingBoxSize('Curve.Route elbow preserves BenchCAD-scale envelope', body, [337, 178, 330], 18);
61
+ verify.that(
62
+ 'Curve.Route elbow bbox stays in expected quadrants',
63
+ () => bbox.min[0] < -40 && bbox.max[0] > 235 && bbox.min[2] < -35 && bbox.max[2] > 245 && bboxSize[1] > 175,
64
+ `bbox was ${JSON.stringify(bbox)}`,
65
+ );
66
+ verify.physicalComponentCount('Curve.Route elbow is one connected component', 1);
67
+
68
+ return body;
@@ -1,6 +1,5 @@
1
- // Transition Curves — smooth connections between edges
2
- // Demonstrates transitionCurve(), transitionSurface(), connectEdges(),
3
- // and weighted blending (G1 + G2 continuity).
1
+ // Curve blends — smooth connections between edges
2
+ // Demonstrates Curve.Blend(), sweep(), local edge recipes, and weighted blending.
4
3
 
5
4
  const weight = Param.number("Weight A", 1.0, { min: 0.1, max: 5.0, step: 0.1 });
6
5
  const weightB = Param.number("Weight B", 1.0, { min: 0.1, max: 5.0, step: 0.1 });
@@ -12,9 +11,43 @@ function anchor(pos) {
12
11
  return box(s, s, s).translate(pos[0], pos[1], pos[2]);
13
12
  }
14
13
 
14
+ function blendTube(edgeA, edgeB, options = {}) {
15
+ const curve = Curve.Blend(
16
+ { point: edgeA.point, tangent: edgeA.tangent, weight: options.weightA },
17
+ { point: edgeB.point, tangent: edgeB.tangent, weight: options.weightB },
18
+ );
19
+ const profile = options.profile ?? circle2d(options.radius ?? radius);
20
+ return sweep(profile, curve, { samples: options.samples, up: options.up });
21
+ }
22
+
23
+ function normalized(vec, fallback = [1, 0, 0]) {
24
+ const length = Math.hypot(vec[0], vec[1], vec[2]);
25
+ return length > 1e-9 ? [vec[0] / length, vec[1] / length, vec[2] / length] : fallback;
26
+ }
27
+
28
+ function edgePoint(edge, which = 'mid') {
29
+ if (which === 'start') return edge.start;
30
+ if (which === 'end') return edge.end;
31
+ return edge.midpoint;
32
+ }
33
+
34
+ function edgeOutward(edge) {
35
+ const a = edge.normalA ?? [0, 0, 0];
36
+ const b = edge.normalB ?? [0, 0, 0];
37
+ return normalized([a[0] + b[0], a[1] + b[1], a[2] + b[2]], edge.direction ?? [1, 0, 0]);
38
+ }
39
+
40
+ function edgeBlendTube(edgeA, edgeB, options = {}) {
41
+ return blendTube(
42
+ { point: edgePoint(edgeA, options.endA), tangent: edgeOutward(edgeA) },
43
+ { point: edgePoint(edgeB, options.endB), tangent: edgeOutward(edgeB) },
44
+ options,
45
+ );
46
+ }
47
+
15
48
  // ── 1. L-bend: 90-degree pipe turn ──────────────────────────────
16
49
  const pA1 = [0, 0, 0], pB1 = [30, 20, 0];
17
- const lBend = transitionSurface(
50
+ const lBend = blendTube(
18
51
  { point: pA1, tangent: [1, 0, 0] },
19
52
  { point: pB1, tangent: [0, 1, 0] },
20
53
  { radius, weightA: weight, weightB: weightB },
@@ -22,7 +55,7 @@ const lBend = transitionSurface(
22
55
 
23
56
  // ── 2. S-curve: opposing tangents ────────────────────────────────
24
57
  const pA2 = [0, 40, 0], pB2 = [30, 60, 0];
25
- const sCurve = transitionSurface(
58
+ const sCurve = blendTube(
26
59
  { point: pA2, tangent: [1, 0, 0] },
27
60
  { point: pB2, tangent: [-1, 0, 0] },
28
61
  { radius, weightA: weight, weightB: weightB },
@@ -30,7 +63,7 @@ const sCurve = transitionSurface(
30
63
 
31
64
  // ── 3. 3D transition: going up and around ────────────────────────
32
65
  const pA3 = [0, 0, 30], pB3 = [25, 15, 45];
33
- const transition3D = transitionSurface(
66
+ const transition3D = blendTube(
34
67
  { point: pA3, tangent: [1, 0, 0] },
35
68
  { point: pB3, tangent: [0, 0, 1] },
36
69
  { radius, weightA: weight, weightB: weightB, up: [0, 1, 0] },
@@ -38,7 +71,7 @@ const transition3D = transitionSurface(
38
71
 
39
72
  // ── 4. Asymmetric weight (3:0.5) ────────────────────────────────
40
73
  const pA4 = [55, 0, 0], pB4 = [85, 20, 0];
41
- const weighted = transitionSurface(
74
+ const weighted = blendTube(
42
75
  { point: pA4, tangent: [1, 0, 0] },
43
76
  { point: pB4, tangent: [0, 1, 0] },
44
77
  { radius, weightA: 3.0, weightB: 0.5 },
@@ -51,25 +84,21 @@ const boxB = box(10, 10, 10).translate(35, 15, -20);
51
84
  const topEdgeA = selectEdge(boxA, { atZ: -25, parallel: [1, 0, 0] });
52
85
  const bottomEdgeB = selectEdge(boxB, { atZ: -20, parallel: [1, 0, 0] });
53
86
 
54
- const edgeConnector = connectEdges(topEdgeA, bottomEdgeB, {
87
+ const edgeConnector = edgeBlendTube(topEdgeA, bottomEdgeB, {
55
88
  endA: 'mid',
56
89
  endB: 'mid',
57
- tangentModeA: 'outward',
58
- tangentModeB: 'outward',
59
90
  radius: 2,
60
91
  weightA: weight,
61
92
  weightB: weightB,
62
93
  });
63
94
 
64
- // ── 6. connectEdges shortcut ─────────────────────────────────────
95
+ // ── 6. Same local edge recipe on vertical side edges ─────────────
65
96
  const sideEdgeA = selectEdge(boxA, { near: [5, 0, -30], parallel: [0, 0, 1] });
66
97
  const sideEdgeB = selectEdge(boxB, { near: [30, 15, -15], parallel: [0, 0, 1] });
67
98
 
68
- const shortcutConnector = connectEdges(sideEdgeA, sideEdgeB, {
99
+ const shortcutConnector = edgeBlendTube(sideEdgeA, sideEdgeB, {
69
100
  endA: 'mid',
70
101
  endB: 'mid',
71
- tangentModeA: 'outward',
72
- tangentModeB: 'outward',
73
102
  radius: 1.5,
74
103
  weightA: weight,
75
104
  weightB: weightB,
@@ -85,7 +114,7 @@ const box2 = box(12, 12, 12).translate(25, -55, 25);
85
114
  // Cylinder rim at Y=-55: full radius available, so X=8 is on the rim.
86
115
  // Box left face at X=25, Y=-55 is on the face edge, Z=31 is mid-height.
87
116
  // End tangent [1,0,0] means the curve arrives going +X (into the face).
88
- const cylToBox = transitionSurface(
117
+ const cylToBox = blendTube(
89
118
  { point: [8, -55, 20], tangent: [1, 0, 0.65] },
90
119
  { point: [25, -55, 31], tangent: [1, 0, 0] },
91
120
  { radius: 1.5, weightA: weight, weightB: weightB },
@@ -1,5 +1,3 @@
1
- if (getActiveBackend() === 'manifold') setActiveBackend('truck');
2
-
3
1
  const width = param('Width', 104);
4
2
  const depth = param('Depth', 76);
5
3
  const height = param('Height', 42);
@@ -9,5 +9,5 @@ const coral = sdf.noise({ scale: 0.15, amplitude: 3, octaves: 4, seed: 7 });
9
9
  return vase
10
10
  .shell(3)
11
11
  .intersect(coral)
12
- .toShape({ edgeLength: 0.5 })
12
+ // .toShape({ edgeLength: 0.5 })
13
13
  .color('#e07856');
@@ -1,5 +1,5 @@
1
1
  // NURBS curve swept into a smooth tube
2
- const curve = nurbs3d(
2
+ const curve = Curve.Nurbs(
3
3
  [[0,0,0], [15,8,0], [25,-3,10], [40,5,15], [50,0,5]],
4
4
  { degree: 3 }
5
5
  );