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
@@ -47,16 +47,16 @@ const innerRadius = radius - rimWidth;
47
47
  const handBaseZ = depth / 2 - 2;
48
48
 
49
49
  // === Clock Rim ===
50
- const outer = cylinder(depth, radius, undefined, undefined, true);
51
- const inner = cylinder(depth + 2, innerRadius, undefined, undefined, true);
50
+ const outer = cylinder(depth, radius);
51
+ const inner = cylinder(depth + 2, innerRadius);
52
52
  const rimBody = outer.subtract(inner);
53
53
 
54
54
  // Add subtle bevel to rim edge
55
- const bevel = cylinder(depth - 5, radius - 1, radius, undefined, true);
55
+ const bevel = cylinder(depth - 5, radius - 1, radius);
56
56
  const rim = union(rimBody, bevel).color(rimHex);
57
57
 
58
58
  // === Clock Face ===
59
- const face = cylinder(2, innerRadius - 1, undefined, undefined, true)
59
+ const face = cylinder(2, innerRadius - 1)
60
60
  .translate(0, 0, depth / 2 - 3)
61
61
  .color(faceHex);
62
62
 
@@ -76,7 +76,7 @@ for (let i = 0; i < 12; i++) {
76
76
  const x = Math.cos(rad) * r;
77
77
  const y = Math.sin(rad) * r;
78
78
 
79
- const tick = roundedRect(width, length, width / 2, true)
79
+ const tick = roundedRect(width, length, width / 2)
80
80
  .rotateAround([0, 0, 0], angle)
81
81
  .extrude(1)
82
82
  .translate(x, y, depth / 2 - 2);
@@ -100,10 +100,10 @@ const secondAngle = second * 6;
100
100
 
101
101
  // Create Apple-style hand with rounded ends
102
102
  function createHand(length, width, angle, zOffset, thickness) {
103
- return roundedRect(width, length, width / 2, true)
103
+ return roundedRect(width, length, width / 2)
104
104
  .translate(0, length / 2)
105
105
  .extrude(thickness)
106
- .rotateAround([0, 0, 0], 0, 0, angle - 90)
106
+ .rotateZ(angle - 90)
107
107
  .translate(0, 0, zOffset);
108
108
  }
109
109
 
@@ -122,10 +122,10 @@ if (showSecondHand > 0) {
122
122
  const counterWidth = 4;
123
123
 
124
124
  const sweep = createHand(secondHandLength, secondHandWidth, secondAngle, handBaseZ + 10, 2);
125
- const counter = roundedRect(counterWidth, counterLength, counterWidth / 2, true)
125
+ const counter = roundedRect(counterWidth, counterLength, counterWidth / 2)
126
126
  .translate(0, -counterLength / 2)
127
127
  .extrude(2)
128
- .rotateAround([0, 0, 0], 0, 0, secondAngle - 90)
128
+ .rotateZ(secondAngle - 90)
129
129
  .translate(0, 0, handBaseZ + 10);
130
130
 
131
131
  secondHand = union(sweep, counter).color(secondHandHex);
@@ -133,11 +133,11 @@ if (showSecondHand > 0) {
133
133
 
134
134
  // === Center Cap ===
135
135
  const centerRadius = 6;
136
- const centerRing = cylinder(3, centerRadius + 2, undefined, undefined, true)
136
+ const centerRing = cylinder(3, centerRadius + 2)
137
137
  .translate(0, 0, handBaseZ + 13)
138
138
  .color(rimHex);
139
139
 
140
- const centerDot = cylinder(4, centerRadius, undefined, undefined, true)
140
+ const centerDot = cylinder(4, centerRadius)
141
141
  .translate(0, 0, handBaseZ + 13)
142
142
  .color(showSecondHand > 0 ? secondHandHex : "#444444");
143
143
 
@@ -145,7 +145,7 @@ const centerDot = cylinder(4, centerRadius, undefined, undefined, true)
145
145
  const mountWidth = 25;
146
146
  const mountHeight = 12;
147
147
  const mountDepth = 6;
148
- const mount = roundedRect(mountWidth, mountHeight, 3, true)
148
+ const mount = roundedRect(mountWidth, mountHeight, 3)
149
149
  .extrude(mountDepth)
150
150
  .translate(0, -radius + 8, -depth / 2 - mountDepth / 2)
151
151
  .color(rimHex);
@@ -11,8 +11,8 @@ const edgeR = param("Edge Radius", 1.5, { min: 0, max: 3, step: 0.1, unit: "mm"
11
11
  // === Body ===
12
12
  // Rounded-rect profile extruded to phone depth, then subdivision-smoothed
13
13
  // to round the 90° edges where top/bottom meet sides.
14
- const bodyProfile = roundedRect(w, h, cornerR, true);
15
- let body = bodyProfile.extrude(d, { center: true });
14
+ const bodyProfile = roundedRect(w, h, cornerR);
15
+ let body = bodyProfile.extrude(d).translate(0, 0, -d / 2);
16
16
 
17
17
  // === Screen cutout (top +Z face = phone screen side) ===
18
18
  const screenInset = param("Screen Inset", 2, { min: 1, max: 5, unit: "mm" });
@@ -21,14 +21,14 @@ const screenW = w - screenInset * 2;
21
21
  const screenH = h - screenInset * 2;
22
22
  const screenR = Math.max(cornerR - screenInset, 1);
23
23
 
24
- const screenCut = roundedRect(screenW, screenH, screenR, true)
24
+ const screenCut = roundedRect(screenW, screenH, screenR)
25
25
  .extrude(screenDepth + 1)
26
26
  .translate(0, 0, d / 2 - screenDepth);
27
27
 
28
28
  body = body.subtract(screenCut);
29
29
 
30
30
  // Dark screen surface filling the cutout
31
- const screenFill = roundedRect(screenW, screenH, screenR, true)
31
+ const screenFill = roundedRect(screenW, screenH, screenR)
32
32
  .color('#111111')
33
33
  .extrude(0.15)
34
34
  .translate(0, 0, d / 2 - screenDepth);
@@ -41,7 +41,7 @@ const camEdgeInset = 4;
41
41
  const camX = -w / 2 + camSize / 2 + camEdgeInset;
42
42
  const camY = h / 2 - camSize / 2 - camEdgeInset;
43
43
 
44
- let camIsland = roundedRect(camSize, camSize, camR, true)
44
+ let camIsland = roundedRect(camSize, camSize, camR)
45
45
  .translate(camX, camY)
46
46
  .extrude(camBump)
47
47
  .translate(0, 0, -d / 2 - camBump);
@@ -75,7 +75,7 @@ const portW = param("Port Width", 9, { min: 6, max: 14, unit: "mm" });
75
75
  const portH = 3;
76
76
  const portDepth = 4;
77
77
 
78
- const portCut = roundedRect(portW, portH, portH / 2, true)
78
+ const portCut = roundedRect(portW, portH, portH / 2)
79
79
  .extrude(portDepth)
80
80
  .pointAlong([0, 1, 0])
81
81
  .translate(0, -h / 2, 0);
@@ -111,11 +111,11 @@ const btnInset = 0.4;
111
111
  const btnThick = 1.6;
112
112
 
113
113
  const makeBtn = (bw, by, side) => {
114
- const btn = roundedRect(bw, btnThick, 0.5, true).extrude(btnInset);
114
+ const btn = roundedRect(bw, btnThick, 0.5).extrude(btnInset);
115
115
  const x = side === 'left'
116
116
  ? -w / 2 - edgeR - btnInset
117
117
  : w / 2 + edgeR + btnInset;
118
- return btn.rotateAround([0, 0, 0], 90, 0, 90).translate(x, by, 0);
118
+ return btn.rotateX(90).rotateZ(90).translate(x, by, 0);
119
119
  };
120
120
 
121
121
  const volUp = makeBtn(14, h / 2 - 35, 'left');
@@ -11,14 +11,14 @@ const kbInsetX = param("KB Inset X", 25, { min: 10, max: 50, unit: "mm" });
11
11
  const kbInsetY = param("KB Inset Y", 15, { min: 8, max: 40, unit: "mm" });
12
12
 
13
13
  // ─── Base ───
14
- const baseProfile = roundedRect(w, d, cornerR, true);
14
+ const baseProfile = roundedRect(w, d, cornerR);
15
15
  let base = baseProfile.extrude(baseH);
16
16
 
17
17
  // Keyboard recess
18
18
  const kbW = w - kbInsetX * 2;
19
19
  const kbD = d * 0.55;
20
20
  const kbDepth = 1.5;
21
- const kbRecess = roundedRect(kbW, kbD, 4, true)
21
+ const kbRecess = roundedRect(kbW, kbD, 4)
22
22
  .extrude(kbDepth + 1)
23
23
  .translate(0, d * 0.1, baseH - kbDepth);
24
24
  base = base.subtract(kbRecess);
@@ -26,7 +26,7 @@ base = base.subtract(kbRecess);
26
26
  // Trackpad recess
27
27
  const tpW = w * 0.3;
28
28
  const tpD = d * 0.22;
29
- const tpRecess = roundedRect(tpW, tpD, 3, true)
29
+ const tpRecess = roundedRect(tpW, tpD, 3)
30
30
  .extrude(kbDepth + 1)
31
31
  .translate(0, -d * 0.28, baseH - kbDepth);
32
32
  base = base.subtract(tpRecess);
@@ -45,7 +45,7 @@ const keys = [];
45
45
  for (let r = 0; r < keyRows; r++) {
46
46
  for (let c = 0; c < keyCols; c++) {
47
47
  keys.push(
48
- roundedRect(keyW, keyH, 1, true)
48
+ roundedRect(keyW, keyH, 1)
49
49
  .extrude(1)
50
50
  .translate(keyStartX + c * keyStep, keyStartY + r * keyStep, baseH - kbDepth - 0.5)
51
51
  );
@@ -54,17 +54,17 @@ for (let r = 0; r < keyRows; r++) {
54
54
  const keyboard = union(...keys);
55
55
 
56
56
  // Ports — left side
57
- const usbC1 = roundedRect(9, 3.5, 1.5, true).extrude(8)
58
- .rotateAround([0, 0, 0], 0, 0, 90)
57
+ const usbC1 = roundedRect(9, 3.5, 1.5).extrude(8)
58
+ .rotateZ(90)
59
59
  .translate(-w / 2, -d * 0.1, baseH * 0.4);
60
- const usbC2 = roundedRect(9, 3.5, 1.5, true).extrude(8)
61
- .rotateAround([0, 0, 0], 0, 0, 90)
60
+ const usbC2 = roundedRect(9, 3.5, 1.5).extrude(8)
61
+ .rotateZ(90)
62
62
  .translate(-w / 2, d * 0.05, baseH * 0.4);
63
63
  base = base.subtract(usbC1).subtract(usbC2);
64
64
 
65
65
  // Headphone jack — right side
66
66
  const hpJack = cylinder(8, 2)
67
- .rotateAround([0, 0, 0], 0, 90, 0)
67
+ .rotateY(90)
68
68
  .translate(w / 2, -d * 0.1, baseH * 0.5);
69
69
  base = base.subtract(hpJack);
70
70
 
@@ -75,7 +75,7 @@ const ventW = w * 0.4;
75
75
  const ventGap = 3;
76
76
  for (let i = 0; i < ventCount; i++) {
77
77
  ventSlots.push(
78
- roundedRect(ventW, 1.5, 0.5, true)
78
+ roundedRect(ventW, 1.5, 0.5)
79
79
  .extrude(2)
80
80
  .translate(0, -d * 0.1 + i * ventGap, -1)
81
81
  );
@@ -83,14 +83,14 @@ for (let i = 0; i < ventCount; i++) {
83
83
  base = difference(base, ...ventSlots);
84
84
 
85
85
  // ─── Lid ───
86
- const lidProfile = roundedRect(w, d, cornerR, true);
86
+ const lidProfile = roundedRect(w, d, cornerR);
87
87
  let lid = lidProfile.extrude(lidH);
88
88
 
89
89
  // Screen cutout (inset from inner face)
90
90
  const screenW = w - screenInset * 2;
91
91
  const screenD = d - screenInset * 2;
92
92
  const screenCutDepth = 1;
93
- const screenCut = roundedRect(screenW, screenD, cornerR - screenInset / 2, true)
93
+ const screenCut = roundedRect(screenW, screenD, cornerR - screenInset / 2)
94
94
  .extrude(screenCutDepth + 1)
95
95
  .translate(0, 0, -0.5);
96
96
  lid = lid.subtract(screenCut);
@@ -101,7 +101,7 @@ const cameraDot = cylinder(lidH + 2, 2)
101
101
  lid = lid.subtract(cameraDot);
102
102
 
103
103
  // Screen panel (thin slab filling the cutout)
104
- const screenPanel = roundedRect(screenW - 1, screenD - 1, cornerR - screenInset / 2 - 1, true)
104
+ const screenPanel = roundedRect(screenW - 1, screenD - 1, cornerR - screenInset / 2 - 1)
105
105
  .extrude(screenCutDepth)
106
106
  .translate(0, 0, 0);
107
107
 
@@ -112,11 +112,11 @@ const hingeZ = baseH;
112
112
 
113
113
  // Position lid at hinge point, then use joint to rotate
114
114
  const lidAtHinge = lid.translate(0, -hingeY, 0)
115
- .rotateAround([0, 0, 0], 180, 0, 0)
115
+ .rotateX(180)
116
116
  .translate(0, hingeY, hingeZ);
117
117
 
118
118
  const screenAtHinge = screenPanel.translate(0, -hingeY, 0)
119
- .rotateAround([0, 0, 0], 180, 0, 0)
119
+ .rotateX(180)
120
120
  .translate(0, hingeY, hingeZ);
121
121
 
122
122
  const lidAngle = param("Lid Angle", 110, { min: 0, max: 135, unit: "°" });
@@ -41,30 +41,30 @@ const nozzleTipX = nozzleRootX + nozzleL;
41
41
  const nozzleZ = headZ + 1;
42
42
 
43
43
  // Bottle shell + neck.
44
- const bottleOuter = cylinder(bodyH, bodyR, bodyR, undefined, true)
44
+ const bottleOuter = cylinder(bodyH, bodyR, bodyR)
45
45
  .translate(0, 0, bodyH * 0.5);
46
- const bottleInner = cylinder(bodyH - wall * 1.4, bodyR - wall, bodyR - wall, undefined, true)
46
+ const bottleInner = cylinder(bodyH - wall * 1.4, bodyR - wall, bodyR - wall)
47
47
  .translate(0, 0, wall + (bodyH - wall * 1.4) * 0.5);
48
48
  const bottleShell = bottleOuter.subtract(bottleInner);
49
49
 
50
- const neckOuter = cylinder(neckH, neckR, neckR, undefined, true).translate(0, 0, bodyH + neckH * 0.5 - 2);
51
- const neckHole = cylinder(neckH + 6, chamberR - 2.5, chamberR - 2.5, undefined, true)
50
+ const neckOuter = cylinder(neckH, neckR, neckR).translate(0, 0, bodyH + neckH * 0.5 - 2);
51
+ const neckHole = cylinder(neckH + 6, chamberR - 2.5, chamberR - 2.5)
52
52
  .translate(0, 0, bodyH + neckH * 0.5 - 2);
53
53
  const bottle = union(bottleShell, neckOuter).subtract(neckHole);
54
54
 
55
55
  // Pump chamber.
56
- const chamberOuter = cylinder(chamberH, chamberR, chamberR, undefined, true)
56
+ const chamberOuter = cylinder(chamberH, chamberR, chamberR)
57
57
  .translate(0, 0, chamberBottomZ + chamberH * 0.5);
58
- const chamberInner = cylinder(chamberH - 4, chamberInnerR, chamberInnerR, undefined, true)
58
+ const chamberInner = cylinder(chamberH - 4, chamberInnerR, chamberInnerR)
59
59
  .translate(0, 0, chamberBottomZ + chamberH * 0.5 + 1.2);
60
60
  const chamberShell = chamberOuter.subtract(chamberInner);
61
61
 
62
62
  // Pump head + nozzle.
63
- const head = box(headW, headD, headH, true).translate(0, 0, headZ);
64
- const nozzleOuter = cylinder(nozzleL, nozzleR, nozzleR * 0.92, undefined, true)
63
+ const head = box(headW, headD, headH).translate(0, 0, headZ);
64
+ const nozzleOuter = cylinder(nozzleL, nozzleR, nozzleR * 0.92)
65
65
  .pointAlong([1, 0, 0])
66
66
  .translate(nozzleCenterX, 0, nozzleZ);
67
- const nozzleInner = cylinder(nozzleL + 2, 1.5, 1.35, undefined, true)
67
+ const nozzleInner = cylinder(nozzleL + 2, 1.5, 1.35)
68
68
  .pointAlong([1, 0, 0])
69
69
  .translate(nozzleCenterX, 0, nozzleZ);
70
70
  const nozzle = nozzleOuter.subtract(nozzleInner);
@@ -72,12 +72,12 @@ const nozzle = nozzleOuter.subtract(nozzleInner);
72
72
  // Stem + piston (moves with the head).
73
73
  const pistonH = 7;
74
74
  const pistonZ = chamberTopZ - 8 - press * pumpStroke * 0.9;
75
- const piston = cylinder(pistonH, chamberR - 3.1, chamberR - 3.1, undefined, true).translate(0, 0, pistonZ);
75
+ const piston = cylinder(pistonH, chamberR - 3.1, chamberR - 3.1).translate(0, 0, pistonZ);
76
76
 
77
77
  const stemTopZ = headZ - headH * 0.5;
78
78
  const stemBottomZ = pistonZ + pistonH * 0.5;
79
79
  const stemLen = Math.max(8, stemTopZ - stemBottomZ);
80
- const stem = cylinder(stemLen, 2.2, 2.2, undefined, true).translate(0, 0, (stemTopZ + stemBottomZ) * 0.5);
80
+ const stem = cylinder(stemLen, 2.2, 2.2).translate(0, 0, (stemTopZ + stemBottomZ) * 0.5);
81
81
 
82
82
  // Return spring shown as compressed ring stack.
83
83
  const springBottomZ = chamberBottomZ + 8;
@@ -88,8 +88,8 @@ const springRings = [];
88
88
  for (let i = 0; i < springTurns; i++) {
89
89
  const t = i / Math.max(1, springTurns - 1);
90
90
  const z = springBottomZ + t * springSpan;
91
- const ringOuter = cylinder(1.2, chamberR - 4.2, chamberR - 4.2, undefined, true).translate(0, 0, z);
92
- const ringInner = cylinder(2.4, chamberR - 5.3, chamberR - 5.3, undefined, true).translate(0, 0, z);
91
+ const ringOuter = cylinder(1.2, chamberR - 4.2, chamberR - 4.2).translate(0, 0, z);
92
+ const ringInner = cylinder(2.4, chamberR - 5.3, chamberR - 5.3).translate(0, 0, z);
93
93
  springRings.push(ringOuter.subtract(ringInner));
94
94
  }
95
95
  const spring = union(...springRings);
@@ -98,8 +98,8 @@ const spring = union(...springRings);
98
98
  const tubeBottomZ = 8;
99
99
  const tubeTopZ = chamberBottomZ + 6;
100
100
  const tubeLen = tubeTopZ - tubeBottomZ;
101
- const tubeOuter = cylinder(tubeLen, 2.5, 2.5, undefined, true).translate(0, 0, (tubeBottomZ + tubeTopZ) * 0.5);
102
- const tubeInner = cylinder(tubeLen + 2, 1.2, 1.2, undefined, true).translate(0, 0, (tubeBottomZ + tubeTopZ) * 0.5);
101
+ const tubeOuter = cylinder(tubeLen, 2.5, 2.5).translate(0, 0, (tubeBottomZ + tubeTopZ) * 0.5);
102
+ const tubeInner = cylinder(tubeLen + 2, 1.2, 1.2).translate(0, 0, (tubeBottomZ + tubeTopZ) * 0.5);
103
103
  const dipTube = tubeOuter.subtract(tubeInner);
104
104
 
105
105
  // Check valves: inlet opens during release, outlet opens during press.
@@ -120,18 +120,18 @@ const reservoir = cylinder(reservoirLevel, bodyR - wall - 1, bodyR - wall - 1)
120
120
  .translate(0, 0, 4 + reservoirLevel * 0.5);
121
121
 
122
122
  const tubeSlugH = 6 + drawPhase * (tubeLen - 10);
123
- const tubeLiquid = cylinder(tubeSlugH, 1.1, 1.1, undefined, true)
123
+ const tubeLiquid = cylinder(tubeSlugH, 1.1, 1.1)
124
124
  .translate(0, 0, tubeBottomZ + tubeSlugH * 0.5);
125
125
 
126
126
  const chamberLiquidH = Math.max(2, 9 + drawPhase * 17 - pushPhase * 16);
127
- const chamberLiquid = cylinder(chamberLiquidH, chamberR - 4.8, chamberR - 4.8, undefined, true)
127
+ const chamberLiquid = cylinder(chamberLiquidH, chamberR - 4.8, chamberR - 4.8)
128
128
  .translate(0, 0, chamberBottomZ + 4 + chamberLiquidH * 0.5);
129
129
 
130
130
  const flowIn = clamp01((progress - 0.45) / 0.2);
131
131
  const flowOut = 1 - clamp01((progress - 0.8) / 0.15);
132
132
  const nozzleFlow = clamp01(flowIn * flowOut);
133
133
  const nozzleLiquidLen = Math.max(1, 1 + nozzleFlow * (nozzleL - 3));
134
- const nozzleLiquid = cylinder(nozzleLiquidLen, 1.05, 0.95, undefined, true)
134
+ const nozzleLiquid = cylinder(nozzleLiquidLen, 1.05, 0.95)
135
135
  .pointAlong([1, 0, 0])
136
136
  .translate(nozzleRootX + nozzleLiquidLen * 0.5, 0, nozzleZ);
137
137
 
@@ -16,23 +16,25 @@ const S = (v) => v * scale;
16
16
  const toPts = (pts) => pts.map(([x, y]) => [S(x), S(y)]);
17
17
 
18
18
  function pose(shape) {
19
- return shape.rotateAround([0, 0, 0], 14, -8, 20).translate(S(6), S(0), S(36));
19
+ return shape.rotateX(14).rotateY(-8).rotateZ(20).translate(S(6), S(0), S(36));
20
20
  }
21
21
 
22
22
  function panel(name, pts, color, rotate = [0, 0, 0], translate = [0, 0, 0]) {
23
23
  const shape = polygon(toPts(pts))
24
- .extrude(paper, { center: true })
24
+ .extrude(paper)
25
+ .translate(0, 0, -paper / 2)
25
26
  .color(color)
26
- .rotateAround([0, 0, 0], rotate[0], rotate[1], rotate[2])
27
+ .rotateX(rotate[0]).rotateY(rotate[1]).rotateZ(rotate[2])
27
28
  .translate(S(translate[0]), S(translate[1]), S(translate[2]));
28
29
  return { name, shape: pose(shape) };
29
30
  }
30
31
 
31
32
  function ridge(name, pts, width, color, rotate = [0, 0, 0], translate = [0, 0, 0]) {
32
33
  const shape = stroke(toPts(pts), S(width), "Round")
33
- .extrude(paper * 0.9, { center: true })
34
+ .extrude(paper * 0.9)
35
+ .translate(0, 0, -paper * 0.45)
34
36
  .color(color)
35
- .rotateAround([0, 0, 0], rotate[0], rotate[1], rotate[2])
37
+ .rotateX(rotate[0]).rotateY(rotate[1]).rotateZ(rotate[2])
36
38
  .translate(S(translate[0]), S(translate[1]), S(translate[2]));
37
39
  return { name, shape: pose(shape) };
38
40
  }
@@ -130,7 +132,7 @@ if (showStand === 1) {
130
132
  .color("#6f6f77")
131
133
  .translate(S(0), S(-4), S(-52));
132
134
 
133
- const clip = cylinder(S(7), S(2.6), S(1.2), 28, true)
135
+ const clip = cylinder(S(7), S(2.6), S(1.2), 28)
134
136
  .pointAlong([0, 1, 0])
135
137
  .color("#56565d")
136
138
  .translate(S(1), S(-4), S(34));
@@ -45,12 +45,12 @@ const eyeW = topRadius * 0.4;
45
45
  const eyeH = tierHeight * 0.6;
46
46
  const eyeT = 2;
47
47
 
48
- const leftEye = box(eyeW, eyeT, eyeH, true).color(spideyWhite)
49
- .rotateAround([0, 0, 0], 0, 0, 20)
48
+ const leftEye = box(eyeW, eyeT, eyeH).color(spideyWhite)
49
+ .rotateZ(20)
50
50
  .onFace(topTier, 'front', { u: -topRadius * 0.35, v: 0, protrude: 1 });
51
51
 
52
- const rightEye = box(eyeW, eyeT, eyeH, true).color(spideyWhite)
53
- .rotateAround([0, 0, 0], 0, 0, -20)
52
+ const rightEye = box(eyeW, eyeT, eyeH).color(spideyWhite)
53
+ .rotateZ(-20)
54
54
  .onFace(topTier, 'front', { u: topRadius * 0.35, v: 0, protrude: 1 });
55
55
 
56
56
  cake.push({ name: "Top Tier", shape: topTier });
@@ -32,7 +32,7 @@ const hw = lib.fastenerSet("M5", grip + 4);
32
32
  const { dims } = hw;
33
33
 
34
34
  // --- Top plate: clearance holes (normal fit) ---
35
- let topPlate = box(plateW, plateD, topThick, true);
35
+ let topPlate = box(plateW, plateD, topThick);
36
36
  for (const [x, y] of boltPositions) {
37
37
  topPlate = topPlate.subtract(
38
38
  hw.clearanceHole.translate(x, y, 0),
@@ -47,7 +47,7 @@ const botCenter = -(topThick / 2 + botThick / 2);
47
47
  const botFace = botCenter - botThick / 2; // bottom face of bottom plate
48
48
 
49
49
  // --- Bottom plate: tapped holes ---
50
- let botPlate = box(plateW, plateD, botThick, true).translate(0, 0, botCenter);
50
+ let botPlate = box(plateW, plateD, botThick).translate(0, 0, botCenter);
51
51
  for (const [x, y] of boltPositions) {
52
52
  botPlate = botPlate.subtract(
53
53
  hw.tappedHole.translate(x, y, botCenter),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgecad",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "Code-first parametric CAD for JavaScript/TypeScript, in the browser and CLI.",
5
5
  "license": "BUSL-1.1",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  "forgecad": "./dist-cli/forgecad.js"
9
9
  },
10
10
  "files": [
11
- "dist-cli/forgecad.js",
11
+ "dist-cli",
12
12
  "dist",
13
13
  "dist-skill",
14
14
  "examples",
@@ -38,14 +38,16 @@
38
38
  "build:hosted": "npm run build:solver && npm run build:skill:forgecad && tsc && npm run build:sitemap && FORGE_HOSTED=true vite build",
39
39
  "dev:cli": "tsup cli/forgecad.ts --format esm --platform node --target node20 --out-dir dist-cli --sourcemap --external typescript",
40
40
  "build:cli": "tsup cli/forgecad.ts --format esm --platform node --target node20 --out-dir dist-cli --clean --sourcemap --external typescript",
41
+ "build:backend": "tsup apps/backend/src/server.ts --format esm --platform node --target node20 --out-dir dist-backend --clean --sourcemap",
41
42
  "build:binary": "node scripts/build-binary.mjs",
42
43
  "build:binary:all": "node scripts/build-binary.mjs --all",
43
44
  "lint": "npx biome check .",
44
45
  "lint:fix": "npx biome check . --write",
45
46
  "format": "npx biome format . --write",
46
- "test": "npm run test:prepare && npm run test:unit && node dist-cli/forgecad.js check suite",
47
+ "test": "npm run test:prepare && node dist-cli/forgecad.js check suite --profile local",
48
+ "test:full": "npm run test:prepare && node dist-cli/forgecad.js check suite",
47
49
  "test:unit": "vitest run",
48
- "test:prepare": "tsc --noEmit && npm run build:cli",
50
+ "test:prepare": "npm run build:solver:if-missing && tsc --noEmit && npm run build:cli",
49
51
  "test:compiler": "npm run test:prepare && node dist-cli/forgecad.js check compiler",
50
52
  "test:compiler:update": "npm run test:prepare && node dist-cli/forgecad.js check compiler --update",
51
53
  "test:query-propagation": "npm run test:prepare && node dist-cli/forgecad.js check query-propagation",
@@ -95,6 +97,7 @@
95
97
  "puppeteer-core": "^24.37.2",
96
98
  "react-router-dom": "^7.13.2",
97
99
  "resend": "^6.9.4",
100
+ "stripe": "^21.0.1",
98
101
  "typescript": "^5.8.3",
99
102
  "zod": "^4.3.6"
100
103
  },