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
|
@@ -7,17 +7,17 @@ const size = 25;
|
|
|
7
7
|
const gap = 5;
|
|
8
8
|
|
|
9
9
|
// --- Three colored boxes ---
|
|
10
|
-
const red = box(size, size, size
|
|
11
|
-
const green = box(size, size, size
|
|
12
|
-
const blue = box(size, size, size
|
|
10
|
+
const red = box(size, size, size).color('#cc4444');
|
|
11
|
+
const green = box(size, size, size).color('#44cc44').translate(size + gap, 0, 0);
|
|
12
|
+
const blue = box(size, size, size).color('#4444cc').translate(2 * (size + gap), 0, 0);
|
|
13
13
|
|
|
14
14
|
// BAD: union kills individual colors — result is all red (first shape's color)
|
|
15
15
|
const merged = union(red, green, blue).translate(-80, 0, 0);
|
|
16
16
|
|
|
17
17
|
// GOOD: separate objects keep their colors
|
|
18
|
-
const redSep = box(size, size, size
|
|
19
|
-
const greenSep = box(size, size, size
|
|
20
|
-
const blueSep = box(size, size, size
|
|
18
|
+
const redSep = box(size, size, size).color('#cc4444').translate(80, 0, 0);
|
|
19
|
+
const greenSep = box(size, size, size).color('#44cc44').translate(80 + size + gap, 0, 0);
|
|
20
|
+
const blueSep = box(size, size, size).color('#4444cc').translate(80 + 2 * (size + gap), 0, 0);
|
|
21
21
|
|
|
22
22
|
return [
|
|
23
23
|
{ name: "❌ Union (all one color)", shape: merged },
|
|
@@ -9,20 +9,22 @@ const doorW = 60, doorH = 100, doorT = 4;
|
|
|
9
9
|
const frameT = 8, frameD = 10;
|
|
10
10
|
|
|
11
11
|
// ── Door with hinge connectors ─────────────────────────────────────────────
|
|
12
|
+
// Hinge axes point "outward" from each part. When connectors mate,
|
|
13
|
+
// they meet face-to-face (anti-parallel), producing the shared rotation axis.
|
|
12
14
|
|
|
13
|
-
const door = box(doorW, doorT, doorH
|
|
15
|
+
const door = box(doorW, doorT, doorH)
|
|
14
16
|
.translate(doorW / 2, 0, 0)
|
|
15
17
|
.withConnectors({
|
|
16
18
|
hinge_top: connector.male("hinge_pin", {
|
|
17
19
|
origin: [0, 0, doorH * 0.3],
|
|
18
|
-
axis: [0, 0, 1],
|
|
20
|
+
axis: [0, 0, -1],
|
|
19
21
|
kind: "revolute",
|
|
20
22
|
min: 0,
|
|
21
23
|
max: 110,
|
|
22
24
|
}),
|
|
23
25
|
hinge_bottom: connector.male("hinge_pin", {
|
|
24
26
|
origin: [0, 0, -doorH * 0.3],
|
|
25
|
-
axis: [0, 0, 1],
|
|
27
|
+
axis: [0, 0, -1],
|
|
26
28
|
kind: "revolute",
|
|
27
29
|
min: 0,
|
|
28
30
|
max: 110,
|
|
@@ -32,11 +34,11 @@ const door = box(doorW, doorT, doorH, true)
|
|
|
32
34
|
|
|
33
35
|
// ── Frame with matching hinge connectors ───────────────────────────────────
|
|
34
36
|
|
|
35
|
-
const leftPost = box(frameT, frameD, doorH + frameT
|
|
37
|
+
const leftPost = box(frameT, frameD, doorH + frameT)
|
|
36
38
|
.translate(-(doorW / 2 + frameT / 2), 0, frameT / 4);
|
|
37
|
-
const rightPost = box(frameT, frameD, doorH + frameT
|
|
39
|
+
const rightPost = box(frameT, frameD, doorH + frameT)
|
|
38
40
|
.translate(doorW / 2 + frameT / 2, 0, frameT / 4);
|
|
39
|
-
const lintel = box(doorW + frameT * 2, frameD, frameT
|
|
41
|
+
const lintel = box(doorW + frameT * 2, frameD, frameT)
|
|
40
42
|
.translate(0, 0, doorH / 2 + frameT / 2);
|
|
41
43
|
|
|
42
44
|
const frame = union(leftPost, rightPost, lintel)
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
// - matchTo() single-pair connector matching
|
|
7
7
|
// - Auto-bubbling: connectors on named group children are accessible via "ChildName.connectorName"
|
|
8
8
|
|
|
9
|
-
const panelH =
|
|
10
|
-
const panelD =
|
|
11
|
-
const panelT =
|
|
12
|
-
const shelfCount =
|
|
13
|
-
const cabinetW =
|
|
9
|
+
const panelH = Param.number("Panel Height", 200, { min: 100, max: 400, unit: "mm" });
|
|
10
|
+
const panelD = Param.number("Panel Depth", 120, { min: 60, max: 200, unit: "mm" });
|
|
11
|
+
const panelT = Param.number("Panel Thickness", 12, { unit: "mm" });
|
|
12
|
+
const shelfCount = Param.number("Shelves", 3, { min: 1, max: 6 });
|
|
13
|
+
const cabinetW = Param.number("Cabinet Width", 180, { min: 100, max: 400, unit: "mm" });
|
|
14
14
|
|
|
15
15
|
// ── Side Panel with shelf slots ────────────────────────────────────────────
|
|
16
16
|
|
|
17
17
|
function makeSidePanel(facingDir) {
|
|
18
|
-
const panel = box(panelT, panelD, panelH
|
|
18
|
+
const panel = box(panelT, panelD, panelH);
|
|
19
19
|
const connectors = {};
|
|
20
20
|
|
|
21
21
|
for (let i = 0; i < shelfCount; i++) {
|
|
@@ -47,7 +47,7 @@ console.log("Cabinet connectors:", cabinet.connectorNames());
|
|
|
47
47
|
|
|
48
48
|
const shelfW = cabinetW - panelT;
|
|
49
49
|
const shelfT = 10;
|
|
50
|
-
const shelf = box(shelfW, panelD - 10, shelfT
|
|
50
|
+
const shelf = box(shelfW, panelD - 10, shelfT)
|
|
51
51
|
.withConnectors({
|
|
52
52
|
left_tab: connector.male("dovetail", {
|
|
53
53
|
origin: [-shelfW / 2, 0, 0],
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
* 4. Connecting rod — constrained trapezoid with symmetric sides
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
const W =
|
|
15
|
-
const H =
|
|
16
|
-
const T =
|
|
17
|
-
const R =
|
|
14
|
+
const W = Param.number('width', 60, { min: 30, max: 120, unit: 'mm' });
|
|
15
|
+
const H = Param.number('height', 40, { min: 20, max: 80, unit: 'mm' });
|
|
16
|
+
const T = Param.number('thick', 8, { min: 3, max: 20, unit: 'mm' });
|
|
17
|
+
const R = Param.number('radius', 10, { min: 5, max: 25, unit: 'mm' });
|
|
18
18
|
|
|
19
19
|
// ─── 1. Slotted plate ─────────────────────────────────────────────────────────
|
|
20
20
|
const slottedPlate = (() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Test lib.elbow() — pipe bend primitive
|
|
2
|
-
const pipeR =
|
|
3
|
-
const bendR =
|
|
4
|
-
const angle =
|
|
2
|
+
const pipeR = Param.number("Pipe Radius", 5, { min: 2, max: 15, unit: "mm" });
|
|
3
|
+
const bendR = Param.number("Bend Radius", 25, { min: 10, max: 60, unit: "mm" });
|
|
4
|
+
const angle = Param.number("Angle", 90, { min: 15, max: 180, unit: "°" });
|
|
5
5
|
|
|
6
6
|
// Basic elbow at default orientation
|
|
7
7
|
const basic = lib.elbow(pipeR, bendR, angle).color('#B87333');
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// Extrude options — twist, taper,
|
|
1
|
+
// Extrude options — twist, taper, scaleTop.
|
|
2
2
|
//
|
|
3
3
|
// .extrude(height) is the basic form.
|
|
4
|
-
// Options: { twist, divisions, scaleTop
|
|
4
|
+
// Options: { twist, divisions, scaleTop }
|
|
5
5
|
|
|
6
|
-
const r =
|
|
7
|
-
const h =
|
|
8
|
-
const twist =
|
|
9
|
-
const taper =
|
|
6
|
+
const r = Param.number("Radius", 20, { min: 10, max: 40, unit: "mm" });
|
|
7
|
+
const h = Param.number("Height", 60, { min: 20, max: 120, unit: "mm" });
|
|
8
|
+
const twist = Param.number("Twist", 90, { min: 0, max: 360, unit: "°" });
|
|
9
|
+
const taper = Param.number("Taper", 0.5, { min: 0.1, max: 1.0 });
|
|
10
10
|
const spacing = 60;
|
|
11
11
|
|
|
12
12
|
// 1. Plain extrude
|
|
@@ -23,22 +23,16 @@ const tapered = circle2d(r).extrude(h, { scaleTop: taper })
|
|
|
23
23
|
.translate(2 * spacing, 0, 0)
|
|
24
24
|
.color('#44cc88');
|
|
25
25
|
|
|
26
|
-
// 4.
|
|
27
|
-
const centered = rect(r * 1.5, r, true).extrude(h, { center: true })
|
|
28
|
-
.translate(3 * spacing, 0, 0)
|
|
29
|
-
.color('#cc44cc');
|
|
30
|
-
|
|
31
|
-
// 5. Combined: twist + taper
|
|
26
|
+
// 4. Combined: twist + taper
|
|
32
27
|
const combo = star(5, r, r * 0.5).extrude(h, {
|
|
33
28
|
twist: twist,
|
|
34
29
|
scaleTop: taper,
|
|
35
30
|
divisions: 32,
|
|
36
|
-
}).translate(
|
|
31
|
+
}).translate(3 * spacing, 0, 0).color('#cccc44');
|
|
37
32
|
|
|
38
33
|
return [
|
|
39
34
|
{ name: "Plain", shape: plain },
|
|
40
35
|
{ name: "Twisted", shape: twisted },
|
|
41
36
|
{ name: "Tapered", shape: tapered },
|
|
42
|
-
{ name: "Centered (Z)", shape: centered },
|
|
43
37
|
{ name: "Twist + Taper", shape: combo },
|
|
44
38
|
];
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
const shellBase = roundedRect(90, 56, 6
|
|
1
|
+
const shellBase = roundedRect(90, 56, 6).extrude(28);
|
|
2
2
|
const cup = shellBase.shell(2.5, { openFaces: ['top'] }).color('#6f7b86');
|
|
3
|
-
const innerWallPad = roundedRect(16, 9, 1.8
|
|
3
|
+
const innerWallPad = roundedRect(16, 9, 1.8)
|
|
4
4
|
.onFace(cup, 'inner-side-right', { u: 0, v: -3, protrude: 0.05, selfAnchor: 'center' })
|
|
5
5
|
.extrude(1.4)
|
|
6
|
-
// .toShape()
|
|
7
6
|
.color('#f2b16a');
|
|
8
7
|
|
|
9
|
-
const holeBase = roundedRect(72, 44, 5
|
|
8
|
+
const holeBase = roundedRect(72, 44, 5).extrude(20);
|
|
10
9
|
const drilled = holeBase.hole('top', { diameter: 8, u: 16, v: -8, depth: 10 }).color('#7a8792');
|
|
11
10
|
const floorBoss = circle2d(3)
|
|
12
11
|
.onFace(drilled, 'floor', { u: 0, v: 0, protrude: 0.05, selfAnchor: 'center' })
|
|
13
12
|
.extrude(1.2)
|
|
14
|
-
// .toShape()
|
|
15
13
|
.color('#d46452');
|
|
16
14
|
|
|
17
|
-
const counterboreBase = roundedRect(72, 44, 5
|
|
15
|
+
const counterboreBase = roundedRect(72, 44, 5).extrude(20);
|
|
18
16
|
const counterboreExitFace = counterboreBase.face('bottom');
|
|
19
17
|
const counterbored = counterboreBase.hole('top', {
|
|
20
18
|
diameter: 6,
|
|
@@ -26,17 +24,15 @@ const counterbored = counterboreBase.hole('top', {
|
|
|
26
24
|
const shoulderPad = rect(4, 3)
|
|
27
25
|
.onFace(counterbored, 'counterbore-floor', { u: 0, v: 0, protrude: 0.05, selfAnchor: 'center' })
|
|
28
26
|
.extrude(0.9)
|
|
29
|
-
// .toShape()
|
|
30
27
|
.color('#f0c36c');
|
|
31
28
|
|
|
32
|
-
const cutBase = roundedRect(78, 46, 5
|
|
33
|
-
const pocket = roundedRect(20, 12, 2
|
|
29
|
+
const cutBase = roundedRect(78, 46, 5).extrude(22);
|
|
30
|
+
const pocket = roundedRect(20, 12, 2)
|
|
34
31
|
.onFace(cutBase, 'front', { u: 0, v: 4, selfAnchor: 'center' });
|
|
35
32
|
const cut = cutBase.cutout(pocket, { depth: 8 }).color('#64707d');
|
|
36
33
|
const wallTab = rect(5, 4)
|
|
37
34
|
.onFace(cut, 'wall-right', { u: 0, v: 0, protrude: 0.05, selfAnchor: 'center' })
|
|
38
35
|
.extrude(1)
|
|
39
|
-
// .toShape()
|
|
40
36
|
.color('#5ba6d6');
|
|
41
37
|
|
|
42
38
|
return [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Fillet Showcase — the new fillet() API
|
|
2
2
|
// Demonstrates: fillet(), edge queries, multi-edge, curved edges
|
|
3
3
|
|
|
4
|
-
const r =
|
|
4
|
+
const r = Param.number("Fillet Radius", 3, { min: 0.5, max: 8, unit: "mm" });
|
|
5
5
|
|
|
6
6
|
// ── 1. Basic: fillet all edges of a box ─────────────────────────────────────
|
|
7
7
|
const simpleBox = box(30, 20, 15);
|
|
@@ -16,7 +16,7 @@ const vertFilleted = fillet(tallBox, r, { parallel: [0, 0, 1], convex: true });
|
|
|
16
16
|
|
|
17
17
|
// ── 4. Boolean result: fillet the sharp edges after a cut ────────────────────
|
|
18
18
|
const base = box(40, 30, 20);
|
|
19
|
-
const cutter = cylinder(25, 10, 10, 32
|
|
19
|
+
const cutter = cylinder(25, 10, 10, 32).translate(20, 15, 10);
|
|
20
20
|
const cutPart = difference(base, cutter);
|
|
21
21
|
const cutFilleted = fillet(cutPart, 2, { convex: true, minLength: 3 });
|
|
22
22
|
|
|
@@ -40,8 +40,8 @@ export function buildFoldedServicePanelCoverPart() {
|
|
|
40
40
|
.flange('right', { length: 18, angleDeg: 90 })
|
|
41
41
|
.flange('bottom', { length: 18, angleDeg: 90 })
|
|
42
42
|
.flange('left', { length: 18, angleDeg: 90 })
|
|
43
|
-
.cutout('panel', rect(72, 36
|
|
44
|
-
.cutout('flange-right', roundedRect(26, 10, 5
|
|
43
|
+
.cutout('panel', rect(72, 36), { selfAnchor: 'center' })
|
|
44
|
+
.cutout('flange-right', roundedRect(26, 10, 5), { selfAnchor: 'center' });
|
|
45
45
|
|
|
46
46
|
const holes = [
|
|
47
47
|
mountingHole(2.2, -68, -37),
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Tier 1 gears demo: spur pair + ring gear + rack gear
|
|
2
2
|
|
|
3
|
-
const moduleSize =
|
|
4
|
-
const pinionTeeth =
|
|
5
|
-
const drivenTeeth =
|
|
6
|
-
const backlash =
|
|
7
|
-
const faceWidth =
|
|
3
|
+
const moduleSize = Param.number("Module", 1.25, { min: 0.6, max: 3.0, step: 0.05 });
|
|
4
|
+
const pinionTeeth = Param.number("Pinion Teeth", 14, { min: 8, max: 28, integer: true });
|
|
5
|
+
const drivenTeeth = Param.number("Driven Teeth", 42, { min: 16, max: 90, integer: true });
|
|
6
|
+
const backlash = Param.number("Backlash", 0.05, { min: 0, max: 0.2, step: 0.01, unit: "mm" });
|
|
7
|
+
const faceWidth = Param.number("Face Width", 10, { min: 4, max: 18, unit: "mm" });
|
|
8
8
|
|
|
9
9
|
const pair = lib.gearPair({
|
|
10
10
|
pinion: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Test assembly grouping — nested group format
|
|
2
|
-
const baseW =
|
|
3
|
-
const baseD =
|
|
2
|
+
const baseW = Param.number("Base Width", 100, { min: 60, max: 200, unit: "mm" });
|
|
3
|
+
const baseD = Param.number("Base Depth", 80, { min: 40, max: 150, unit: "mm" });
|
|
4
4
|
|
|
5
5
|
// Bed assembly
|
|
6
6
|
const bedPlate = box(baseW, baseD, 5).color('#666666');
|
|
@@ -14,7 +14,7 @@ const crossBar = box(baseW + 20, 5, 5).translate(-10, baseD / 2, 63).color('#aaa
|
|
|
14
14
|
|
|
15
15
|
// Extruder (intentionally overlaps crossbar — intra-group collision)
|
|
16
16
|
const nozzle = cylinder(15, 4).translate(baseW / 2, baseD / 2, 48).color('#ff8800');
|
|
17
|
-
const heatsink = box(20, 20, 10
|
|
17
|
+
const heatsink = box(20, 20, 10).translate(baseW / 2, baseD / 2, 60).color('#cccccc');
|
|
18
18
|
|
|
19
19
|
return [
|
|
20
20
|
{ name: "Bed Assembly", group: [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Use union when you need a single solid (e.g., to subtract from something).
|
|
7
7
|
// Use group when you want parts to move together but stay visually distinct.
|
|
8
8
|
|
|
9
|
-
const base = box(60, 60, 5
|
|
9
|
+
const base = box(60, 60, 5).color('#888888');
|
|
10
10
|
const col = cylinder(30, 5).color('#cc4444')
|
|
11
11
|
.attachTo(base, 'top', 'bottom');
|
|
12
12
|
|
|
@@ -29,4 +29,8 @@ highlight(b.edge('top-right'), { color: 'blue', label: 'top-right edge' });
|
|
|
29
29
|
// Shape highlight — transparent colored overlay on the entire shape
|
|
30
30
|
highlight(b, { color: '#ff00ff' });
|
|
31
31
|
|
|
32
|
+
// Intermediary shape highlight — snapshot a temporary shape that is not returned
|
|
33
|
+
const temporary = b.translate(40, 0, 0);
|
|
34
|
+
highlight(temporary, { color: '#00ffff', label: 'temporary snapshot' });
|
|
35
|
+
|
|
32
36
|
return b;
|
|
@@ -16,7 +16,7 @@ export default class PillarPair {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
build() {
|
|
19
|
-
const pillar = box(6, 6, this.height
|
|
19
|
+
const pillar = box(6, 6, this.height);
|
|
20
20
|
return union(
|
|
21
21
|
pillar.translate(-this.spacing / 2, 0, this.height / 2),
|
|
22
22
|
pillar.translate(this.spacing / 2, 0, this.height / 2),
|
|
@@ -2,8 +2,8 @@ import { box, union } from "forgecad";
|
|
|
2
2
|
import PillarPair, { capHeight } from "./js-module-pillars.js";
|
|
3
3
|
|
|
4
4
|
export function buildAssembly() {
|
|
5
|
-
const base = box(40, 18, 4
|
|
5
|
+
const base = box(40, 18, 4);
|
|
6
6
|
const pillars = new PillarPair(24, 12).build().translate(0, 0, 2);
|
|
7
|
-
const cap = box(14, 18, capHeight
|
|
7
|
+
const cap = box(14, 18, capHeight).translate(0, 0, 17);
|
|
8
8
|
return union(base, pillars, cap).color("#d6a86a");
|
|
9
9
|
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// Imports an external STL mesh and intersects it with a parametric
|
|
4
4
|
// slat pattern to create a layered sculpture effect.
|
|
5
5
|
|
|
6
|
-
const slatCount =
|
|
7
|
-
const slatThickness =
|
|
8
|
-
const gap =
|
|
6
|
+
const slatCount = Param.number("Slat count", 16, { min: 4, max: 40 });
|
|
7
|
+
const slatThickness = Param.number("Slat thickness", 1.2, { min: 0.4, max: 3, unit: "mm" });
|
|
8
|
+
const gap = Param.number("Gap", 1.5, { min: 0.5, max: 5, unit: "mm" });
|
|
9
9
|
|
|
10
10
|
// Import an external mesh file
|
|
11
11
|
const mesh = importMesh("assets/sphere.stl");
|
|
@@ -19,7 +19,7 @@ const slats = [];
|
|
|
19
19
|
for (let i = 0; i < slatCount; i++) {
|
|
20
20
|
const y = center[1] - (slatCount - 1) * pitch / 2 + i * pitch;
|
|
21
21
|
slats.push(
|
|
22
|
-
box(size[0] + 10, slatThickness, size[2] + 10
|
|
22
|
+
box(size[0] + 10, slatThickness, size[2] + 10)
|
|
23
23
|
.translate(center[0], y, center[2])
|
|
24
24
|
);
|
|
25
25
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Patterns — linearPattern and circularPattern for repeating shapes.
|
|
2
2
|
|
|
3
|
-
const count =
|
|
4
|
-
const spacing =
|
|
5
|
-
const radius =
|
|
3
|
+
const count = Param.number("Count", 6, { min: 2, max: 12, integer: true });
|
|
4
|
+
const spacing = Param.number("Spacing", 20, { min: 10, max: 40, unit: "mm" });
|
|
5
|
+
const radius = Param.number("Ring Radius", 40, { min: 20, max: 80, unit: "mm" });
|
|
6
6
|
|
|
7
7
|
// --- linearPattern: repeat along a direction ---
|
|
8
8
|
const peg = cylinder(15, 4).color('#4488cc');
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// pointAlong() — orient a cylinder's axis without thinking about Euler angles.
|
|
2
2
|
//
|
|
3
3
|
// Cylinders default to Z-up. To lay one along X or Y:
|
|
4
|
-
// ❌ cylinder(80, 5).
|
|
4
|
+
// ❌ cylinder(80, 5).rotateX(90) — works, but less readable
|
|
5
5
|
// ✅ cylinder(80, 5).pointAlong([0, 1, 0]) — "point along Y"
|
|
6
6
|
//
|
|
7
7
|
// After pointAlong, the cylinder starts at origin and extends in that direction.
|
|
8
8
|
// Always call pointAlong BEFORE translate/attachTo.
|
|
9
9
|
|
|
10
|
-
const len =
|
|
11
|
-
const r =
|
|
10
|
+
const len = Param.number("Length", 80, { min: 30, max: 150, unit: "mm" });
|
|
11
|
+
const r = Param.number("Radius", 5, { min: 2, max: 15, unit: "mm" });
|
|
12
12
|
const spacing = 40;
|
|
13
13
|
|
|
14
14
|
// Default: along +Z (up)
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
// - direct 3D helper (`lib.profile2020BSlot6`)
|
|
5
5
|
// - parameterized technical dimensions
|
|
6
6
|
|
|
7
|
-
const length =
|
|
8
|
-
const slotDepth =
|
|
9
|
-
const slotInner =
|
|
10
|
-
const centerBore =
|
|
7
|
+
const length = Param.number("Length", 220, { min: 40, max: 800, unit: "mm" });
|
|
8
|
+
const slotDepth = Param.number("Slot Depth", 5.5, { min: 4.6, max: 6.6, step: 0.1, unit: "mm" });
|
|
9
|
+
const slotInner = Param.number("Slot Inner Width", 8.2, { min: 7, max: 10.5, step: 0.1, unit: "mm" });
|
|
10
|
+
const centerBore = Param.number("Center Bore", 5.5, { min: 0, max: 6.5, step: 0.1, unit: "mm" });
|
|
11
11
|
|
|
12
12
|
const profile2d = lib.profile2020BSlot6Profile({
|
|
13
13
|
slotInnerWidth: slotInner,
|
|
@@ -16,7 +16,6 @@ const profile2d = lib.profile2020BSlot6Profile({
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
const extrusion = lib.profile2020BSlot6(length, {
|
|
19
|
-
center: true,
|
|
20
19
|
slotDepth,
|
|
21
20
|
slotInnerWidth: slotInner,
|
|
22
21
|
centerBoreDia: centerBore,
|
|
@@ -29,7 +29,7 @@ let body = constrainedSketch()
|
|
|
29
29
|
// Subtract center bore
|
|
30
30
|
body = body.subtract(circle2d(R_CORE_IN))
|
|
31
31
|
|
|
32
|
-
const solidCutRectangle = rect(200, 8
|
|
32
|
+
const solidCutRectangle = rect(200, 8);
|
|
33
33
|
const solidRing = circle2d(R_CORE)
|
|
34
34
|
.subtract(circle2d(R_CORE_IN))
|
|
35
35
|
.subtract(solidCutRectangle)
|
|
@@ -26,33 +26,33 @@ const wheelbase = 250;
|
|
|
26
26
|
const groundClearance = 26;
|
|
27
27
|
const bodyZ = wheelRadius + groundClearance + chassisHeight * 0.5;
|
|
28
28
|
|
|
29
|
-
const baseDeck = box(chassisLength, chassisWidth, chassisHeight
|
|
29
|
+
const baseDeck = box(chassisLength, chassisWidth, chassisHeight)
|
|
30
30
|
.translate(0, 0, bodyZ);
|
|
31
31
|
|
|
32
|
-
const roofPod = box(roofLength, roofWidth, roofHeight
|
|
32
|
+
const roofPod = box(roofLength, roofWidth, roofHeight)
|
|
33
33
|
.translate(20, 0, bodyZ + 40);
|
|
34
34
|
|
|
35
35
|
const bumper = union(
|
|
36
|
-
box(54, bumperWidth, bumperDepth
|
|
37
|
-
box(bumperLength, bumperWidth - 42, bumperDepth * 0.7
|
|
36
|
+
box(54, bumperWidth, bumperDepth).translate(chassisLength * 0.5 - 18, 0, wheelRadius + 6),
|
|
37
|
+
box(bumperLength, bumperWidth - 42, bumperDepth * 0.7).translate(chassisLength * 0.5 + 46, 0, wheelRadius - 10),
|
|
38
38
|
).color('#c8742b');
|
|
39
39
|
|
|
40
40
|
const sensorMast = union(
|
|
41
|
-
cylinder(92, 10, undefined, 40
|
|
42
|
-
box(78, 34, 26
|
|
41
|
+
cylinder(92, 10, undefined, 40).translate(58, 0, bodyZ + 78),
|
|
42
|
+
box(78, 34, 26).translate(88, 0, bodyZ + 126),
|
|
43
43
|
).color('#d7dee8');
|
|
44
44
|
|
|
45
45
|
const chassis = union(baseDeck, roofPod)
|
|
46
46
|
.color('#60707d');
|
|
47
47
|
|
|
48
48
|
const wheelTire = difference(
|
|
49
|
-
cylinder(wheelWidth, wheelRadius, undefined, 64
|
|
50
|
-
cylinder(wheelWidth + 2, wheelRadius * 0.56, undefined, 48
|
|
49
|
+
cylinder(wheelWidth, wheelRadius, undefined, 64).pointAlong([0, 1, 0]),
|
|
50
|
+
cylinder(wheelWidth + 2, wheelRadius * 0.56, undefined, 48).pointAlong([0, 1, 0]),
|
|
51
51
|
).color('#1d2329');
|
|
52
52
|
|
|
53
53
|
const wheelRim = union(
|
|
54
|
-
cylinder(wheelWidth * 0.86, wheelRadius * 0.52, undefined, 40
|
|
55
|
-
cylinder(wheelWidth * 1.02, wheelRadius * 0.16, undefined, 28
|
|
54
|
+
cylinder(wheelWidth * 0.86, wheelRadius * 0.52, undefined, 40).pointAlong([0, 1, 0]),
|
|
55
|
+
cylinder(wheelWidth * 1.02, wheelRadius * 0.16, undefined, 28).pointAlong([0, 1, 0]),
|
|
56
56
|
).color('#b8c5d3');
|
|
57
57
|
|
|
58
58
|
const wheel = group(
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
const W = 80, D = 50, H = 30;
|
|
9
9
|
|
|
10
10
|
// ── Base enclosure ────────────────────────────────────────────────────────────
|
|
11
|
-
const body = roundedRect(W, D, 4
|
|
11
|
+
const body = roundedRect(W, D, 4)
|
|
12
12
|
.extrude(H)
|
|
13
13
|
.color('#c8cdd6');
|
|
14
14
|
|
|
@@ -41,7 +41,7 @@ const vents = ribSketch
|
|
|
41
41
|
.color('#1a1a2e');
|
|
42
42
|
|
|
43
43
|
// ── Badge recess on the front face ────────────────────────────────────────────
|
|
44
|
-
const badge = roundedRect(36, 12, 2
|
|
44
|
+
const badge = roundedRect(36, 12, 2)
|
|
45
45
|
.onFace(body, 'front', { v: 4, protrude: 0.05 })
|
|
46
46
|
.extrude(1.5)
|
|
47
47
|
.color('#2563eb');
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
// A "T" cross-section: wide base + narrow stem. The boolean creates one
|
|
23
23
|
// connected region; we pick it with the regions() API.
|
|
24
24
|
|
|
25
|
-
const base = rect(120, 20
|
|
26
|
-
const stem = rect(30, 50
|
|
25
|
+
const base = rect(120, 20); // centered at origin
|
|
26
|
+
const stem = rect(30, 50).translate(0, 35); // stem centered above base
|
|
27
27
|
const tShape = base.add(stem);
|
|
28
28
|
const [tRegion] = tShape.regions(); // one connected T region
|
|
29
29
|
const tPart = tRegion.extrude(6); // extrude the T profile
|
|
@@ -32,8 +32,8 @@ const tPart = tRegion.extrude(6); // extrude the T profile
|
|
|
32
32
|
// A 100×40 plate with a 60×20 hole punched in the center, leaving a frame.
|
|
33
33
|
// Pick the frame ring as one region using a corner seed.
|
|
34
34
|
|
|
35
|
-
const plate = rect(100, 40
|
|
36
|
-
const hole = rect(60, 20
|
|
35
|
+
const plate = rect(100, 40); // centered at origin
|
|
36
|
+
const hole = rect(60, 20); // centered cutout
|
|
37
37
|
const frame = plate.subtract(hole);
|
|
38
38
|
|
|
39
39
|
// The seed [45, 15] is in the top-right corner — inside the frame wall, outside the hole.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Compare common sketch-rounding strategies on the same roof profile.
|
|
2
2
|
// Only the selective fillet keeps the lower roof corners sharp.
|
|
3
3
|
|
|
4
|
-
const radius =
|
|
4
|
+
const radius = Param.number("Radius", 14, { min: 4, max: 24, unit: "mm" });
|
|
5
5
|
const gap = 120;
|
|
6
6
|
const bodyWidth = 90;
|
|
7
7
|
const bodyHeight = 44;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Drag the Blend Weight slider to shift the blend shape!
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const blendWeight =
|
|
13
|
+
const blendWeight = Param.number('Blend Weight', 0.5, { min: 0.1, max: 0.9, step: 0.05 });
|
|
14
14
|
|
|
15
15
|
// ─── 1. Gothic arch — two arcs meeting at a point ──────────────────────────
|
|
16
16
|
// Two arcs sharing a crown point — smooth by construction since both
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Demonstrates transitionCurve(), transitionSurface(), connectEdges(),
|
|
3
3
|
// and weighted blending (G1 + G2 continuity).
|
|
4
4
|
|
|
5
|
-
const weight =
|
|
6
|
-
const weightB =
|
|
7
|
-
const radius =
|
|
5
|
+
const weight = Param.number("Weight A", 1.0, { min: 0.1, max: 5.0, step: 0.1 });
|
|
6
|
+
const weightB = Param.number("Weight B", 1.0, { min: 0.1, max: 5.0, step: 0.1 });
|
|
7
|
+
const radius = Param.number("Tube Radius", 1.5, { min: 0.3, max: 5, unit: "mm" });
|
|
8
8
|
|
|
9
9
|
// Small anchor block at a point (visual reference for where the tube connects)
|
|
10
10
|
function anchor(pos) {
|
|
11
11
|
const s = 3;
|
|
12
|
-
return box(s, s, s
|
|
12
|
+
return box(s, s, s).translate(pos[0], pos[1], pos[2]);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// ── 1. L-bend: 90-degree pipe turn ──────────────────────────────
|