forgecad 0.6.3 → 0.8.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 +3 -12
- package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-D4bocK4E.js} +250 -151
- package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
- package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-D3A_g8V3.js} +329 -163
- package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-BWYUSpUN.css} +590 -136
- package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
- package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-kWjKaC_t.js} +2 -4
- package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
- package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
- package/dist/assets/PricingPage-BsU5vzEx.js +232 -0
- package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-PqvpAKIs.js} +129 -5
- package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-C-hzNUMy.js} +8949 -3161
- package/dist/assets/{Viewport-CoB46f5R.js → index-Pz321YAt.js} +38382 -7501
- package/dist/assets/{index-2hfs_ub0.css → index-ay13WNfa.css} +726 -53
- package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
- package/dist/assets/{manifold-CqNMHHKO.js → manifold-BcbjWLIo.js} +4 -3
- package/dist/assets/{manifold-Cce9wRFz.js → manifold-DBckbFgx.js} +1 -1
- package/dist/assets/{manifold-D6BeHIOo.js → manifold-O2AAGXyj.js} +1 -1
- package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-Dxr-5A7w.js} +8760 -3559
- package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +341 -718
- package/dist/docs-raw/generated/assembly.md +699 -112
- package/dist/docs-raw/generated/concepts.md +1834 -1346
- package/dist/docs-raw/generated/core.md +1012 -1059
- package/dist/docs-raw/generated/curves.md +759 -116
- package/dist/docs-raw/generated/lib.md +43 -748
- package/dist/docs-raw/generated/output.md +139 -245
- package/dist/docs-raw/generated/sdf.md +208 -0
- package/dist/docs-raw/generated/sheet-metal.md +473 -21
- package/dist/docs-raw/generated/sketch.md +1518 -362
- package/dist/docs-raw/generated/viewport.md +368 -299
- package/dist/docs-raw/generated/wood.md +104 -0
- package/dist/index.html +2 -2
- package/dist/landing/proof-ams-adapter.png +0 -0
- package/dist/landing/proof-bolt-and-nut.png +0 -0
- package/dist/landing/proof-fillet-enclosure.png +0 -0
- package/dist/landing/proof-glasses.png +0 -0
- package/dist/landing/proof-gyroid.png +0 -0
- package/dist/sitemap.xml +6 -6
- package/dist-cli/forgecad.js +12321 -5700
- package/dist-cli/forgecad.js.map +1 -0
- package/dist-cli/solver-46FFSK2U.js +363 -0
- package/dist-cli/solver-46FFSK2U.js.map +1 -0
- package/dist-skill/CONTEXT.md +4890 -6302
- package/dist-skill/SKILL-dev.md +22 -66
- package/dist-skill/SKILL.md +20 -59
- package/dist-skill/docs/API/core/concepts.md +37 -92
- package/dist-skill/docs/CLI.md +341 -718
- package/dist-skill/docs/generated/assembly.md +699 -112
- package/dist-skill/docs/generated/core.md +1012 -1059
- package/dist-skill/docs/generated/curves.md +759 -116
- package/dist-skill/docs/generated/lib.md +43 -748
- package/dist-skill/docs/generated/output.md +139 -245
- package/dist-skill/docs/generated/sdf.md +208 -0
- package/dist-skill/docs/generated/sheet-metal.md +473 -21
- package/dist-skill/docs/generated/sketch.md +1518 -362
- package/dist-skill/docs/generated/viewport.md +368 -299
- 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/joint-design.md +78 -0
- 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 +78 -0
- package/dist-skill/docs-dev/CLI.md +488 -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 +2 -4
- package/dist-skill/docs-dev/component-model.md +164 -0
- package/dist-skill/docs-dev/generated/assembly.md +779 -0
- package/dist-skill/docs-dev/generated/core.md +1676 -0
- package/dist-skill/docs-dev/generated/curves.md +855 -0
- package/dist-skill/docs-dev/generated/lib.md +55 -0
- package/dist-skill/docs-dev/generated/output.md +234 -0
- package/dist-skill/docs-dev/generated/sdf.md +208 -0
- package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
- package/dist-skill/docs-dev/generated/sketch.md +1753 -0
- package/dist-skill/docs-dev/generated/viewport.md +513 -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/joint-design.md +78 -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 +8 -8
- package/examples/api/bill-of-materials.forge.js +9 -9
- package/examples/api/bolt-pattern.forge.js +5 -5
- package/examples/api/boolean-operations.forge.js +5 -5
- package/examples/api/bounding-box-visualizer.forge.js +3 -3
- package/examples/api/clone-duplicate.forge.js +2 -2
- package/examples/api/colors-union-vs-array.forge.js +6 -6
- package/examples/api/connector-assembly.forge.js +8 -6
- package/examples/api/connector-basics.forge.js +7 -7
- package/examples/api/constrained-sketch-mechanical.forge.js +4 -4
- package/examples/api/elbow-test.forge.js +3 -3
- package/examples/api/extrude-options.forge.js +8 -14
- package/examples/api/feature-created-faces.forge.js +6 -10
- package/examples/api/fillet-showcase.forge.js +2 -2
- package/examples/api/folded-service-panel-cover.forge.js +2 -2
- package/examples/api/gears-tier1.forge.js +5 -5
- package/examples/api/group-test.forge.js +3 -3
- 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 +4 -4
- package/examples/api/patterns.forge.js +3 -3
- package/examples/api/pointAlong-orientation.forge.js +3 -3
- package/examples/api/profile-2020-b-slot6.forge.js +4 -5
- 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/sketch-rounding-strategies.forge.js +1 -1
- package/examples/api/smooth-curve-connections.forge.js +1 -1
- package/examples/api/transition-curves.forge.js +4 -4
- 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/constraints/01-fully-constrained-rect.forge.js +2 -2
- package/examples/constraints/02-underconstrained-triangle.forge.js +1 -1
- package/examples/constraints/03-redundant-constraints.forge.js +2 -2
- package/examples/constraints/05-parallel-with-linedistance.forge.js +2 -2
- package/examples/constraints/06-complex-spectrogram.forge.js +1 -1
- package/examples/constraints/07-perpendicular-chain.forge.js +4 -4
- package/examples/constraints/08-symmetric-bracket.forge.js +4 -4
- package/examples/constraints/09-stress-spiral.forge.js +1 -1
- package/examples/constraints/10-stress-honeycomb.forge.js +1 -1
- package/examples/constraints/11-surface-grid.forge.js +2 -2
- package/examples/constraints/12-surface-nested.forge.js +4 -4
- package/examples/constraints/13-surface-complex.forge.js +1 -1
- package/examples/exact-arc-housing.forge.js +12 -0
- package/examples/experiments/drone-arm.forge.js +53 -0
- package/examples/furniture/adjustable-table.forge.js +15 -15
- package/examples/furniture/bathroom.forge.js +26 -26
- package/examples/furniture/chair.forge.js +13 -13
- package/examples/furniture/picture-frame.forge.js +6 -6
- package/examples/furniture/shoe-rack-doors.forge.js +8 -8
- package/examples/furniture/shoe-rack.forge.js +7 -7
- package/examples/furniture/table-lamp.forge.js +8 -8
- package/examples/gcode/lissajous-vase.forge.js +4 -4
- package/examples/gcode/math-surface.forge.js +3 -3
- package/examples/gcode/parametric-vase.forge.js +4 -4
- package/examples/gcode/spiral-tower.forge.js +4 -4
- package/examples/generative/crystal-growth.forge.js +9 -9
- package/examples/generative/frost-spires.forge.js +9 -9
- package/examples/generative/golden-spiral-tower.forge.js +11 -11
- package/examples/generative/molten-forge.forge.js +6 -6
- package/examples/generative/neon-coral.forge.js +7 -7
- package/examples/mechanical/3d-printer.forge.js +37 -37
- package/examples/mechanical/5-finger-robot-hand.forge.js +19 -19
- package/examples/mechanical/airplane-propeller.forge.js +9 -9
- package/examples/mechanical/bolt-and-nut.forge.js +10 -10
- package/examples/mechanical/door-with-hinges.forge.js +7 -7
- package/examples/mechanical/fillet-enclosure.forge.js +15 -11
- package/examples/mechanical/headphone-hanger-v2.forge.js +11 -11
- package/examples/mechanical/robot_hand.forge.js +24 -24
- package/examples/mechanical/robot_hand_2.forge.js +26 -26
- package/examples/nurbs-surface.forge.js +8 -0
- package/examples/nurbs-tube.forge.js +7 -0
- package/examples/products/bottle.forge.js +8 -8
- package/examples/products/chess-set.forge.js +25 -25
- package/examples/products/classical-piano.forge.js +20 -20
- package/examples/products/clock.forge.js +33 -33
- package/examples/products/cup.forge.js +5 -5
- package/examples/products/iphone.forge.js +20 -20
- package/examples/products/laptop.forge.js +24 -24
- package/examples/products/laser-cut-box.forge.js +6 -6
- package/examples/products/laser-cut-tray.forge.js +6 -6
- package/examples/products/liquid-soap-dispenser.forge.js +23 -23
- package/examples/products/origami-fish.forge.js +14 -12
- package/examples/products/spiderman-cake.forge.js +6 -6
- package/examples/shelf/container.forge.js +5 -5
- package/examples/shelf/shelf-unit.forge.js +6 -6
- package/examples/toolbox/bolted-joint.forge.js +7 -7
- package/package.json +9 -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-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/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
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
// Strategy: build small reliable modules, then combine with parametric kinematics.
|
|
4
4
|
|
|
5
5
|
// ---- 1) Control params (motion + fabrication) ----
|
|
6
|
-
const baseYaw =
|
|
7
|
-
const shoulderPitch =
|
|
8
|
-
const elbowPitch =
|
|
9
|
-
const wristPitch =
|
|
10
|
-
const wristRoll =
|
|
6
|
+
const baseYaw = Param.number("Base Yaw", 20, { min: -170, max: 170, unit: "°" });
|
|
7
|
+
const shoulderPitch = Param.number("Shoulder Pitch", 35, { min: -25, max: 105, unit: "°" });
|
|
8
|
+
const elbowPitch = Param.number("Elbow Pitch", 55, { min: -15, max: 135, unit: "°" });
|
|
9
|
+
const wristPitch = Param.number("Wrist Pitch", -20, { min: -100, max: 100, unit: "°" });
|
|
10
|
+
const wristRoll = Param.number("Wrist Roll", 10, { min: -180, max: 180, unit: "°" });
|
|
11
11
|
|
|
12
|
-
const upperLen =
|
|
13
|
-
const foreLen =
|
|
14
|
-
const foreExtension =
|
|
12
|
+
const upperLen = Param.number("Upper Arm Len", 210, { min: 140, max: 320, unit: "mm" });
|
|
13
|
+
const foreLen = Param.number("Forearm Len", 220, { min: 150, max: 340, unit: "mm" });
|
|
14
|
+
const foreExtension = Param.number("Forearm Ext", 70, { min: 0, max: 150, unit: "mm" });
|
|
15
15
|
|
|
16
|
-
const gripperOpen =
|
|
17
|
-
const fingerCurl =
|
|
18
|
-
const payloadType =
|
|
19
|
-
const payloadSize =
|
|
20
|
-
const carryPayload =
|
|
16
|
+
const gripperOpen = Param.number("Gripper Open", 55, { min: 0, max: 90, unit: "mm" });
|
|
17
|
+
const fingerCurl = Param.number("Finger Curl", 72, { min: 0, max: 100, unit: "°" });
|
|
18
|
+
const payloadType = Param.number("Payload Type", 2, { min: 1, max: 4, integer: true });
|
|
19
|
+
const payloadSize = Param.number("Payload Size", 36, { min: 20, max: 65, unit: "mm" });
|
|
20
|
+
const carryPayload = Param.number("Carry Payload", 1, { min: 0, max: 1, integer: true });
|
|
21
21
|
|
|
22
|
-
const exploded =
|
|
23
|
-
const sectionEnabled =
|
|
22
|
+
const exploded = Param.number("Exploded", 0, { min: 0, max: 140, unit: "mm" });
|
|
23
|
+
const sectionEnabled = Param.number("Section Enabled", 0, { min: 0, max: 1, integer: true });
|
|
24
24
|
|
|
25
25
|
// ---- 2) Math + transform helpers ----
|
|
26
26
|
function rad(deg) {
|
|
@@ -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 = [
|
|
@@ -602,12 +602,12 @@ const sectionMarginZ = Math.max(30, (sceneBounds.max[2] - sceneBounds.min[2]) *
|
|
|
602
602
|
const sectionDefaultX = (sceneBounds.min[0] + sceneBounds.max[0]) * 0.5;
|
|
603
603
|
const sectionDefaultZ = (sceneBounds.min[2] + sceneBounds.max[2]) * 0.5;
|
|
604
604
|
|
|
605
|
-
const sectionX =
|
|
605
|
+
const sectionX = Param.number("Section X", sectionDefaultX, {
|
|
606
606
|
min: sceneBounds.min[0] - sectionMarginX,
|
|
607
607
|
max: sceneBounds.max[0] + sectionMarginX,
|
|
608
608
|
unit: "mm",
|
|
609
609
|
});
|
|
610
|
-
const sectionZ =
|
|
610
|
+
const sectionZ = Param.number("Section Z", sectionDefaultZ, {
|
|
611
611
|
min: sceneBounds.min[2] - sectionMarginZ,
|
|
612
612
|
max: sceneBounds.max[2] + sectionMarginZ,
|
|
613
613
|
unit: "mm",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Freeform NURBS surface — a gently curved panel
|
|
2
|
+
const grid = [
|
|
3
|
+
[[0,0,0], [10,0,2], [20,0,2], [30,0,0]],
|
|
4
|
+
[[0,10,1], [10,10,6], [20,10,6], [30,10,1]],
|
|
5
|
+
[[0,20,1], [10,20,6], [20,20,6], [30,20,1]],
|
|
6
|
+
[[0,30,0], [10,30,2], [20,30,2], [30,30,0]],
|
|
7
|
+
];
|
|
8
|
+
return nurbsSurface(grid, { thickness: 1.5 });
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Water Bottle — revolve profile with cap
|
|
2
2
|
// Demonstrates: revolve, polygon, difference, smoothing, multi-object
|
|
3
3
|
|
|
4
|
-
const bodyH =
|
|
5
|
-
const bodyR =
|
|
6
|
-
const neckH =
|
|
7
|
-
const neckR =
|
|
8
|
-
const wall =
|
|
9
|
-
const capH =
|
|
10
|
-
const shoulderR =
|
|
4
|
+
const bodyH = Param.number("Body Height", 180, { min: 120, max: 250, unit: "mm" });
|
|
5
|
+
const bodyR = Param.number("Body Radius", 35, { min: 25, max: 50, unit: "mm" });
|
|
6
|
+
const neckH = Param.number("Neck Height", 30, { min: 15, max: 50, unit: "mm" });
|
|
7
|
+
const neckR = Param.number("Neck Radius", 14, { min: 10, max: 25, unit: "mm" });
|
|
8
|
+
const wall = Param.number("Wall Thickness", 2, { min: 1, max: 5, unit: "mm" });
|
|
9
|
+
const capH = Param.number("Cap Height", 18, { min: 10, max: 30, unit: "mm" });
|
|
10
|
+
const shoulderR = Param.number("Shoulder Curve", 20, { min: 5, max: 40, unit: "mm" });
|
|
11
11
|
|
|
12
12
|
// Outer profile — polygon traced from bottom-center up and around
|
|
13
13
|
// Bottom flat → body → shoulder curve → neck
|
|
@@ -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
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const squareSize =
|
|
2
|
-
const boardThickness =
|
|
3
|
-
const borderWidth =
|
|
4
|
-
const tileHeight =
|
|
5
|
-
const pieceScale =
|
|
6
|
-
const pieceLift =
|
|
1
|
+
const squareSize = Param.number("Square Size", 36, { min: 24, max: 54, unit: "mm" });
|
|
2
|
+
const boardThickness = Param.number("Board Thickness", 14, { min: 8, max: 24, unit: "mm" });
|
|
3
|
+
const borderWidth = Param.number("Border Width", 10, { min: 4, max: 18, unit: "mm" });
|
|
4
|
+
const tileHeight = Param.number("Tile Height", 1.8, { min: 0.8, max: 4, step: 0.1, unit: "mm" });
|
|
5
|
+
const pieceScale = Param.number("Piece Scale", 1, { min: 0.8, max: 1.25, step: 0.01 });
|
|
6
|
+
const pieceLift = Param.number("Piece Lift", 0, { min: 0, max: 16, unit: "mm" });
|
|
7
7
|
|
|
8
8
|
const boardSize = squareSize * 8;
|
|
9
9
|
const frameSize = boardSize + borderWidth * 2;
|
|
@@ -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
|
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
- Bench
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
const bodyWidth =
|
|
16
|
-
const bodyLength =
|
|
17
|
-
const rimHeight =
|
|
18
|
-
const lidThickness =
|
|
19
|
-
const lidOpen =
|
|
20
|
-
const legHeight =
|
|
21
|
-
const legTopRadius =
|
|
22
|
-
const keyboardDepth =
|
|
23
|
-
const keyHeight =
|
|
15
|
+
const bodyWidth = Param.number("Body Width", 180, { min: 140, max: 240, unit: "mm" });
|
|
16
|
+
const bodyLength = Param.number("Body Length", 280, { min: 220, max: 360, unit: "mm" });
|
|
17
|
+
const rimHeight = Param.number("Rim Height", 28, { min: 20, max: 40, unit: "mm" });
|
|
18
|
+
const lidThickness = Param.number("Lid Thickness", 6, { min: 4, max: 10, unit: "mm" });
|
|
19
|
+
const lidOpen = Param.number("Lid Angle", 25, { min: 0, max: 50, unit: "°" });
|
|
20
|
+
const legHeight = Param.number("Leg Height", 60, { min: 45, max: 90, unit: "mm" });
|
|
21
|
+
const legTopRadius = Param.number("Leg Top Radius", 8, { min: 5, max: 12, unit: "mm" });
|
|
22
|
+
const keyboardDepth = Param.number("Keyboard Depth", 60, { min: 45, max: 80, unit: "mm" });
|
|
23
|
+
const keyHeight = Param.number("Key Height", 5, { min: 3, max: 8, unit: "mm" });
|
|
24
24
|
|
|
25
25
|
const rimThickness = Math.min(12, bodyWidth * 0.07);
|
|
26
26
|
const keyboardWidth = bodyWidth * 0.9;
|
|
@@ -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
|
|
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
// Returns named objects to preserve colors and enable individual visibility control
|
|
4
4
|
|
|
5
5
|
// === Dimensions ===
|
|
6
|
-
const diameter =
|
|
7
|
-
const depth =
|
|
8
|
-
const rimWidth =
|
|
6
|
+
const diameter = Param.number("Diameter", 220, { min: 80, max: 400, unit: "mm" });
|
|
7
|
+
const depth = Param.number("Depth", 18, { min: 8, max: 50, unit: "mm" });
|
|
8
|
+
const rimWidth = Param.number("Rim Width", 8, { min: 3, max: 30, unit: "mm" });
|
|
9
9
|
|
|
10
10
|
// === Time Settings — Default 10:10:30 (Apple display time) ===
|
|
11
|
-
const hour =
|
|
12
|
-
const minute =
|
|
13
|
-
const second =
|
|
14
|
-
const showSecondHand =
|
|
11
|
+
const hour = Param.number("Hour", 10, { min: 1, max: 12, integer: true });
|
|
12
|
+
const minute = Param.number("Minute", 10, { min: 0, max: 59, integer: true });
|
|
13
|
+
const second = Param.number("Second", 30, { min: 0, max: 59, integer: true });
|
|
14
|
+
const showSecondHand = Param.number("Show Seconds", 1, { min: 0, max: 1, integer: true });
|
|
15
15
|
|
|
16
16
|
// === Color Customization ===
|
|
17
|
-
const rimColor =
|
|
18
|
-
const faceColor =
|
|
19
|
-
const markerColor =
|
|
20
|
-
const hourHandColor =
|
|
21
|
-
const minuteHandColor =
|
|
22
|
-
const secondHandColor =
|
|
17
|
+
const rimColor = Param.number("Rim Color", 0, { min: 0, max: 3, integer: true }); // 0=silver, 1=gold, 2=black, 3=rose
|
|
18
|
+
const faceColor = Param.number("Face Color", 0, { min: 0, max: 2, integer: true }); // 0=white, 1=black, 2=cream
|
|
19
|
+
const markerColor = Param.number("Marker Color", 0, { min: 0, max: 2, integer: true }); // 0=black, 1=white, 2=gold
|
|
20
|
+
const hourHandColor = Param.number("Hour Hand Color", 0, { min: 0, max: 3, integer: true }); // 0=black, 1=white, 2=gold, 3=red
|
|
21
|
+
const minuteHandColor = Param.number("Minute Hand Color", 1, { min: 0, max: 3, integer: true }); // 0=black, 1=white, 2=gold, 3=red
|
|
22
|
+
const secondHandColor = Param.number("Second Hand Color", 3, { min: 0, max: 3, integer: true }); // 0=black, 1=white, 2=gold, 3=red
|
|
23
23
|
|
|
24
24
|
// Color palette
|
|
25
25
|
const colors = {
|
|
@@ -47,22 +47,22 @@ const innerRadius = radius - rimWidth;
|
|
|
47
47
|
const handBaseZ = depth / 2 - 2;
|
|
48
48
|
|
|
49
49
|
// === Clock Rim ===
|
|
50
|
-
const outer = cylinder(depth, radius
|
|
51
|
-
const inner = cylinder(depth + 2, innerRadius
|
|
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
|
|
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
|
|
59
|
+
const face = cylinder(2, innerRadius - 1)
|
|
60
60
|
.translate(0, 0, depth / 2 - 3)
|
|
61
61
|
.color(faceHex);
|
|
62
62
|
|
|
63
63
|
// === Hour Markers ===
|
|
64
|
-
const markerLength =
|
|
65
|
-
const markerWidth =
|
|
64
|
+
const markerLength = Param.number("Marker Length", 10, { min: 5, max: 25, unit: "mm" });
|
|
65
|
+
const markerWidth = Param.number("Marker Width", 2.5, { min: 1, max: 6, unit: "mm" });
|
|
66
66
|
|
|
67
67
|
const markerShapes = [];
|
|
68
68
|
for (let i = 0; i < 12; i++) {
|
|
@@ -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
|
|
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);
|
|
@@ -86,12 +86,12 @@ for (let i = 0; i < 12; i++) {
|
|
|
86
86
|
const markers = union(...markerShapes).color(markerHex);
|
|
87
87
|
|
|
88
88
|
// === Clock Hands ===
|
|
89
|
-
const hourHandLength =
|
|
90
|
-
const hourHandWidth =
|
|
91
|
-
const minuteHandLength =
|
|
92
|
-
const minuteHandWidth =
|
|
93
|
-
const secondHandLength =
|
|
94
|
-
const secondHandWidth =
|
|
89
|
+
const hourHandLength = Param.number("Hour Hand Length", 55, { min: 25, max: 110, unit: "mm" });
|
|
90
|
+
const hourHandWidth = Param.number("Hour Hand Width", 10, { min: 5, max: 20, unit: "mm" });
|
|
91
|
+
const minuteHandLength = Param.number("Minute Hand Length", 80, { min: 40, max: 160, unit: "mm" });
|
|
92
|
+
const minuteHandWidth = Param.number("Minute Hand Width", 7, { min: 3, max: 14, unit: "mm" });
|
|
93
|
+
const secondHandLength = Param.number("Second Hand Length", 85, { min: 50, max: 170, unit: "mm" });
|
|
94
|
+
const secondHandWidth = Param.number("Second Hand Width", 2, { min: 1, max: 5, unit: "mm" });
|
|
95
95
|
|
|
96
96
|
// Calculate hand angles (0 degrees = 12 o'clock, clockwise)
|
|
97
97
|
const hourAngle = (hour % 12) * 30 + (minute / 60) * 30;
|
|
@@ -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
|
|
103
|
+
return roundedRect(width, length, width / 2)
|
|
104
104
|
.translate(0, length / 2)
|
|
105
105
|
.extrude(thickness)
|
|
106
|
-
.
|
|
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
|
|
125
|
+
const counter = roundedRect(counterWidth, counterLength, counterWidth / 2)
|
|
126
126
|
.translate(0, -counterLength / 2)
|
|
127
127
|
.extrude(2)
|
|
128
|
-
.
|
|
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
|
|
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
|
|
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
|
|
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);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Cup with larger top than bottom
|
|
2
2
|
|
|
3
3
|
// Parameters
|
|
4
|
-
const height =
|
|
5
|
-
const topRadius =
|
|
6
|
-
const bottomRadius =
|
|
7
|
-
const wallThickness =
|
|
8
|
-
const baseThickness =
|
|
4
|
+
const height = Param.number("Height", 80, { min: 40, max: 150, unit: "mm" });
|
|
5
|
+
const topRadius = Param.number("Top Radius", 35, { min: 20, max: 60, unit: "mm" });
|
|
6
|
+
const bottomRadius = Param.number("Bottom Radius", 25, { min: 15, max: 50, unit: "mm" });
|
|
7
|
+
const wallThickness = Param.number("Wall Thickness", 3, { min: 1, max: 8, unit: "mm" });
|
|
8
|
+
const baseThickness = Param.number("Base Thickness", 5, { min: 2, max: 10, unit: "mm" });
|
|
9
9
|
|
|
10
10
|
// Outer cup shape - tapered cylinder (truncated cone)
|
|
11
11
|
const outerCup = cylinder(height, bottomRadius, topRadius);
|