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.
- package/README.md +2 -11
- package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-DAu1C1ST.js} +250 -151
- package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
- package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-Gc_BCdqC.js} +269 -143
- package/dist/assets/EditorApp-D9bJvtf7.js +11338 -0
- package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-DG1-oUSV.css} +459 -87
- package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-CEO8XbV8.js} +2 -4
- package/dist/assets/LandingPage-CdCuEOdC.js +451 -0
- package/dist/assets/PricingPage-BSrxu6d7.js +232 -0
- package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-FUCSIRq6.js} +129 -5
- package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-KoR0SNKq.js} +6770 -2914
- package/dist/assets/{index-2hfs_ub0.css → index-CyVd1D4D.css} +227 -53
- package/dist/assets/{Viewport-CoB46f5R.js → index-wTEK39at.js} +31385 -6439
- package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
- package/dist/assets/{manifold-CqNMHHKO.js → manifold-B1sGWdYk.js} +4 -3
- package/dist/assets/{manifold-Cce9wRFz.js → manifold-D7o0N50J.js} +1 -1
- package/dist/assets/{manifold-D6BeHIOo.js → manifold-G5sBaXzi.js} +1 -1
- package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-DYcRHhv9.js} +6798 -3341
- package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
- package/dist/docs-raw/generated/assembly.md +691 -112
- package/dist/docs-raw/generated/concepts.md +1225 -1400
- package/dist/docs-raw/generated/core.md +464 -1412
- package/dist/docs-raw/generated/curves.md +593 -117
- package/dist/docs-raw/generated/lib.md +38 -748
- package/dist/docs-raw/generated/output.md +139 -245
- package/dist/docs-raw/generated/sheet-metal.md +473 -21
- package/dist/docs-raw/generated/sketch.md +553 -349
- package/dist/docs-raw/generated/viewport.md +345 -303
- package/dist/docs-raw/generated/wood.md +104 -0
- package/dist/index.html +2 -2
- package/dist/sitemap.xml +6 -6
- package/dist-cli/chunk-PZ5AY32C.js +10 -0
- package/dist-cli/chunk-PZ5AY32C.js.map +1 -0
- package/dist-cli/forgecad.js +9435 -5407
- package/dist-cli/forgecad.js.map +1 -0
- package/dist-cli/solver-FV7TJZGI.js +365 -0
- package/dist-cli/solver-FV7TJZGI.js.map +1 -0
- package/dist-skill/CONTEXT.md +3186 -7145
- package/dist-skill/SKILL-dev.md +21 -63
- package/dist-skill/SKILL.md +12 -56
- package/dist-skill/docs/API/core/concepts.md +16 -98
- package/dist-skill/docs/CLI/export.md +91 -0
- package/dist-skill/docs/CLI/projects.md +107 -0
- package/dist-skill/docs/CLI/studio_publishing.md +52 -0
- package/dist-skill/docs/CLI/validation.md +66 -0
- package/dist-skill/docs/generated/assembly.md +691 -112
- package/dist-skill/docs/generated/core.md +464 -1412
- package/dist-skill/docs/generated/curves.md +593 -117
- package/dist-skill/docs/generated/lib.md +38 -748
- package/dist-skill/docs/generated/output.md +139 -245
- package/dist-skill/docs/generated/sheet-metal.md +473 -21
- package/dist-skill/docs/generated/sketch.md +553 -349
- package/dist-skill/docs/generated/viewport.md +345 -303
- package/dist-skill/docs/generated/wood.md +104 -0
- package/dist-skill/docs/guides/coordinate-system.md +11 -17
- package/dist-skill/docs/guides/geometry-conventions.md +13 -70
- package/dist-skill/docs/guides/modeling-recipes.md +22 -195
- package/dist-skill/docs/guides/positioning.md +88 -147
- package/dist-skill/docs-dev/API/core/concepts.md +51 -0
- package/dist-skill/docs-dev/API/core/sdf-advanced.md +92 -0
- package/dist-skill/docs-dev/API/core/sdf-primitives.md +58 -0
- package/dist-skill/docs-dev/API/core/sdf-workflow.md +42 -0
- package/dist-skill/docs-dev/CLI/export.md +91 -0
- package/dist-skill/docs-dev/CLI/projects.md +107 -0
- package/dist-skill/docs-dev/CLI/studio_publishing.md +52 -0
- package/dist-skill/docs-dev/CLI/validation.md +66 -0
- package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
- package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
- package/dist-skill/{docs → docs-dev}/coding.md +1 -3
- package/dist-skill/docs-dev/generated/assembly.md +771 -0
- package/dist-skill/docs-dev/generated/core.md +775 -0
- package/dist-skill/docs-dev/generated/curves.md +688 -0
- package/dist-skill/docs-dev/generated/lib.md +50 -0
- package/dist-skill/docs-dev/generated/output.md +234 -0
- package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
- package/dist-skill/docs-dev/generated/sketch.md +801 -0
- package/dist-skill/docs-dev/generated/viewport.md +486 -0
- package/dist-skill/docs-dev/generated/wood.md +104 -0
- package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
- package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
- package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
- package/dist-skill/docs-dev/guides/positioning.md +151 -0
- package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
- package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
- package/examples/api/attachTo-basics.forge.js +5 -5
- package/examples/api/boolean-operations.forge.js +3 -3
- package/examples/api/bounding-box-visualizer.forge.js +2 -2
- package/examples/api/clone-duplicate.forge.js +1 -1
- package/examples/api/colors-union-vs-array.forge.js +6 -6
- package/examples/api/connector-assembly.forge.js +4 -4
- package/examples/api/connector-basics.forge.js +2 -2
- package/examples/api/extrude-options.forge.js +4 -10
- package/examples/api/feature-created-faces.forge.js +6 -10
- package/examples/api/fillet-showcase.forge.js +1 -1
- package/examples/api/folded-service-panel-cover.forge.js +2 -2
- package/examples/api/group-test.forge.js +1 -1
- package/examples/api/group-vs-union.forge.js +1 -1
- package/examples/api/highlight-debug.forge.js +4 -0
- package/examples/api/js-module-pillars.js +1 -1
- package/examples/api/js-module-scene.js +2 -2
- package/examples/api/mesh-import-slats.forge.js +1 -1
- package/examples/api/pointAlong-orientation.forge.js +1 -1
- package/examples/api/profile-2020-b-slot6.forge.js +0 -1
- package/examples/api/route-perimeter-flange.forge.js +1 -1
- package/examples/api/sdf-rover-demo.forge.js +10 -10
- package/examples/api/sketch-on-face-demo.forge.js +2 -2
- package/examples/api/sketch-regions.forge.js +4 -4
- package/examples/api/transition-curves.forge.js +1 -1
- package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
- package/examples/api/variable-sweep-test.forge.js +2 -2
- package/examples/api/wood-joinery.forge.js +60 -0
- package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
- package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
- package/examples/experiments/drone-arm.forge.js +53 -0
- package/examples/furniture/adjustable-table.forge.js +2 -2
- package/examples/furniture/bathroom.forge.js +11 -11
- package/examples/furniture/chair.forge.js +1 -1
- package/examples/generative/crystal-growth.forge.js +2 -2
- package/examples/generative/frost-spires.forge.js +3 -3
- package/examples/generative/golden-spiral-tower.forge.js +3 -3
- package/examples/mechanical/3d-printer.forge.js +28 -28
- package/examples/mechanical/5-finger-robot-hand.forge.js +15 -15
- package/examples/mechanical/airplane-propeller.forge.js +2 -2
- package/examples/mechanical/fillet-enclosure.forge.js +1 -1
- package/examples/mechanical/headphone-hanger-v2.forge.js +2 -2
- package/examples/mechanical/robot_hand.forge.js +15 -15
- package/examples/mechanical/robot_hand_2.forge.js +9 -9
- package/examples/products/bottle.forge.js +1 -1
- package/examples/products/chess-set.forge.js +19 -19
- package/examples/products/classical-piano.forge.js +11 -11
- package/examples/products/clock.forge.js +12 -12
- package/examples/products/iphone.forge.js +8 -8
- package/examples/products/laptop.forge.js +15 -15
- package/examples/products/liquid-soap-dispenser.forge.js +18 -18
- package/examples/products/origami-fish.forge.js +8 -6
- package/examples/products/spiderman-cake.forge.js +4 -4
- package/examples/toolbox/bolted-joint.forge.js +2 -2
- package/package.json +7 -4
- package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
- package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
- package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
- package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
- package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
- package/dist/assets/index-1CYp3zUp.js +0 -1455
- package/dist/docs-raw/CLI.md +0 -865
- package/dist-skill/docs/API/API.md +0 -1666
- package/dist-skill/docs/API/README.md +0 -37
- package/dist-skill/docs/API/assembly/assembly.md +0 -617
- package/dist-skill/docs/API/core/edge-queries.md +0 -130
- package/dist-skill/docs/API/core/parameters.md +0 -122
- package/dist-skill/docs/API/core/reserved-terms.md +0 -137
- package/dist-skill/docs/API/core/sdf.md +0 -326
- package/dist-skill/docs/API/core/skill-cli.md +0 -194
- package/dist-skill/docs/API/core/skill-guide.md +0 -205
- package/dist-skill/docs/API/core/specs.md +0 -186
- package/dist-skill/docs/API/core/topology.md +0 -372
- package/dist-skill/docs/API/entities.md +0 -268
- package/dist-skill/docs/API/output/bom.md +0 -58
- package/dist-skill/docs/API/output/brep-export.md +0 -87
- package/dist-skill/docs/API/output/dimensions.md +0 -67
- package/dist-skill/docs/API/output/export.md +0 -110
- package/dist-skill/docs/API/output/gcode.md +0 -195
- package/dist-skill/docs/API/runtime/viewport.md +0 -420
- package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
- package/dist-skill/docs/API/sketch/anchor.md +0 -37
- package/dist-skill/docs/API/sketch/booleans.md +0 -91
- package/dist-skill/docs/API/sketch/core.md +0 -73
- package/dist-skill/docs/API/sketch/extrude.md +0 -62
- package/dist-skill/docs/API/sketch/on-face.md +0 -104
- package/dist-skill/docs/API/sketch/operations.md +0 -78
- package/dist-skill/docs/API/sketch/path.md +0 -75
- package/dist-skill/docs/API/sketch/primitives.md +0 -146
- package/dist-skill/docs/API/sketch/regions.md +0 -80
- package/dist-skill/docs/API/sketch/text.md +0 -108
- package/dist-skill/docs/API/sketch/transforms.md +0 -65
- package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
- package/dist-skill/docs/CLI.md +0 -865
- package/dist-skill/docs/INDEX.md +0 -94
- package/dist-skill/docs/RELEASING.md +0 -55
- package/dist-skill/docs/cli-monetization.md +0 -111
- package/dist-skill/docs/deployment.md +0 -281
- package/dist-skill/docs/generated/concepts.md +0 -2112
- package/dist-skill/docs/internals/shape-from-slices.md +0 -152
- package/dist-skill/docs/platform/admin.md +0 -45
- package/dist-skill/docs/platform/architecture.md +0 -79
- package/dist-skill/docs/platform/auth.md +0 -110
- package/dist-skill/docs/platform/email.md +0 -67
- package/dist-skill/docs/platform/projects.md +0 -111
- package/dist-skill/docs/platform/sharing.md +0 -90
- package/dist-skill/docs/runbook.md +0 -345
|
@@ -62,13 +62,13 @@ const hd = frameD / 2 - beam / 2;
|
|
|
62
62
|
|
|
63
63
|
for (const z of [bz, tz]) {
|
|
64
64
|
for (const sy of [-1, 1])
|
|
65
|
-
fp.push(box(frameW, beam, beam
|
|
65
|
+
fp.push(box(frameW, beam, beam).translate(0, sy * hd, z));
|
|
66
66
|
for (const sx of [-1, 1])
|
|
67
|
-
fp.push(box(beam, frameD - 2 * beam, beam
|
|
67
|
+
fp.push(box(beam, frameD - 2 * beam, beam).translate(sx * hw, 0, z));
|
|
68
68
|
}
|
|
69
69
|
for (const sx of [-1, 1])
|
|
70
70
|
for (const sy of [-1, 1])
|
|
71
|
-
fp.push(box(beam, beam, pH
|
|
71
|
+
fp.push(box(beam, beam, pH).translate(sx * hw, sy * hd, pZ));
|
|
72
72
|
|
|
73
73
|
add("Frame", union(...fp), C.frame);
|
|
74
74
|
|
|
@@ -93,8 +93,8 @@ add("Lead Screws", union(
|
|
|
93
93
|
), C.lead);
|
|
94
94
|
|
|
95
95
|
add("Z Motors", union(
|
|
96
|
-
box(42, 42, 40
|
|
97
|
-
box(42, 42, 40
|
|
96
|
+
box(42, 42, 40).translate(-zRailX, leadY, beam + 20),
|
|
97
|
+
box(42, 42, 40).translate(zRailX, leadY, beam + 20),
|
|
98
98
|
), C.motor);
|
|
99
99
|
|
|
100
100
|
// ─── Bed Assembly (moves in Z) ───
|
|
@@ -103,8 +103,8 @@ const glassTopZ = bedZ;
|
|
|
103
103
|
const bedPlateTopZ = glassTopZ - glassThick;
|
|
104
104
|
const bedPlateCenterZ = bedPlateTopZ - bedThick / 2;
|
|
105
105
|
|
|
106
|
-
const bedPlate = box(bedW, bedD, bedThick
|
|
107
|
-
const glass = box(bedW - 6, bedD - 6, glassThick
|
|
106
|
+
const bedPlate = box(bedW, bedD, bedThick).translate(0, 0, bedPlateCenterZ);
|
|
107
|
+
const glass = box(bedW - 6, bedD - 6, glassThick)
|
|
108
108
|
.translate(0, 0, bedPlateTopZ + glassThick / 2);
|
|
109
109
|
|
|
110
110
|
const carriageThick = 8;
|
|
@@ -112,12 +112,12 @@ const springH = 12;
|
|
|
112
112
|
const carriageZ = bedPlateCenterZ - bedThick / 2 - springH - carriageThick / 2;
|
|
113
113
|
|
|
114
114
|
// Carriage narrower in Y so it doesn't extend past the Z rail Y position
|
|
115
|
-
const bedCarriage = box(bedW + 20, bedD - 40, carriageThick
|
|
115
|
+
const bedCarriage = box(bedW + 20, bedD - 40, carriageThick)
|
|
116
116
|
.translate(0, 0, carriageZ);
|
|
117
117
|
|
|
118
118
|
add("Z Bearings", union(
|
|
119
|
-
box(24, 24, 16
|
|
120
|
-
box(24, 24, 16
|
|
119
|
+
box(24, 24, 16).translate(-zRailX, zRailY, carriageZ),
|
|
120
|
+
box(24, 24, 16).translate(zRailX, zRailY, carriageZ),
|
|
121
121
|
), C.carriage);
|
|
122
122
|
|
|
123
123
|
add("Lead Nuts", union(
|
|
@@ -148,8 +148,8 @@ add("Y Rails", union(
|
|
|
148
148
|
), C.rail);
|
|
149
149
|
|
|
150
150
|
add("Y Carriages", union(
|
|
151
|
-
box(28, 32, 18
|
|
152
|
-
box(28, 32, 18
|
|
151
|
+
box(28, 32, 18).translate(-yRailX, gantryY, gantryZ),
|
|
152
|
+
box(28, 32, 18).translate(yRailX, gantryY, gantryZ),
|
|
153
153
|
), C.carriage);
|
|
154
154
|
|
|
155
155
|
const xRailLen = yRailX * 2 - 30;
|
|
@@ -157,24 +157,24 @@ add("X Rail", cylinder(xRailLen, railR).pointAlong([1, 0, 0])
|
|
|
157
157
|
.translate(-xRailLen / 2, gantryY, gantryZ), C.rail);
|
|
158
158
|
|
|
159
159
|
// X beam at gantry level — supports the X rail from behind
|
|
160
|
-
add("X Beam", box(xRailLen, beam, beam
|
|
160
|
+
add("X Beam", box(xRailLen, beam, beam)
|
|
161
161
|
.translate(0, gantryY, gantryZ), C.frame);
|
|
162
162
|
|
|
163
163
|
// ─── CoreXY Belts ───
|
|
164
164
|
const beltZ = gantryZ + 22;
|
|
165
165
|
add("XY Belts", union(
|
|
166
|
-
box(xRailLen, 2, 3
|
|
167
|
-
box(xRailLen, 2, 3
|
|
168
|
-
box(2, yRailLen, 3
|
|
169
|
-
box(2, yRailLen, 3
|
|
166
|
+
box(xRailLen, 2, 3).translate(0, gantryY + 8, beltZ),
|
|
167
|
+
box(xRailLen, 2, 3).translate(0, gantryY - 8, beltZ),
|
|
168
|
+
box(2, yRailLen, 3).translate(-yRailX, 0, beltZ),
|
|
169
|
+
box(2, yRailLen, 3).translate(yRailX, 0, beltZ),
|
|
170
170
|
), C.belt);
|
|
171
171
|
|
|
172
172
|
// XY motors inside frame at top-rear
|
|
173
173
|
const motorSize = 42;
|
|
174
174
|
const motorY = innerD / 2 - motorSize / 2 - 5;
|
|
175
175
|
add("XY Motors", union(
|
|
176
|
-
box(motorSize, motorSize, motorSize
|
|
177
|
-
box(motorSize, motorSize, motorSize
|
|
176
|
+
box(motorSize, motorSize, motorSize).translate(-yRailX, motorY, gantryZ + 30),
|
|
177
|
+
box(motorSize, motorSize, motorSize).translate(yRailX, motorY, gantryZ + 30),
|
|
178
178
|
), C.motor);
|
|
179
179
|
|
|
180
180
|
add("XY Idlers", union(
|
|
@@ -189,19 +189,19 @@ const hx = headX;
|
|
|
189
189
|
const hy = gantryY;
|
|
190
190
|
|
|
191
191
|
add("Nozzle", cylinder(6, 0.4, 2).translate(hx, hy, nozzleZ), C.nozzle);
|
|
192
|
-
add("Heater Block", box(12, 12, 8
|
|
192
|
+
add("Heater Block", box(12, 12, 8).translate(hx, hy, nozzleZ + 10), C.hotend);
|
|
193
193
|
add("Heatbreak", cylinder(6, 1.5).translate(hx, hy, nozzleZ + 14), C.lead);
|
|
194
194
|
add("Heatsink", cylinder(12, 6).translate(hx, hy, nozzleZ + 22), C.hotend);
|
|
195
195
|
|
|
196
|
-
const headCarriage = box(46, 28, 36
|
|
196
|
+
const headCarriage = box(46, 28, 36).translate(hx, hy, gantryZ - 18);
|
|
197
197
|
add("Extruder Carriage", headCarriage, C.carriage);
|
|
198
198
|
|
|
199
|
-
add("Part Fan", box(18, 8, 16
|
|
199
|
+
add("Part Fan", box(18, 8, 16)
|
|
200
200
|
.onFace(headCarriage, 'front', { v: -5, protrude: 5 }), C.fan);
|
|
201
201
|
|
|
202
202
|
// Extruder motor — compact, sits just above gantry plane
|
|
203
203
|
const extruderMotorZ = gantryZ + 5;
|
|
204
|
-
add("Extruder Motor", box(30, 30, 20
|
|
204
|
+
add("Extruder Motor", box(30, 30, 20)
|
|
205
205
|
.translate(hx, hy, extruderMotorZ), C.motor);
|
|
206
206
|
|
|
207
207
|
// ─── Spool Holder (behind frame, on top) ───
|
|
@@ -225,8 +225,8 @@ add("Spool Hub", cylinder(spoolW, 8).pointAlong([1, 0, 0])
|
|
|
225
225
|
.translate(-spoolW / 2, spoolY, spoolZ), C.lead);
|
|
226
226
|
|
|
227
227
|
add("Spool Supports", union(
|
|
228
|
-
box(10, 20, 50
|
|
229
|
-
box(10, 20, 50
|
|
228
|
+
box(10, 20, 50).translate(-spoolW / 2 - 15, frameD / 2 - beam / 2, frameH - 25),
|
|
229
|
+
box(10, 20, 50).translate(spoolW / 2 + 15, frameD / 2 - beam / 2, frameH - 25),
|
|
230
230
|
), C.frame);
|
|
231
231
|
|
|
232
232
|
// ─── Filament Path ───
|
|
@@ -248,13 +248,13 @@ const filFixedPath = lib.pipeRoute(
|
|
|
248
248
|
add("Filament Guide Tube", filFixedPath, C.bowden);
|
|
249
249
|
|
|
250
250
|
// ─── Electronics ───
|
|
251
|
-
add("PSU", box(100, 60, 40
|
|
251
|
+
add("PSU", box(100, 60, 40)
|
|
252
252
|
.translate(frameW / 2 - 55, -frameD / 2 + 35, 25), C.electronics);
|
|
253
253
|
|
|
254
|
-
add("Control Board", box(70, 40, 25
|
|
254
|
+
add("Control Board", box(70, 40, 25)
|
|
255
255
|
.translate(-frameW / 2 + 40, -frameD / 2 + 25, 18), C.electronics);
|
|
256
256
|
|
|
257
|
-
add("Display", box(50, 3, 25
|
|
257
|
+
add("Display", box(50, 3, 25)
|
|
258
258
|
.translate(-frameW / 2 + 40, -frameD / 2 + 1, frameH / 3), C.screen);
|
|
259
259
|
|
|
260
260
|
// ─── Build Volume wireframe ───
|
|
@@ -76,37 +76,37 @@ function makeFinger(opts) {
|
|
|
76
76
|
const tipPivot0 = [basePivot[0], basePivot[1] - L1 - L2, basePivot[2]];
|
|
77
77
|
|
|
78
78
|
// Straight segments in world space
|
|
79
|
-
let s1 = box(W1, L1, t
|
|
79
|
+
let s1 = box(W1, L1, t)
|
|
80
80
|
.translate(basePivot[0], basePivot[1] - L1 / 2, basePivot[2])
|
|
81
81
|
.color(colors.segment);
|
|
82
|
-
let s2 = box(W2, L2, t
|
|
82
|
+
let s2 = box(W2, L2, t)
|
|
83
83
|
.translate(basePivot[0], basePivot[1] - L1 - L2 / 2, basePivot[2])
|
|
84
84
|
.color(colors.segment);
|
|
85
|
-
let s3 = box(W3, L3, t
|
|
85
|
+
let s3 = box(W3, L3, t)
|
|
86
86
|
.translate(basePivot[0], basePivot[1] - L1 - L2 - L3 / 2, basePivot[2])
|
|
87
87
|
.color(colors.segment);
|
|
88
88
|
|
|
89
89
|
// Pads (rubber contact)
|
|
90
90
|
const padT = t * 0.18;
|
|
91
|
-
let pad1 = box(W1 * 0.7, L1 * 0.45, padT
|
|
91
|
+
let pad1 = box(W1 * 0.7, L1 * 0.45, padT)
|
|
92
92
|
.color(colors.pad)
|
|
93
93
|
.onFace(s1, 'bottom', { v: -L1 * 0.15, protrude: padT / 2 });
|
|
94
|
-
let pad2 = box(W2 * 0.65, L2 * 0.45, padT
|
|
94
|
+
let pad2 = box(W2 * 0.65, L2 * 0.45, padT)
|
|
95
95
|
.color(colors.pad)
|
|
96
96
|
.onFace(s2, 'bottom', { v: -L2 * 0.15, protrude: padT / 2 });
|
|
97
|
-
let pad3 = box(W3 * 0.8, L3 * 0.6, padT
|
|
97
|
+
let pad3 = box(W3 * 0.8, L3 * 0.6, padT)
|
|
98
98
|
.color(colors.pad)
|
|
99
99
|
.onFace(s3, 'bottom', { v: -L3 * 0.1, protrude: padT / 2 });
|
|
100
100
|
|
|
101
101
|
// Tendon guides (raised top rails)
|
|
102
102
|
const rodT = t * 0.12;
|
|
103
|
-
let rod1 = box(W1 * 0.2, L1 * 0.9, rodT
|
|
103
|
+
let rod1 = box(W1 * 0.2, L1 * 0.9, rodT)
|
|
104
104
|
.color(colors.tendon)
|
|
105
105
|
.onFace(s1, 'top', { v: -L1 * 0.05, protrude: rodT / 2 });
|
|
106
|
-
let rod2 = box(W2 * 0.2, L2 * 0.9, rodT
|
|
106
|
+
let rod2 = box(W2 * 0.2, L2 * 0.9, rodT)
|
|
107
107
|
.color(colors.tendon)
|
|
108
108
|
.onFace(s2, 'top', { v: -L2 * 0.05, protrude: rodT / 2 });
|
|
109
|
-
let rod3 = box(W3 * 0.2, L3 * 0.85, rodT
|
|
109
|
+
let rod3 = box(W3 * 0.2, L3 * 0.85, rodT)
|
|
110
110
|
.color(colors.tendon)
|
|
111
111
|
.onFace(s3, 'top', { v: -L3 * 0.05, protrude: rodT / 2 });
|
|
112
112
|
|
|
@@ -137,7 +137,7 @@ function makeFinger(opts) {
|
|
|
137
137
|
let pin3 = pinBase.translate(tipPivot2[0] - pinLen / 2, tipPivot2[1], tipPivot2[2]);
|
|
138
138
|
|
|
139
139
|
// Yoke block at base
|
|
140
|
-
let yoke = box(W1 * 1.1, 6 * scale, t * 0.8
|
|
140
|
+
let yoke = box(W1 * 1.1, 6 * scale, t * 0.8)
|
|
141
141
|
.translate(basePivot[0], basePivot[1] + 3 * scale, basePivot[2])
|
|
142
142
|
.color(colors.knuckle);
|
|
143
143
|
yoke = seg1(yoke);
|
|
@@ -173,12 +173,12 @@ function makeFinger(opts) {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
// --- Palm assembly ---
|
|
176
|
-
const palm = box(palmW, palmD, palmH
|
|
177
|
-
const palmPad = box(palmW * 0.6, 3 * scale, palmH * 0.5
|
|
176
|
+
const palm = box(palmW, palmD, palmH).color(colors.palm);
|
|
177
|
+
const palmPad = box(palmW * 0.6, 3 * scale, palmH * 0.5)
|
|
178
178
|
.color(colors.palmPad)
|
|
179
179
|
.onFace(palm, 'front', { v: -palmH * 0.05, protrude: 1 * scale });
|
|
180
180
|
|
|
181
|
-
const knuckleBar = box(palmW * 0.9, 10 * scale, 6 * scale
|
|
181
|
+
const knuckleBar = box(palmW * 0.9, 10 * scale, 6 * scale)
|
|
182
182
|
.color(colors.knuckle)
|
|
183
183
|
.onFace(palm, 'top', { v: -palmD / 2 + 8 * scale, protrude: 3 * scale });
|
|
184
184
|
|
|
@@ -192,7 +192,7 @@ const wrist = cylinder(wristLen, wristR)
|
|
|
192
192
|
const motorW = 40 * scale;
|
|
193
193
|
const motorD = 28 * scale;
|
|
194
194
|
const motorH = 20 * scale;
|
|
195
|
-
const motor = box(motorW, motorD, motorH
|
|
195
|
+
const motor = box(motorW, motorD, motorH)
|
|
196
196
|
.color(colors.motor)
|
|
197
197
|
.attachTo(palm, 'bottom', 'top', [0, palmD / 2 - motorD / 2 - 4 * scale, -2 * scale]);
|
|
198
198
|
|
|
@@ -261,7 +261,7 @@ const cables = fingerBases.map((end, i) => {
|
|
|
261
261
|
// --- Grasp target object ---
|
|
262
262
|
const graspObject = union(
|
|
263
263
|
sphere(18 * scale).translate(0, baseY - 45 * scale, baseZ + 6 * scale),
|
|
264
|
-
box(32 * scale, 20 * scale, 26 * scale
|
|
264
|
+
box(32 * scale, 20 * scale, 26 * scale).translate(12 * scale, baseY - 65 * scale, baseZ + 2 * scale)
|
|
265
265
|
).color('#88ccee');
|
|
266
266
|
|
|
267
267
|
// --- Return scene ---
|
|
@@ -191,7 +191,7 @@ for (let i = 0; i <= NUM_STATIONS; i++) {
|
|
|
191
191
|
const bladeRaw = loft(profiles, heights, { edgeLength: meshRes });
|
|
192
192
|
|
|
193
193
|
// Rotate blade from Z-axis (span) to X-axis (radial in propeller disk)
|
|
194
|
-
const blade = bladeRaw.
|
|
194
|
+
const blade = bladeRaw.rotateY(90);
|
|
195
195
|
|
|
196
196
|
// ─── Spinner / Hub ──────────────────────────────────────────────
|
|
197
197
|
//
|
|
@@ -257,7 +257,7 @@ if (showSections) {
|
|
|
257
257
|
pts = rotate2D(pts, 90 + twist);
|
|
258
258
|
|
|
259
259
|
const section = polygon(pts).extrude(2)
|
|
260
|
-
.
|
|
260
|
+
.rotateY(90)
|
|
261
261
|
.translate(r, 0, 0)
|
|
262
262
|
.color('#ff4422');
|
|
263
263
|
|
|
@@ -12,7 +12,7 @@ const outer = box(width, depth, height);
|
|
|
12
12
|
let enclosure = fillet(outer, outerR, { parallel: [0, 0, 1], convex: true });
|
|
13
13
|
|
|
14
14
|
// ── Hollow interior ─────────────────────────────────────────────────────────
|
|
15
|
-
const cavity = box(width - wall * 2, depth - wall * 2, height - wall
|
|
15
|
+
const cavity = box(width - wall * 2, depth - wall * 2, height - wall)
|
|
16
16
|
.translate(width / 2, depth / 2, wall + (height - wall) / 2 + 0.01);
|
|
17
17
|
enclosure = difference(enclosure, cavity);
|
|
18
18
|
|
|
@@ -48,8 +48,8 @@ const curveProfile = rect(thick, width).translate(hookCurveR, 0);
|
|
|
48
48
|
const curvePiece = curveProfile.revolve(90)
|
|
49
49
|
// revolve produces shape around Y axis; rotate to align:
|
|
50
50
|
// we need the arc to go from -Z (down) to +Y (forward)
|
|
51
|
-
.
|
|
52
|
-
.
|
|
51
|
+
.rotateX(90).rotateZ(90) // align width along X
|
|
52
|
+
.rotateX(180) // flip so arc opens downward-to-forward
|
|
53
53
|
.translate(0, clampDepth * 0.6 + hookCurveR, hookZ);
|
|
54
54
|
|
|
55
55
|
// Straight hook tip extending forward
|
|
@@ -61,9 +61,9 @@ function localToWorld(localPt, basePt, yawDeg) {
|
|
|
61
61
|
|
|
62
62
|
// Clevis mount with pin bore centered at origin
|
|
63
63
|
function makeClevis(width, height, depth, gap, lugW, boreR) {
|
|
64
|
-
const left = box(lugW, depth, height
|
|
65
|
-
const right = box(lugW, depth, height
|
|
66
|
-
const bridge = box(width, depth * 0.55, height * 0.55
|
|
64
|
+
const left = box(lugW, depth, height).translate(-(gap * 0.5 + lugW * 0.5), -depth * 0.5, 0);
|
|
65
|
+
const right = box(lugW, depth, height).translate(gap * 0.5 + lugW * 0.5, -depth * 0.5, 0);
|
|
66
|
+
const bridge = box(width, depth * 0.55, height * 0.55).translate(0, -depth * 0.78, 0);
|
|
67
67
|
const raw = union(left, right, bridge);
|
|
68
68
|
const bore = cylinder(width + 2, boreR).pointAlong([1, 0, 0]);
|
|
69
69
|
return raw.subtract(bore);
|
|
@@ -73,7 +73,7 @@ function makeClevis(width, height, depth, gap, lugW, boreR) {
|
|
|
73
73
|
function makeHingeEar(width, height, depth, boreR) {
|
|
74
74
|
const ear = union(
|
|
75
75
|
cylinder(width * 0.62, height * 0.45).pointAlong([1, 0, 0]).translate(0, 0, 0),
|
|
76
|
-
box(width * 0.62, depth * 0.9, height * 0.85
|
|
76
|
+
box(width * 0.62, depth * 0.9, height * 0.85).translate(0, depth * 0.45, 0)
|
|
77
77
|
);
|
|
78
78
|
const bore = cylinder(width + 2, boreR).pointAlong([1, 0, 0]);
|
|
79
79
|
return ear.subtract(bore);
|
|
@@ -88,8 +88,8 @@ function makePhalanxPart(length, width, thick, hasFrontClevis, frontScale = 1.0)
|
|
|
88
88
|
const baseEar = makeHingeEar(width, thick, lugDepth, pinR + jointClearance * 0.6)
|
|
89
89
|
.translate(0, 0, 0);
|
|
90
90
|
|
|
91
|
-
const topRib = box(width * 0.36, length * 0.72, thick * 0.22
|
|
92
|
-
const bottomRib = box(width * 0.36, length * 0.72, thick * 0.18
|
|
91
|
+
const topRib = box(width * 0.36, length * 0.72, thick * 0.22).translate(0, length * 0.52, thick * 0.28);
|
|
92
|
+
const bottomRib = box(width * 0.36, length * 0.72, thick * 0.18).translate(0, length * 0.52, -thick * 0.28);
|
|
93
93
|
|
|
94
94
|
let part = union(body, baseEar, topRib, bottomRib);
|
|
95
95
|
|
|
@@ -157,8 +157,8 @@ function makeFingerAssembly(opts) {
|
|
|
157
157
|
|
|
158
158
|
const worldBase = localToWorld([0, py, pz], basePivot, yawDeg);
|
|
159
159
|
const part = localPart
|
|
160
|
-
.
|
|
161
|
-
.
|
|
160
|
+
.rotateX(accum)
|
|
161
|
+
.rotateZ(yawDeg)
|
|
162
162
|
.translate(worldBase[0], worldBase[1], worldBase[2])
|
|
163
163
|
.translate(0, 0, explode * i * 0.08);
|
|
164
164
|
|
|
@@ -170,7 +170,7 @@ function makeFingerAssembly(opts) {
|
|
|
170
170
|
const pinLen = segW + wall * 2.4;
|
|
171
171
|
const pin = cylinder(pinLen, pinR * 0.92)
|
|
172
172
|
.pointAlong([1, 0, 0])
|
|
173
|
-
.
|
|
173
|
+
.rotateZ(yawDeg)
|
|
174
174
|
.translate(worldBase[0], worldBase[1], worldBase[2])
|
|
175
175
|
.translate(0, 0, explode * i * 0.08)
|
|
176
176
|
.color('#B0B7C3');
|
|
@@ -220,7 +220,7 @@ function makeFingerAssembly(opts) {
|
|
|
220
220
|
|
|
221
221
|
// Build palm with integrated finger clevises and wrist lug
|
|
222
222
|
function makePalm() {
|
|
223
|
-
const palmCore = roundedRect(palmW, palmD, 10 * scale
|
|
223
|
+
const palmCore = roundedRect(palmW, palmD, 10 * scale).extrude(palmT, { center: true })
|
|
224
224
|
.translate(0, palmD * 0.5, 0);
|
|
225
225
|
|
|
226
226
|
const palmHoles = union(
|
|
@@ -246,11 +246,11 @@ function makePalm() {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
const thumbClevis = makeClevis(thumbWidth, segmentThick * 0.86, lugDepth, lugGap, lugWidth, pinR + jointClearance)
|
|
249
|
-
.
|
|
249
|
+
.rotateZ(-thumbOpposition)
|
|
250
250
|
.translate(palmW * 0.45, palmD * 0.24, 0);
|
|
251
251
|
|
|
252
252
|
const wristEar = makeHingeEar(palmW * 0.45, segmentThick, lugDepth * 1.05, pinR + jointClearance)
|
|
253
|
-
.
|
|
253
|
+
.rotateY(180)
|
|
254
254
|
.translate(0, 0, 0);
|
|
255
255
|
|
|
256
256
|
palm = union(palm, thumbClevis, wristEar);
|
|
@@ -267,7 +267,7 @@ function makeMount() {
|
|
|
267
267
|
const mastD = 34 * scale;
|
|
268
268
|
const mastH = 86 * scale;
|
|
269
269
|
|
|
270
|
-
let base = roundedRect(baseW, baseD, 8 * scale
|
|
270
|
+
let base = roundedRect(baseW, baseD, 8 * scale).extrude(baseT, { center: true }).translate(0, -36 * scale, -mastH * 0.52);
|
|
271
271
|
|
|
272
272
|
const slotSketchA = slot(20 * scale, 7 * scale).translate(-baseW * 0.28, -36 * scale);
|
|
273
273
|
const slotSketchB = slot(20 * scale, 7 * scale).translate(baseW * 0.28, -36 * scale);
|
|
@@ -281,10 +281,10 @@ function makeMount() {
|
|
|
281
281
|
);
|
|
282
282
|
base = base.subtract(slots);
|
|
283
283
|
|
|
284
|
-
const mast = box(mastW, mastD, mastH
|
|
284
|
+
const mast = box(mastW, mastD, mastH).translate(0, -8 * scale, -mastH * 0.02);
|
|
285
285
|
const gussetL = polygon([[0, 0], [26 * scale, 0], [0, 28 * scale]])
|
|
286
286
|
.extrude(6 * scale, { center: true })
|
|
287
|
-
.
|
|
287
|
+
.rotateX(90).rotateZ(90)
|
|
288
288
|
.translate(-mastW * 0.5 - 3 * scale, -18 * scale, -mastH * 0.28);
|
|
289
289
|
const gussetR = gussetL.mirrorThrough([0, 0, 0], [1, 0, 0]);
|
|
290
290
|
|
|
@@ -89,7 +89,7 @@ function collectSceneBounds(items) {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function gearDisc(radius, thickness, teeth) {
|
|
92
|
-
return cylinder(thickness, radius, radius, teeth
|
|
92
|
+
return cylinder(thickness, radius, radius, teeth).pointAlong([0, 1, 0]);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function axle(radius, length) {
|
|
@@ -185,15 +185,15 @@ function makePayloadLocal(kind, size) {
|
|
|
185
185
|
return sphere(size * 0.5);
|
|
186
186
|
}
|
|
187
187
|
if (kind === 2) {
|
|
188
|
-
return box(size, size * 0.78, size * 0.58
|
|
188
|
+
return box(size, size * 0.78, size * 0.58);
|
|
189
189
|
}
|
|
190
190
|
if (kind === 3) {
|
|
191
|
-
return cylinder(size * 0.9, size * 0.32
|
|
191
|
+
return cylinder(size * 0.9, size * 0.32);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
const lobeA = sphere(size * 0.35).translate(-size * 0.2, 0, 0);
|
|
195
195
|
const lobeB = sphere(size * 0.28).translate(size * 0.2, size * 0.1, size * 0.05);
|
|
196
|
-
const bridge = box(size * 0.48, size * 0.22, size * 0.28
|
|
196
|
+
const bridge = box(size * 0.48, size * 0.22, size * 0.28);
|
|
197
197
|
return union(lobeA, lobeB, bridge);
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -202,7 +202,7 @@ const mountW = 180;
|
|
|
202
202
|
const mountD = 140;
|
|
203
203
|
const mountT = 8;
|
|
204
204
|
|
|
205
|
-
let mountPlate = box(mountW, mountD, mountT
|
|
205
|
+
let mountPlate = box(mountW, mountD, mountT).translate(0, 0, mountT * 0.5);
|
|
206
206
|
const mountHoles = [];
|
|
207
207
|
for (const sx of [-1, 1]) {
|
|
208
208
|
for (const sy of [-1, 1]) {
|
|
@@ -216,11 +216,11 @@ mountPlate = difference(mountPlate, ...mountHoles);
|
|
|
216
216
|
const clampGap = 38;
|
|
217
217
|
const clampNeck = box(44, 28, clampGap + mountT)
|
|
218
218
|
.translate(-22, -mountD / 2 - 14, -clampGap + mountT * 0.5);
|
|
219
|
-
const clampJaw = box(130, 28, 10
|
|
219
|
+
const clampJaw = box(130, 28, 10)
|
|
220
220
|
.translate(0, -mountD / 2 - 14, -clampGap - 5);
|
|
221
221
|
const clampScrew = cylinder(clampGap + 7, 4.8)
|
|
222
222
|
.translate(0, -mountD / 2 - 14, -clampGap - 1);
|
|
223
|
-
const clampKnob = cylinder(8, 14, 14, 18
|
|
223
|
+
const clampKnob = cylinder(8, 14, 14, 18)
|
|
224
224
|
.translate(0, -mountD / 2 - 14, -clampGap - 11);
|
|
225
225
|
|
|
226
226
|
const statorH = 44;
|
|
@@ -233,7 +233,7 @@ let baseRotor = cylinder(rotorH, 46).translate(0, 0, mountT + statorH - 4);
|
|
|
233
233
|
baseRotor = baseRotor.subtract(cylinder(rotorH + 2, 30).translate(0, 0, mountT + statorH - 3));
|
|
234
234
|
|
|
235
235
|
const towerH = 40;
|
|
236
|
-
const shoulderTower = box(42, 58, towerH
|
|
236
|
+
const shoulderTower = box(42, 58, towerH)
|
|
237
237
|
.translate(0, 0, mountT + statorH + rotorH + towerH * 0.5 - 4);
|
|
238
238
|
|
|
239
239
|
const yawServoLocal = makeServoLocal(44, 21, 39, 11)
|
|
@@ -518,7 +518,7 @@ function placeHandLocal(shape) {
|
|
|
518
518
|
const rotatingRollShaftLocal = rollShaft;
|
|
519
519
|
const wristCouplerLocal = union(
|
|
520
520
|
cylinder(20, 8.5).pointAlong([1, 0, 0]).translate(handRootX - 20, 0, 0),
|
|
521
|
-
box(14, 6, 18
|
|
521
|
+
box(14, 6, 18).translate(handRootX - 8, 0, 9)
|
|
522
522
|
);
|
|
523
523
|
|
|
524
524
|
const handGroup = [
|
|
@@ -89,7 +89,7 @@ for (let i = 0; i < ridgeCount; i++) {
|
|
|
89
89
|
const rx = (capOuterR + 0.5) * Math.cos(rad);
|
|
90
90
|
const ry = (capOuterR + 0.5) * Math.sin(rad);
|
|
91
91
|
ridges.push(
|
|
92
|
-
box(1.5, 1.5, capH - 4
|
|
92
|
+
box(1.5, 1.5, capH - 4)
|
|
93
93
|
.translate(rx, ry, bodyH + neckH + capH / 2)
|
|
94
94
|
);
|
|
95
95
|
}
|
|
@@ -52,7 +52,7 @@ function rookShape() {
|
|
|
52
52
|
.translate(0, 0, squareSize * 0.34);
|
|
53
53
|
const crown = cylinder(squareSize * 0.17, squareSize * 0.23)
|
|
54
54
|
.translate(0, 0, squareSize * 0.79);
|
|
55
|
-
const slot = box(squareSize * 0.08, squareSize * 0.18, squareSize * 0.14
|
|
55
|
+
const slot = box(squareSize * 0.08, squareSize * 0.18, squareSize * 0.14)
|
|
56
56
|
.translate(0, squareSize * 0.18, squareSize * 0.88);
|
|
57
57
|
const battlements = crown.subtract(circularPattern(slot, 4));
|
|
58
58
|
return union(base, lowerBody, tower, battlements);
|
|
@@ -68,8 +68,8 @@ function bishopShape() {
|
|
|
68
68
|
const crown = ring(squareSize * 0.05, squareSize * 0.16, squareSize * 0.11)
|
|
69
69
|
.translate(0, 0, squareSize * 0.74);
|
|
70
70
|
const piece = union(base, lowerBody, body, crown, head);
|
|
71
|
-
const slit = box(squareSize * 0.06, squareSize * 0.28, squareSize * 0.42
|
|
72
|
-
.
|
|
71
|
+
const slit = box(squareSize * 0.06, squareSize * 0.28, squareSize * 0.42)
|
|
72
|
+
.rotateZ(32)
|
|
73
73
|
.translate(0, 0, squareSize * 0.86);
|
|
74
74
|
return piece.subtract(slit);
|
|
75
75
|
}
|
|
@@ -100,9 +100,9 @@ function kingShape() {
|
|
|
100
100
|
.translate(0, 0, squareSize * 0.37);
|
|
101
101
|
const shoulder = sphere(squareSize * 0.12).translate(0, 0, squareSize * 0.94);
|
|
102
102
|
const neck = cylinder(squareSize * 0.08, squareSize * 0.08).translate(0, 0, squareSize * 1.04);
|
|
103
|
-
const crossStem = box(squareSize * 0.055, squareSize * 0.055, squareSize * 0.22
|
|
103
|
+
const crossStem = box(squareSize * 0.055, squareSize * 0.055, squareSize * 0.22)
|
|
104
104
|
.translate(0, 0, squareSize * 1.2);
|
|
105
|
-
const crossArm = box(squareSize * 0.18, squareSize * 0.05, squareSize * 0.05
|
|
105
|
+
const crossArm = box(squareSize * 0.18, squareSize * 0.05, squareSize * 0.05)
|
|
106
106
|
.translate(0, 0, squareSize * 1.23);
|
|
107
107
|
return union(base, lowerBody, body, shoulder, neck, crossStem, crossArm);
|
|
108
108
|
}
|
|
@@ -124,17 +124,17 @@ function knightShape() {
|
|
|
124
124
|
sphere(squareSize * 0.055).translate(0, squareSize * 0.24, squareSize * 0.98),
|
|
125
125
|
sphere(squareSize * 0.045).translate(0, squareSize * 0.31, squareSize * 0.94)
|
|
126
126
|
);
|
|
127
|
-
const mane = box(squareSize * 0.08, squareSize * 0.12, squareSize * 0.36
|
|
128
|
-
.
|
|
127
|
+
const mane = box(squareSize * 0.08, squareSize * 0.12, squareSize * 0.36)
|
|
128
|
+
.rotateX(-12)
|
|
129
129
|
.translate(0, squareSize * 0.03, squareSize * 0.94);
|
|
130
|
-
const earL = box(squareSize * 0.035, squareSize * 0.08, squareSize * 0.12
|
|
131
|
-
.
|
|
130
|
+
const earL = box(squareSize * 0.035, squareSize * 0.08, squareSize * 0.12)
|
|
131
|
+
.rotateX(-18).rotateZ(14)
|
|
132
132
|
.translate(-squareSize * 0.04, squareSize * 0.18, squareSize * 1.2);
|
|
133
|
-
const earR = box(squareSize * 0.035, squareSize * 0.08, squareSize * 0.12
|
|
134
|
-
.
|
|
133
|
+
const earR = box(squareSize * 0.035, squareSize * 0.08, squareSize * 0.12)
|
|
134
|
+
.rotateX(-18).rotateZ(-14)
|
|
135
135
|
.translate(squareSize * 0.04, squareSize * 0.18, squareSize * 1.2);
|
|
136
|
-
const chinCut = box(squareSize * 0.5, squareSize * 0.28, squareSize * 0.34
|
|
137
|
-
.
|
|
136
|
+
const chinCut = box(squareSize * 0.5, squareSize * 0.28, squareSize * 0.34)
|
|
137
|
+
.rotateX(58)
|
|
138
138
|
.translate(0, -squareSize * 0.04, squareSize * 0.93);
|
|
139
139
|
return union(base, chest, neck, head, muzzle, mane, earL, earR).subtract(chinCut);
|
|
140
140
|
}
|
|
@@ -159,15 +159,15 @@ function placePiece(kind, file, rank, color, facingDeg, name) {
|
|
|
159
159
|
const [x, y] = squareCenter(file, rank);
|
|
160
160
|
const shape = makePiece(kind)
|
|
161
161
|
.scale(pieceScale)
|
|
162
|
-
.
|
|
162
|
+
.rotateZ(facingDeg)
|
|
163
163
|
.translate(x, y, pieceZ)
|
|
164
164
|
.color(color);
|
|
165
165
|
return { name, shape };
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
const frame = difference(
|
|
169
|
-
box(frameSize, frameSize, boardThickness
|
|
170
|
-
box(boardSize + 1, boardSize + 1, boardThickness * 0.32
|
|
169
|
+
box(frameSize, frameSize, boardThickness).translate(0, 0, boardThickness * 0.5),
|
|
170
|
+
box(boardSize + 1, boardSize + 1, boardThickness * 0.32)
|
|
171
171
|
.translate(0, 0, boardThickness - boardThickness * 0.16)
|
|
172
172
|
)
|
|
173
173
|
.color(woodDark);
|
|
@@ -177,7 +177,7 @@ const darkSquares = [];
|
|
|
177
177
|
for (let file = 0; file < 8; file += 1) {
|
|
178
178
|
for (let rank = 0; rank < 8; rank += 1) {
|
|
179
179
|
const [x, y] = squareCenter(file, rank);
|
|
180
|
-
const tile = box(squareSize, squareSize, tileHeight
|
|
180
|
+
const tile = box(squareSize, squareSize, tileHeight)
|
|
181
181
|
.translate(x, y, boardTop + tileHeight * 0.5);
|
|
182
182
|
if ((file + rank) % 2 === 0) lightSquares.push(tile);
|
|
183
183
|
else darkSquares.push(tile);
|
|
@@ -188,9 +188,9 @@ const lightSquareField = union(...lightSquares).color(woodLight);
|
|
|
188
188
|
const darkSquareField = union(...darkSquares).color(squareDark);
|
|
189
189
|
|
|
190
190
|
const trim = difference(
|
|
191
|
-
box(frameSize - borderWidth * 0.45, frameSize - borderWidth * 0.45, tileHeight * 0.9
|
|
191
|
+
box(frameSize - borderWidth * 0.45, frameSize - borderWidth * 0.45, tileHeight * 0.9)
|
|
192
192
|
.translate(0, 0, boardTop + tileHeight * 0.45),
|
|
193
|
-
box(boardSize + borderWidth * 0.2, boardSize + borderWidth * 0.2, tileHeight * 2
|
|
193
|
+
box(boardSize + borderWidth * 0.2, boardSize + borderWidth * 0.2, tileHeight * 2)
|
|
194
194
|
.translate(0, 0, boardTop + tileHeight * 0.45)
|
|
195
195
|
).color(woodMid);
|
|
196
196
|
|
|
@@ -130,12 +130,12 @@ const propStick = union(
|
|
|
130
130
|
).color('#8B7355');
|
|
131
131
|
|
|
132
132
|
// --- Keybed ---
|
|
133
|
-
const keybed = box(keyboardWidth, keyboardDepth, keybedHeight
|
|
133
|
+
const keybed = box(keyboardWidth, keyboardDepth, keybedHeight)
|
|
134
134
|
.attachTo(body, 'top-front', 'top-front', [0, 0, -2])
|
|
135
135
|
.color('#222222');
|
|
136
136
|
|
|
137
137
|
// --- White keys ---
|
|
138
|
-
const whiteKey = box(whiteKeyWidth * 0.98, whiteKeyDepth, keyHeight
|
|
138
|
+
const whiteKey = box(whiteKeyWidth * 0.98, whiteKeyDepth, keyHeight).color('#f5f5f5');
|
|
139
139
|
const keyboardLeft = -keyboardWidth / 2 + whiteKeyWidth / 2;
|
|
140
140
|
|
|
141
141
|
const whiteKeyRow = linearPattern(whiteKey, whiteKeyCount, whiteKeyWidth, 0, 0)
|
|
@@ -145,7 +145,7 @@ const whiteKeys = whiteKeyRow
|
|
|
145
145
|
.attachTo(keybed, 'top-front', 'bottom-front', [0, -2, 0.1]);
|
|
146
146
|
|
|
147
147
|
// --- Black keys ---
|
|
148
|
-
const blackKey = box(blackKeyWidth, blackKeyDepth, blackKeyHeight
|
|
148
|
+
const blackKey = box(blackKeyWidth, blackKeyDepth, blackKeyHeight).color('#111111');
|
|
149
149
|
const blackPattern = [0, 1, 3, 4, 5];
|
|
150
150
|
const blackKeysList = [];
|
|
151
151
|
|
|
@@ -161,12 +161,12 @@ const blackKeys = blackKeysRow
|
|
|
161
161
|
.attachTo(keybed, 'top-front', 'bottom-front', [0, whiteKeyDepth * 0.2, 0.1]);
|
|
162
162
|
|
|
163
163
|
// --- Key slip (front rail below keyboard) ---
|
|
164
|
-
const keySlip = box(keyboardWidth, 12, 6
|
|
164
|
+
const keySlip = box(keyboardWidth, 12, 6)
|
|
165
165
|
.attachTo(keybed, 'bottom-front', 'top-front', [0, -4, -2])
|
|
166
166
|
.color('#1b1b1b');
|
|
167
167
|
|
|
168
168
|
// --- Fallboard (keyboard cover, resting behind the keys) ---
|
|
169
|
-
const fallboard = box(keyboardWidth, 4, keybedHeight + keyHeight + 2
|
|
169
|
+
const fallboard = box(keyboardWidth, 4, keybedHeight + keyHeight + 2)
|
|
170
170
|
.attachTo(keybed, 'top-back', 'bottom-front', [0, 2, 0])
|
|
171
171
|
.color('#111111');
|
|
172
172
|
|
|
@@ -178,16 +178,16 @@ const standLipHeight = 8;
|
|
|
178
178
|
const standLipDepth = 6;
|
|
179
179
|
|
|
180
180
|
// Main panel of the music stand
|
|
181
|
-
const standPanel = box(standWidth, standThickness, standHeight
|
|
181
|
+
const standPanel = box(standWidth, standThickness, standHeight)
|
|
182
182
|
.translate(0, 0, standHeight / 2);
|
|
183
183
|
|
|
184
184
|
// Bottom lip to hold sheet music
|
|
185
|
-
const standLip = box(standWidth, standLipDepth, standLipHeight
|
|
185
|
+
const standLip = box(standWidth, standLipDepth, standLipHeight)
|
|
186
186
|
.attachTo(standPanel, 'bottom-front', 'bottom-back', [0, 0, 0]);
|
|
187
187
|
|
|
188
188
|
// Combine panel + lip, tilt back, then position behind the fallboard
|
|
189
189
|
const standAssembly = group(standPanel, standLip)
|
|
190
|
-
.
|
|
190
|
+
.rotateX(-12);
|
|
191
191
|
|
|
192
192
|
// Position the music stand so it sits above the soundboard, behind the keyboard area
|
|
193
193
|
const keybedBB = keybed.boundingBox();
|
|
@@ -223,11 +223,11 @@ const frontRightBB = frontRightLeg.boundingBox();
|
|
|
223
223
|
const pedalRailY = (frontLeftBB.min[1] + frontLeftBB.max[1]) / 2;
|
|
224
224
|
const pedalRailZ = legHeight * 0.15;
|
|
225
225
|
|
|
226
|
-
const pedalRail = box(50, 14, 6
|
|
226
|
+
const pedalRail = box(50, 14, 6)
|
|
227
227
|
.translate(bodyCenterX, pedalRailY, pedalRailZ)
|
|
228
228
|
.color('#bfa14a');
|
|
229
229
|
|
|
230
|
-
const pedalBlade = box(4, 18, 2
|
|
230
|
+
const pedalBlade = box(4, 18, 2).rotateX(10).color('#d8b45a');
|
|
231
231
|
const pedalSpacing = 12;
|
|
232
232
|
|
|
233
233
|
const pedalL = pedalBlade.attachTo(pedalRail, 'top', 'bottom', [-pedalSpacing, 0, 0]);
|
|
@@ -240,7 +240,7 @@ const benchDepth = keyboardDepth * 0.6;
|
|
|
240
240
|
const benchSeatThickness = 6;
|
|
241
241
|
const benchHeight = legHeight * 0.7;
|
|
242
242
|
|
|
243
|
-
const benchSeat = box(benchWidth, benchDepth, benchSeatThickness
|
|
243
|
+
const benchSeat = box(benchWidth, benchDepth, benchSeatThickness)
|
|
244
244
|
.translate(bodyCenterX, frontY - keyboardDepth * 0.9, benchHeight + benchSeatThickness / 2)
|
|
245
245
|
.color('#3b2a1a');
|
|
246
246
|
|