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
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Pure-SDF reference for the variableSweep taper test.
|
|
2
|
+
// If this renders with clean sidewalls while variable-sweep-test.forge.js does not,
|
|
3
|
+
// the artifact is in variableSweep()'s spine field construction rather than the
|
|
4
|
+
// shared SDF meshing pipeline.
|
|
5
|
+
|
|
6
|
+
const controlPoints = [
|
|
7
|
+
[0, 0, 0],
|
|
8
|
+
[20, 0, 10],
|
|
9
|
+
[40, 10, 20],
|
|
10
|
+
[60, 10, 30],
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const spine = spline3d(controlPoints, { tension: 0.4 });
|
|
14
|
+
const pathPoints = spine.sample(160);
|
|
15
|
+
|
|
16
|
+
const cumulativeLengths = [0];
|
|
17
|
+
for (let index = 1; index < pathPoints.length; index += 1) {
|
|
18
|
+
const [ax, ay, az] = pathPoints[index - 1];
|
|
19
|
+
const [bx, by, bz] = pathPoints[index];
|
|
20
|
+
cumulativeLengths.push(
|
|
21
|
+
cumulativeLengths[cumulativeLengths.length - 1] + Math.hypot(bx - ax, by - ay, bz - az),
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const totalLength = cumulativeLengths[cumulativeLengths.length - 1];
|
|
25
|
+
|
|
26
|
+
const smallRadius = 3;
|
|
27
|
+
const largeRadius = 8;
|
|
28
|
+
const maxRadius = largeRadius;
|
|
29
|
+
const pad = maxRadius + 4;
|
|
30
|
+
|
|
31
|
+
let minX = Infinity;
|
|
32
|
+
let minY = Infinity;
|
|
33
|
+
let minZ = Infinity;
|
|
34
|
+
let maxX = -Infinity;
|
|
35
|
+
let maxY = -Infinity;
|
|
36
|
+
let maxZ = -Infinity;
|
|
37
|
+
for (const [x, y, z] of pathPoints) {
|
|
38
|
+
minX = Math.min(minX, x);
|
|
39
|
+
minY = Math.min(minY, y);
|
|
40
|
+
minZ = Math.min(minZ, z);
|
|
41
|
+
maxX = Math.max(maxX, x);
|
|
42
|
+
maxY = Math.max(maxY, y);
|
|
43
|
+
maxZ = Math.max(maxZ, z);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const embeddedPath = JSON.stringify(pathPoints);
|
|
47
|
+
const embeddedArc = JSON.stringify(cumulativeLengths);
|
|
48
|
+
|
|
49
|
+
const pureSweepSdf = new Function(`
|
|
50
|
+
return (x, y, z) => (() => {
|
|
51
|
+
const pts = ${embeddedPath};
|
|
52
|
+
const arc = ${embeddedArc};
|
|
53
|
+
const totalLength = ${totalLength};
|
|
54
|
+
const smallRadius = ${smallRadius};
|
|
55
|
+
const largeRadius = ${largeRadius};
|
|
56
|
+
|
|
57
|
+
function clamp(v, lo, hi) {
|
|
58
|
+
return Math.max(lo, Math.min(hi, v));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function catmullScalar(p0, p1, p2, p3, t0, t1, t2, t3, t) {
|
|
62
|
+
const dt = Math.max(t2 - t1, 1e-9);
|
|
63
|
+
const local = clamp((t - t1) / dt, 0, 1);
|
|
64
|
+
const tt = local * local;
|
|
65
|
+
const ttt = tt * local;
|
|
66
|
+
const m1 = (p2 - p0) / Math.max(t2 - t0, 1e-9);
|
|
67
|
+
const m2 = (p3 - p1) / Math.max(t3 - t1, 1e-9);
|
|
68
|
+
const h00 = 2 * ttt - 3 * tt + 1;
|
|
69
|
+
const h10 = ttt - 2 * tt + local;
|
|
70
|
+
const h01 = -2 * ttt + 3 * tt;
|
|
71
|
+
const h11 = ttt - tt;
|
|
72
|
+
return h00 * p1 + h10 * dt * m1 + h01 * p2 + h11 * dt * m2;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function radiusAt(t) {
|
|
76
|
+
const tc = clamp(t, 0, 1);
|
|
77
|
+
if (tc <= 0) return smallRadius;
|
|
78
|
+
if (tc >= 1) return smallRadius;
|
|
79
|
+
if (tc <= 0.5) return catmullScalar(smallRadius, smallRadius, largeRadius, smallRadius, -0.5, 0, 0.5, 1, tc);
|
|
80
|
+
return catmullScalar(smallRadius, largeRadius, smallRadius, smallRadius, 0, 0.5, 1, 1.5, tc);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let bestDist2 = Infinity;
|
|
84
|
+
let bestIndex = 0;
|
|
85
|
+
let bestSegmentT = 0;
|
|
86
|
+
let bestPoint = pts[0];
|
|
87
|
+
|
|
88
|
+
for (let index = 0; index < pts.length - 1; index += 1) {
|
|
89
|
+
const a = pts[index];
|
|
90
|
+
const b = pts[index + 1];
|
|
91
|
+
const dx = b[0] - a[0];
|
|
92
|
+
const dy = b[1] - a[1];
|
|
93
|
+
const dz = b[2] - a[2];
|
|
94
|
+
const len2 = dx * dx + dy * dy + dz * dz;
|
|
95
|
+
if (len2 < 1e-12) continue;
|
|
96
|
+
|
|
97
|
+
const px = x - a[0];
|
|
98
|
+
const py = y - a[1];
|
|
99
|
+
const pz = z - a[2];
|
|
100
|
+
const segT = clamp((px * dx + py * dy + pz * dz) / len2, 0, 1);
|
|
101
|
+
const qx = a[0] + dx * segT;
|
|
102
|
+
const qy = a[1] + dy * segT;
|
|
103
|
+
const qz = a[2] + dz * segT;
|
|
104
|
+
const rx = x - qx;
|
|
105
|
+
const ry = y - qy;
|
|
106
|
+
const rz = z - qz;
|
|
107
|
+
const dist2 = rx * rx + ry * ry + rz * rz;
|
|
108
|
+
|
|
109
|
+
if (dist2 < bestDist2) {
|
|
110
|
+
bestDist2 = dist2;
|
|
111
|
+
bestIndex = index;
|
|
112
|
+
bestSegmentT = segT;
|
|
113
|
+
bestPoint = [qx, qy, qz];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const radiusT = (arc[bestIndex] + (arc[bestIndex + 1] - arc[bestIndex]) * bestSegmentT) / Math.max(totalLength, 1e-9);
|
|
118
|
+
let sdfValue = Math.sqrt(bestDist2) - radiusAt(radiusT);
|
|
119
|
+
|
|
120
|
+
if (bestIndex === 0 && bestSegmentT <= 1e-6) {
|
|
121
|
+
const a = pts[0];
|
|
122
|
+
const b = pts[1];
|
|
123
|
+
const dx = b[0] - a[0];
|
|
124
|
+
const dy = b[1] - a[1];
|
|
125
|
+
const dz = b[2] - a[2];
|
|
126
|
+
const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
127
|
+
if (len > 1e-9) {
|
|
128
|
+
const tx = dx / len;
|
|
129
|
+
const ty = dy / len;
|
|
130
|
+
const tz = dz / len;
|
|
131
|
+
const startCap = -((x - a[0]) * tx + (y - a[1]) * ty + (z - a[2]) * tz);
|
|
132
|
+
sdfValue = Math.max(sdfValue, startCap);
|
|
133
|
+
}
|
|
134
|
+
} else if (bestIndex === pts.length - 2 && bestSegmentT >= 1 - 1e-6) {
|
|
135
|
+
const a = pts[pts.length - 2];
|
|
136
|
+
const b = pts[pts.length - 1];
|
|
137
|
+
const dx = b[0] - a[0];
|
|
138
|
+
const dy = b[1] - a[1];
|
|
139
|
+
const dz = b[2] - a[2];
|
|
140
|
+
const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
141
|
+
if (len > 1e-9) {
|
|
142
|
+
const tx = dx / len;
|
|
143
|
+
const ty = dy / len;
|
|
144
|
+
const tz = dz / len;
|
|
145
|
+
const endCap = (x - b[0]) * tx + (y - b[1]) * ty + (z - b[2]) * tz;
|
|
146
|
+
sdfValue = Math.max(sdfValue, endCap);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return sdfValue;
|
|
151
|
+
})();
|
|
152
|
+
`)();
|
|
153
|
+
|
|
154
|
+
const tapered = sdf.fromFunction(
|
|
155
|
+
pureSweepSdf,
|
|
156
|
+
{
|
|
157
|
+
min: [minX - pad, minY - pad, minZ - pad],
|
|
158
|
+
max: [maxX + pad, maxY + pad, maxZ + pad],
|
|
159
|
+
},
|
|
160
|
+
).toShape({ edgeLength: 0.8 });
|
|
161
|
+
|
|
162
|
+
return tapered.color('#8899aa');
|
|
@@ -8,8 +8,8 @@ const spine = spline3d([
|
|
|
8
8
|
[60, 10, 30],
|
|
9
9
|
], { tension: 0.4 });
|
|
10
10
|
|
|
11
|
-
const smallCircle = circle2d(3
|
|
12
|
-
const largeCircle = circle2d(8
|
|
11
|
+
const smallCircle = circle2d(3);
|
|
12
|
+
const largeCircle = circle2d(8);
|
|
13
13
|
|
|
14
14
|
const tapered = variableSweep(spine, [
|
|
15
15
|
{ t: 0.0, profile: smallCircle },
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Wood Joinery — dado, rabbet, mortise & tenon
|
|
2
|
+
// Demonstrates joint cuts and assembled positioning.
|
|
3
|
+
|
|
4
|
+
const t = 18; // stock thickness
|
|
5
|
+
|
|
6
|
+
// ─── BOOKCASE CORNER ───────────────────────────────────────────
|
|
7
|
+
// Side panel lies flat: width=250 (X, depth), height=400 (Y, vertical), thickness=18 (Z, face)
|
|
8
|
+
const side = Wood.board(250, 400, t, { species: 'birch' });
|
|
9
|
+
const shelf = Wood.board(250, 300, t, { species: 'birch' });
|
|
10
|
+
|
|
11
|
+
// Dado: channel across the face of side for shelf to sit in
|
|
12
|
+
Wood.dado(side, shelf, { fromBottom: 150 });
|
|
13
|
+
|
|
14
|
+
// Rabbet: step on the back face for a back panel
|
|
15
|
+
Wood.rabbet(side, { edge: 'back', width: 6, depth: 9 });
|
|
16
|
+
|
|
17
|
+
// Assemble the bookcase corner:
|
|
18
|
+
// Side panel stands upright — rotate so Y (400mm) becomes vertical (Z)
|
|
19
|
+
const sideAssembled = side.shape.rotateX(90).color('#c4956a');
|
|
20
|
+
|
|
21
|
+
// Shelf sits in the dado channel
|
|
22
|
+
// After side.rotateX(90): side is in XZ plane, dado channel is at Z = -200 + 150 + 9 = -41
|
|
23
|
+
// Shelf needs its 18mm thickness edge in the dado
|
|
24
|
+
const shelfAssembled = shelf.shape
|
|
25
|
+
.rotateX(90) // stand upright
|
|
26
|
+
.rotateZ(90) // perpendicular to side
|
|
27
|
+
.translate(0, t, -200 + 150 + t / 2)
|
|
28
|
+
.color('#b8864e');
|
|
29
|
+
|
|
30
|
+
// ─── TABLE JOINT: MORTISE & TENON ──────────────────────────────
|
|
31
|
+
// Leg: width=45 (X), height=400 (Y, vertical), thickness=45 (Z, face for mortise)
|
|
32
|
+
// The mortise cuts into Z (45mm face), positioned along Y (400mm height)
|
|
33
|
+
const leg = Wood.board(45, 400, 45, { species: 'oak' });
|
|
34
|
+
const apron = Wood.board(300, 80, 20, { species: 'oak' });
|
|
35
|
+
|
|
36
|
+
Wood.mortiseAndTenon(leg, apron, {
|
|
37
|
+
style: 'blind',
|
|
38
|
+
position: { fromTop: 25 },
|
|
39
|
+
cornerRadius: 4,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Tenon defaults: thickness = 20/3 ≈ 6.7mm, width = min(48, 320) = 48mm, length = 45*2/3 = 30mm
|
|
43
|
+
|
|
44
|
+
// Assemble: leg stands on its Y-axis (already vertical), apron connects to face
|
|
45
|
+
const legAssembled = leg.shape
|
|
46
|
+
.translate(500, 0, 0)
|
|
47
|
+
.color('#a07040');
|
|
48
|
+
|
|
49
|
+
// Apron: tenon protrudes from +X end. Rotate so it points into the leg's Z-face.
|
|
50
|
+
const apronAssembled = apron.shape
|
|
51
|
+
.rotateY(90) // tenon now points +Z (into leg face)
|
|
52
|
+
.translate(500, 200 - 25 - 24, 45) // align with mortise position on leg
|
|
53
|
+
.color('#8b6030');
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
{ name: 'Side (dado + rabbet)', shape: sideAssembled },
|
|
57
|
+
{ name: 'Shelf', shape: shelfAssembled },
|
|
58
|
+
{ name: 'Leg (mortise)', shape: legAssembled },
|
|
59
|
+
{ name: 'Apron (tenon)', shape: apronAssembled },
|
|
60
|
+
];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Guard part: shell + face-driven cuts + mirrored feet in one ordinary enclosure workflow.
|
|
2
2
|
|
|
3
|
-
const base = roundedRect(120, 80, 10
|
|
3
|
+
const base = roundedRect(120, 80, 10).extrude(36);
|
|
4
4
|
const shell = base.shell(3, { openFaces: ['top'] });
|
|
5
5
|
|
|
6
|
-
const displayCut = roundedRect(34, 18, 3
|
|
6
|
+
const displayCut = roundedRect(34, 18, 3)
|
|
7
7
|
.onFace(base, 'front', { u: 0, v: 8, protrude: 0.25, selfAnchor: 'center' })
|
|
8
8
|
.extrude(10);
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ const cableCut = circle2d(7)
|
|
|
11
11
|
.onFace(base, 'right', { u: -12, v: -8, protrude: 0.25, selfAnchor: 'center' })
|
|
12
12
|
.extrude(10);
|
|
13
13
|
|
|
14
|
-
const foot = roundedRect(18, 18, 4
|
|
14
|
+
const foot = roundedRect(18, 18, 4)
|
|
15
15
|
.onFace(base, 'bottom', { u: 36, v: 20, protrude: 0, selfAnchor: 'center' })
|
|
16
16
|
.extrude(6);
|
|
17
17
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Guard part: counterbore/countersink hole variants plus an up-to-face service pocket in one ordinary plate workflow.
|
|
2
2
|
|
|
3
|
-
const plate = roundedRect(118, 76, 8
|
|
3
|
+
const plate = roundedRect(118, 76, 8).extrude(18);
|
|
4
4
|
const entryFace = plate.face('top');
|
|
5
5
|
const exitFace = plate.face('bottom');
|
|
6
6
|
const pocketExitFace = plate.face('side-top');
|
|
7
7
|
|
|
8
|
-
const servicePocket = roundedRect(34, 18, 4
|
|
8
|
+
const servicePocket = roundedRect(34, 18, 4)
|
|
9
9
|
.onFace(plate, 'front', { u: 0, v: -2, selfAnchor: 'center' });
|
|
10
10
|
|
|
11
11
|
const fastenerPlate = plate
|
|
@@ -21,7 +21,7 @@ sk.horizontal(bottom);
|
|
|
21
21
|
sk.vertical(right);
|
|
22
22
|
sk.parallel(bottom, top);
|
|
23
23
|
sk.parallel(right, left);
|
|
24
|
-
sk.length(bottom,
|
|
25
|
-
sk.length(right,
|
|
24
|
+
sk.length(bottom, Param.number("width", 40, { unit: "mm" }));
|
|
25
|
+
sk.length(right, Param.number("height", 30, { unit: "mm" }));
|
|
26
26
|
|
|
27
27
|
return sk.solve();
|
|
@@ -24,7 +24,7 @@ sk.absoluteAngle(lBottom, 0); // line must be at 0 degrees (= horizontal)
|
|
|
24
24
|
sk.vertical(lRight);
|
|
25
25
|
sk.vertical(lLeft);
|
|
26
26
|
sk.horizontal(lTop);
|
|
27
|
-
sk.length(lBottom,
|
|
28
|
-
sk.length(lRight,
|
|
27
|
+
sk.length(lBottom, Param.number("width", 10, { unit: "mm" }));
|
|
28
|
+
sk.length(lRight, Param.number("height", 5, { unit: "mm" }));
|
|
29
29
|
|
|
30
30
|
return sk.solve();
|
|
@@ -20,10 +20,10 @@ sk.addLoop([p1, p2, p4, p3]);
|
|
|
20
20
|
sk.fix(p1);
|
|
21
21
|
sk.horizontal(bottom);
|
|
22
22
|
sk.vertical(left);
|
|
23
|
-
sk.length(bottom,
|
|
23
|
+
sk.length(bottom, Param.number("width", 20, { unit: "mm" }));
|
|
24
24
|
|
|
25
25
|
// lineDistance already implies parallel:
|
|
26
|
-
sk.lineDistance(bottom, top,
|
|
26
|
+
sk.lineDistance(bottom, top, Param.number("height", 10, { unit: "mm" }));
|
|
27
27
|
sk.parallel(bottom, top); // redundant — lineDistance already forces parallel
|
|
28
28
|
|
|
29
29
|
sk.parallel(left, right);
|
|
@@ -20,9 +20,9 @@ sk.absoluteAngle(l1, 0);
|
|
|
20
20
|
sk.perpendicular(l1, l2);
|
|
21
21
|
sk.perpendicular(l2, l3);
|
|
22
22
|
sk.perpendicular(l3, l4);
|
|
23
|
-
sk.length(l1,
|
|
24
|
-
sk.length(l2,
|
|
25
|
-
sk.length(l3,
|
|
26
|
-
sk.length(l4,
|
|
23
|
+
sk.length(l1, Param.number("seg1", 20, { unit: "mm" }));
|
|
24
|
+
sk.length(l2, Param.number("seg2", 15, { unit: "mm" }));
|
|
25
|
+
sk.length(l3, Param.number("seg3", 15, { unit: "mm" }));
|
|
26
|
+
sk.length(l4, Param.number("seg4", 15, { unit: "mm" }));
|
|
27
27
|
|
|
28
28
|
return sk.solve();
|
|
@@ -47,9 +47,9 @@ sk.vertical(lLeft);
|
|
|
47
47
|
sk.horizontal(lLeftTop);
|
|
48
48
|
sk.vertical(lLeftUp);
|
|
49
49
|
|
|
50
|
-
sk.length(lBottom,
|
|
51
|
-
sk.length(lLeft,
|
|
52
|
-
sk.length(lLeftTop,
|
|
53
|
-
sk.length(lLeftUp,
|
|
50
|
+
sk.length(lBottom, Param.number("base_width", 50, { unit: "mm" }));
|
|
51
|
+
sk.length(lLeft, Param.number("leg_height", 20, { unit: "mm" }));
|
|
52
|
+
sk.length(lLeftTop, Param.number("step_width", 15, { unit: "mm" }));
|
|
53
|
+
sk.length(lLeftUp, Param.number("top_height", 20, { unit: "mm" }));
|
|
54
54
|
|
|
55
55
|
return sk.solve();
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const sk = constrainedSketch();
|
|
7
7
|
|
|
8
8
|
const N = 50; // number of segments
|
|
9
|
-
const SEG_LEN =
|
|
9
|
+
const SEG_LEN = Param.number("seg_len", 5, { unit: "mm" });
|
|
10
10
|
|
|
11
11
|
// Build a spiral: each segment turns 90° left from the previous,
|
|
12
12
|
// with increasing runs (1,1,2,2,3,3,4,4,...) to form a square spiral.
|
|
@@ -8,7 +8,7 @@ const sk = constrainedSketch();
|
|
|
8
8
|
|
|
9
9
|
const COLS = 3;
|
|
10
10
|
const ROWS = 2;
|
|
11
|
-
const SIDE =
|
|
11
|
+
const SIDE = Param.number("cell_size", 8, { unit: "mm" });
|
|
12
12
|
|
|
13
13
|
// Flat-top hex: vertex 0 at 0° (right), CCW
|
|
14
14
|
const vAngles = [0, 60, 120, 180, 240, 300].map(d => d * Math.PI / 180);
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
const sk = constrainedSketch();
|
|
8
8
|
|
|
9
|
-
const W =
|
|
10
|
-
const H =
|
|
9
|
+
const W = Param.number("width", 150, { unit: "mm" });
|
|
10
|
+
const H = Param.number("height", 100, { unit: "mm" });
|
|
11
11
|
|
|
12
12
|
// Outer box corners
|
|
13
13
|
const p00 = sk.point(0, 0);
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
const sk = constrainedSketch();
|
|
8
8
|
|
|
9
|
-
const OW =
|
|
10
|
-
const OH =
|
|
11
|
-
const IW =
|
|
12
|
-
const IH =
|
|
9
|
+
const OW = Param.number("outer_w", 120, { unit: "mm" });
|
|
10
|
+
const OH = Param.number("outer_h", 100, { unit: "mm" });
|
|
11
|
+
const IW = Param.number("inner_w", 60, { unit: "mm" });
|
|
12
|
+
const IH = Param.number("inner_h", 50, { unit: "mm" });
|
|
13
13
|
|
|
14
14
|
// Outer rectangle
|
|
15
15
|
const o1 = sk.point(0, 0);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Bearing housing with exact circular arc (not polyline-approximated)
|
|
2
|
+
const profile = path()
|
|
3
|
+
.moveTo(0, 0)
|
|
4
|
+
.lineTo(50, 0)
|
|
5
|
+
.lineTo(50, 10)
|
|
6
|
+
.exactArcTo(40, 20, { radius: 10 })
|
|
7
|
+
.lineTo(0, 20)
|
|
8
|
+
.close();
|
|
9
|
+
|
|
10
|
+
const housing = profile.extrude(30);
|
|
11
|
+
const bore = cylinder(30, 8).translate(25, 10, 0);
|
|
12
|
+
return difference(housing, bore);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Smooth drone arm: flat rectangular mount → organic taper → circular motor mount
|
|
2
|
+
// Tests: cross-section morphing, S-curve sweep, shell, G2 transitions
|
|
3
|
+
|
|
4
|
+
// --- Spine: gentle S-curve from origin to motor mount ---
|
|
5
|
+
const armLength = 120;
|
|
6
|
+
const spine = spline3d([
|
|
7
|
+
[0, 0, 0],
|
|
8
|
+
[armLength * 0.3, 0, 8],
|
|
9
|
+
[armLength * 0.7, 0, -5],
|
|
10
|
+
[armLength, 0, 3],
|
|
11
|
+
], { tension: 0.3 });
|
|
12
|
+
|
|
13
|
+
// --- Cross-sections ---
|
|
14
|
+
|
|
15
|
+
// Mount end: flat rectangle with rounded corners
|
|
16
|
+
const mountProfile = roundedRect(20, 6, 1.5);
|
|
17
|
+
|
|
18
|
+
// Mid-section: transitional rounded rectangle
|
|
19
|
+
const midProfile = roundedRect(14, 10, 4);
|
|
20
|
+
|
|
21
|
+
// Motor end: circle
|
|
22
|
+
const motorProfile = circle2d(8);
|
|
23
|
+
|
|
24
|
+
// --- Variable sweep: morph between profiles along spine ---
|
|
25
|
+
const solidArm = variableSweep(spine, [
|
|
26
|
+
{ t: 0, profile: mountProfile },
|
|
27
|
+
{ t: 0.4, profile: midProfile },
|
|
28
|
+
{ t: 1, profile: motorProfile },
|
|
29
|
+
], { edgeLength: 1.5 });
|
|
30
|
+
|
|
31
|
+
// --- Hollow it out ---
|
|
32
|
+
const arm = solidArm.shell(1.5);
|
|
33
|
+
|
|
34
|
+
// --- Mounting holes at the flat end ---
|
|
35
|
+
const mountHole = cylinder(10, 2).translate(0, 0, -5);
|
|
36
|
+
const mountHoles = union(
|
|
37
|
+
mountHole.translate(-6, 0, 0),
|
|
38
|
+
mountHole.translate(6, 0, 0),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// --- Motor mount ring at the far end ---
|
|
42
|
+
// Place at the end of the spine
|
|
43
|
+
const motorRing = difference(
|
|
44
|
+
cylinder(4, 10),
|
|
45
|
+
cylinder(4, 7),
|
|
46
|
+
).translate(armLength, 0, 3);
|
|
47
|
+
|
|
48
|
+
const result = difference(
|
|
49
|
+
union(arm, motorRing),
|
|
50
|
+
mountHoles,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return result;
|
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
// BUILD NOTES (at bottom of file):
|
|
6
6
|
// Materials, dimensions, and assembly instructions for actually building this.
|
|
7
7
|
|
|
8
|
-
const topW =
|
|
9
|
-
const topD =
|
|
10
|
-
const topThick =
|
|
11
|
-
const minH =
|
|
12
|
-
const maxH =
|
|
13
|
-
const heightPct =
|
|
14
|
-
const outerLeg =
|
|
15
|
-
const innerLeg =
|
|
16
|
-
const legWall =
|
|
17
|
-
const inset =
|
|
18
|
-
const braceW =
|
|
19
|
-
const braceH =
|
|
20
|
-
const crankR =
|
|
8
|
+
const topW = Param.number("Top Width", 120, { min: 80, max: 200, unit: "cm" });
|
|
9
|
+
const topD = Param.number("Top Depth", 60, { min: 40, max: 100, unit: "cm" });
|
|
10
|
+
const topThick = Param.number("Top Thickness", 3, { min: 2, max: 5, unit: "cm" });
|
|
11
|
+
const minH = Param.number("Min Height", 72, { min: 60, max: 80, unit: "cm" });
|
|
12
|
+
const maxH = Param.number("Max Height", 120, { min: 100, max: 140, unit: "cm" });
|
|
13
|
+
const heightPct = Param.number("Height %", 30, { min: 0, max: 100, unit: "%" });
|
|
14
|
+
const outerLeg = Param.number("Outer Leg", 6, { min: 4, max: 10, unit: "cm" });
|
|
15
|
+
const innerLeg = Param.number("Inner Leg", 4, { min: 3, max: 8, unit: "cm" });
|
|
16
|
+
const legWall = Param.number("Leg Wall", 0.3, { min: 0.2, max: 0.5, unit: "cm" });
|
|
17
|
+
const inset = Param.number("Leg Inset", 5, { min: 2, max: 15, unit: "cm" });
|
|
18
|
+
const braceW = Param.number("Brace Width", 3, { min: 2, max: 5, unit: "cm" });
|
|
19
|
+
const braceH = Param.number("Brace Height", 1.5, { min: 1, max: 3, unit: "cm" });
|
|
20
|
+
const crankR = Param.number("Crank Radius", 8, { min: 5, max: 15, unit: "cm" });
|
|
21
21
|
|
|
22
22
|
// Current height based on slider
|
|
23
23
|
const currentH = minH + (maxH - minH) * heightPct / 100;
|
|
@@ -75,7 +75,7 @@ for (const [lx, ly] of legPositions) {
|
|
|
75
75
|
// Through-hole in Y direction
|
|
76
76
|
pinHoles.push(
|
|
77
77
|
cylinder(outerLeg + 2, pinHoleR)
|
|
78
|
-
.
|
|
78
|
+
.rotateX(90)
|
|
79
79
|
.translate(legCenterX, ly - 1, pz)
|
|
80
80
|
);
|
|
81
81
|
}
|
|
@@ -105,7 +105,7 @@ const shaftY = inset + outerLeg / 2;
|
|
|
105
105
|
const shaftZ = legH - outerLegH + 25;
|
|
106
106
|
const shaftLen = topW - 2 * inset;
|
|
107
107
|
const shaft = cylinder(shaftLen, 0.8)
|
|
108
|
-
.
|
|
108
|
+
.rotateY(90)
|
|
109
109
|
.translate(inset, shaftY, shaftZ);
|
|
110
110
|
|
|
111
111
|
// Crank handle (on the right side)
|