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
|
@@ -5,206 +5,147 @@ skill-order: 3
|
|
|
5
5
|
|
|
6
6
|
# Positioning Strategy
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## Primitive origin convention
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
All 3D primitives are **centered on XY, base at Z=0**:
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
| Primitive | X range | Y range | Z range |
|
|
13
|
+
|-----------|---------|---------|---------|
|
|
14
|
+
| `box(60, 40, 20)` | [-30, 30] | [-20, 20] | [0, 20] |
|
|
15
|
+
| `cylinder(50, 10)` | [-10, 10] | [-10, 10] | [0, 50] |
|
|
16
|
+
| `sphere(15)` | [-15, 15] | [-15, 15] | [-15, 15] |
|
|
17
|
+
| `torus(20, 5)` | [-25, 25] | [-25, 25] | [-5, 5] |
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
Sphere and torus are fully centered (symmetric in Z). Box and cylinder sit on the XY ground plane — **Z goes up from zero, never negative**.
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
// Define connectors on parts
|
|
18
|
-
const shelf = box(200, 120, 10, true).withConnectors({
|
|
19
|
-
left_tab: connector.male("dovetail", { origin: [-100, 0, 0], axis: [-1, 0, 0] }),
|
|
20
|
-
right_tab: connector.male("dovetail", { origin: [100, 0, 0], axis: [1, 0, 0] }),
|
|
21
|
-
});
|
|
21
|
+
This means `box(w, d, h).translate(0, 0, -h/2)` is wrong for "center on Z" — the box is already at `[0, h]`, not `[-h/2, h/2]`.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
shelf_0: connector.female("dovetail", { origin: [6, 0, -50], axis: [1, 0, 0] }),
|
|
25
|
-
shelf_1: connector.female("dovetail", { origin: [6, 0, 50], axis: [1, 0, 0] }),
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Single pair: "put my left_tab into panel's shelf_0"
|
|
29
|
-
const placed = shelf.matchTo(panel, "left_tab", "shelf_0");
|
|
23
|
+
---
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
const placed2 = shelf.matchTo(panel, { left_tab: "shelf_0" });
|
|
25
|
+
Most positioning bugs come from manual coordinate arithmetic. Use these methods in priority order.
|
|
33
26
|
|
|
34
|
-
|
|
35
|
-
const cabinet = group({ name: "Left", shape: panel });
|
|
36
|
-
shelf.matchTo(cabinet, "left_tab", "Left.shelf_0");
|
|
37
|
-
```
|
|
27
|
+
## 1. `group()` — local coordinates for multi-part assemblies
|
|
38
28
|
|
|
39
|
-
**
|
|
40
|
-
- **Stable.** Connector positions are authored explicitly — they don't shift when you fillet, chamfer, or boolean the part.
|
|
41
|
-
- **Semantic.** Connectors carry type and gender — `assembly.match()` validates compatibility before connecting.
|
|
42
|
-
- **Oriented.** Full coordinate frame (origin + axis + up), not just a point.
|
|
43
|
-
- **Queryable.** `shape.connectorDistance('a', 'b')` lets you derive dimensions from connector positions — e.g. compute pipe length from the distance between two fittings.
|
|
44
|
-
- **Explode-aware.** Matched parts automatically separate along connector axes when the explode slider is used.
|
|
29
|
+
The most common positioning bug: manually adding a parent's global offset to every sub-part. One wrong sign or forgotten variable and parts float into space. **Use `group()` to build parts in local coordinates (at the origin), then position the group once.**
|
|
45
30
|
|
|
46
|
-
**Connector patterns:**
|
|
47
31
|
```javascript
|
|
48
|
-
//
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
const
|
|
60
|
-
const
|
|
32
|
+
// BAD — every sub-part repeats the parent's global position
|
|
33
|
+
const unitY = -18, unitZ = 70;
|
|
34
|
+
const body = lib.roundedBox(100, 20, 32, 4).translate(0, unitY, unitZ);
|
|
35
|
+
const panel = box(98, 2, 18).translate(0, unitY - 12, unitZ + 4);
|
|
36
|
+
const louver = box(88, 2, 6).translate(0, unitY - 14, unitZ - 11);
|
|
37
|
+
const led = sphere(1.2).translate(35, unitY - 12, unitZ + 9);
|
|
38
|
+
|
|
39
|
+
// GOOD — build at local origin, group, translate once
|
|
40
|
+
const body = lib.roundedBox(100, 20, 32, 4);
|
|
41
|
+
const panel = box(98, 2, 18).translate(0, -12, 4); // relative to local origin
|
|
42
|
+
const louver = box(88, 2, 6).translate(0, -14, -11); // relative to local origin
|
|
43
|
+
const led = sphere(1.2).translate(35, -12, 9); // relative to local origin
|
|
44
|
+
const indoorUnit = group(
|
|
45
|
+
{ name: 'Body', shape: body },
|
|
46
|
+
{ name: 'Panel', shape: panel },
|
|
47
|
+
{ name: 'Louver', shape: louver },
|
|
48
|
+
{ name: 'LED', shape: led },
|
|
49
|
+
).translate(0, -18, 70); // ONE translate for the whole assembly
|
|
61
50
|
```
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Cylinders default to Z-up. Instead of `rotate(90, 0, 0)` (which is confusing), use `pointAlong()`:
|
|
52
|
+
**Groups nest.** Build sub-assemblies as groups, then group those into larger assemblies — each level has its own local origin.
|
|
66
53
|
|
|
67
54
|
```javascript
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
55
|
+
const fan = group(hub, ...blades).translate(0, 25, 0); // fan assembly
|
|
56
|
+
const outdoorUnit = group(
|
|
57
|
+
{ name: 'Body', shape: casing },
|
|
58
|
+
{ name: 'Fan', shape: fan }, // already a group
|
|
59
|
+
{ name: 'Grille', shape: grille },
|
|
60
|
+
).translate(0, 23, -42); // position the whole outdoor unit
|
|
73
61
|
```
|
|
74
62
|
|
|
75
|
-
**
|
|
63
|
+
**When to use something else:** `group()` preserves individual shapes — you can't boolean (subtract/intersect) a group. If a sub-part needs a boolean with the parent body, do that boolean first in local coordinates, then group the result.
|
|
76
64
|
|
|
77
|
-
|
|
65
|
+
## 2. Connectors + `matchTo()` — default for mating interfaces
|
|
78
66
|
|
|
79
|
-
|
|
67
|
+
Define connectors on parts; `matchTo()` provides automatic 6-DOF alignment. The child translates and rotates so its connector aligns with the target's — origins coincide, axes oppose (plug-in model).
|
|
80
68
|
|
|
81
69
|
```javascript
|
|
82
|
-
const
|
|
83
|
-
|
|
70
|
+
const shelf = box(200, 120, 10, true).withConnectors({
|
|
71
|
+
left_tab: connector.male("dovetail", { origin: [-100, 0, 0], axis: [-1, 0, 0] }),
|
|
72
|
+
});
|
|
73
|
+
const panel = box(12, 120, 200, true).withConnectors({
|
|
74
|
+
shelf_0: connector.female("dovetail", { origin: [6, 0, -50], axis: [1, 0, 0] }),
|
|
75
|
+
});
|
|
76
|
+
const placed = shelf.matchTo(panel, "left_tab", "shelf_0");
|
|
77
|
+
// Dictionary form for multiple pairs on same target:
|
|
78
|
+
const placed2 = shelf.matchTo(panel, { left_tab: "shelf_0" });
|
|
79
|
+
// Named group children bubble connectors via dotted paths:
|
|
80
|
+
const cabinet = group({ name: "Left", shape: panel });
|
|
81
|
+
shelf.matchTo(cabinet, "left_tab", "Left.shelf_0");
|
|
84
82
|
```
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
**Limitations:** Anchor points are derived from the bounding box, so they shift when you fillet, chamfer, or boolean the part. No orientation, no validation, no semantic meaning. Prefer connectors for anything beyond quick prototyping.
|
|
89
|
-
|
|
90
|
-
### 5. `rotateAroundTo()` — Aim a point around a hinge/axis
|
|
84
|
+
**Why connectors first:** stable (don't shift on fillet/chamfer/boolean), semantic (carry type/gender), oriented (full frame), queryable (`shape.connectorDistance('a','b')`), explode-aware.
|
|
91
85
|
|
|
92
|
-
|
|
86
|
+
## 3. `pointAlong()` — orient cylinders before positioning
|
|
93
87
|
|
|
94
88
|
```javascript
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// Rotate around Z until the tip lies in the plane formed by the Z axis and the target point
|
|
100
|
-
const aimed = arm.rotateAroundTo(
|
|
101
|
-
[0, 0, 1],
|
|
102
|
-
[0, 0, 0],
|
|
103
|
-
"tip",
|
|
104
|
-
[30, 30, 20],
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
// Exact line solve: throws if the target line is unreachable while preserving radius about the axis
|
|
108
|
-
const lineHit = arm.rotateAroundTo(
|
|
109
|
-
[0, 0, 1],
|
|
110
|
-
[0, 0, 0],
|
|
111
|
-
"tip",
|
|
112
|
-
[30, 30, 0],
|
|
113
|
-
{ mode: 'line' },
|
|
114
|
-
);
|
|
89
|
+
// BAD
|
|
90
|
+
const pipe = cylinder(100, 5).rotateX(90).translate(x, y, z);
|
|
91
|
+
// GOOD — reads as "pipe pointing along Y"
|
|
92
|
+
const pipe = cylinder(100, 5).pointAlong([0, 1, 0]).translate(x, y, z);
|
|
115
93
|
```
|
|
116
94
|
|
|
117
|
-
|
|
95
|
+
**Always call `pointAlong()` BEFORE `matchTo()` or `translate()`** — it reorients around the origin.
|
|
118
96
|
|
|
119
|
-
|
|
97
|
+
## 4. `attachTo()` — quick bounding-box positioning
|
|
120
98
|
|
|
121
99
|
```javascript
|
|
122
|
-
const
|
|
123
|
-
const part = box(20, 20, 30).moveToLocal(base, 10, 10, 10);
|
|
100
|
+
const column = cylinder(50, 8).attachTo(base, 'top', 'bottom');
|
|
124
101
|
```
|
|
125
102
|
|
|
126
|
-
|
|
103
|
+
`child.attachTo(parent, parentAnchor, selfAnchor, offset)`. Anchor points shift on fillet/chamfer/boolean — fragile for assembly interfaces, fine for quick prototyping.
|
|
127
104
|
|
|
128
|
-
|
|
129
|
-
- Moving a shape by a known fixed amount
|
|
130
|
-
- Positioning between two shapes whose locations you've already computed via `boundingBox()`
|
|
105
|
+
## 5. `rotateAroundTo()` — aim a point around a hinge/axis
|
|
131
106
|
|
|
132
107
|
```javascript
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
const pipeLen = bb2.min[1] - bb1.max[1];
|
|
137
|
-
const pipe = cylinder(pipeLen, 5)
|
|
138
|
-
.pointAlong([0, 1, 0])
|
|
139
|
-
.translate(40, (bb1.max[1] + bb2.min[1]) / 2, bb1.min[2] + 15);
|
|
108
|
+
const aimed = arm.rotateAroundTo([0, 0, 1], [0, 0, 0], "tip", [30, 30, 20]);
|
|
109
|
+
// Exact line solve:
|
|
110
|
+
const lineHit = arm.rotateAroundTo([0, 0, 1], [0, 0, 0], "tip", [30, 30, 0], { mode: 'line' });
|
|
140
111
|
```
|
|
141
112
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
When a part will be imported elsewhere, define semantic placement references once in the source file:
|
|
113
|
+
## 6. `moveToLocal()` — offset from another shape's min corner
|
|
145
114
|
|
|
146
115
|
```javascript
|
|
147
|
-
|
|
148
|
-
return union(base, post).withReferences({
|
|
149
|
-
points: {
|
|
150
|
-
mount: [0, -16, -4],
|
|
151
|
-
},
|
|
152
|
-
objects: {
|
|
153
|
-
post,
|
|
154
|
-
},
|
|
155
|
-
});
|
|
116
|
+
const part = box(20, 20, 30).moveToLocal(base, 10, 10, 10);
|
|
156
117
|
```
|
|
157
118
|
|
|
158
|
-
|
|
119
|
+
## 7. `translate()` — for simple offsets or bridging computed locations
|
|
159
120
|
|
|
160
121
|
```javascript
|
|
161
|
-
const
|
|
162
|
-
|
|
122
|
+
const pipeLen = bb2.min[1] - bb1.max[1];
|
|
123
|
+
const pipe = cylinder(pipeLen, 5).pointAlong([0, 1, 0]).translate(40, (bb1.max[1] + bb2.min[1]) / 2, bb1.min[2] + 15);
|
|
163
124
|
```
|
|
164
125
|
|
|
165
|
-
|
|
126
|
+
## 8. `placeReference()` — align any anchor to a world coordinate
|
|
166
127
|
|
|
167
|
-
|
|
128
|
+
Place a shape so a named anchor point lands exactly where you want it. Accepts all built-in anchors (`'bottom'`, `'center'`, `'top-front-left'`, etc.) plus custom references from `withReferences()`.
|
|
168
129
|
|
|
169
|
-
### ❌ Manual center-offset math
|
|
170
130
|
```javascript
|
|
171
|
-
//
|
|
172
|
-
const
|
|
173
|
-
.translate(0, -parentThickness/2 - d/2 - 5, parentHeight/2 - h/2 - 20);
|
|
174
|
-
```
|
|
131
|
+
// Ground a shape — bottom face center at Z = 0
|
|
132
|
+
const grounded = shape.placeReference('bottom', [0, 0, 0])
|
|
175
133
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// GOOD: stable, semantic, self-documenting
|
|
179
|
-
const parent = box(100, 40, 60, true).withConnectors({
|
|
180
|
-
mount: connector.female("bracket", { origin: [0, -20, 10], axis: [0, -1, 0] }),
|
|
181
|
-
});
|
|
182
|
-
const child = box(w, d, h, true).withConnectors({
|
|
183
|
-
tab: connector.male("bracket", { origin: [0, d/2, 0], axis: [0, 1, 0] }),
|
|
184
|
-
});
|
|
185
|
-
const placed = child.matchTo(parent, "tab", "mount");
|
|
186
|
-
```
|
|
134
|
+
// Center at the world origin
|
|
135
|
+
const centered = shape.placeReference('center', [0, 0, 0])
|
|
187
136
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
// BAD: which axis? what happens to center?
|
|
191
|
-
const pipe = cylinder(100, 5).rotate(90, 0, 0).translate(x, y, z);
|
|
137
|
+
// Align left edge to X = 10
|
|
138
|
+
const aligned = shape.placeReference('left', [10, 0, 0])
|
|
192
139
|
```
|
|
193
140
|
|
|
194
|
-
|
|
195
|
-
```javascript
|
|
196
|
-
// GOOD: reads as "pipe pointing along Y"
|
|
197
|
-
const pipe = cylinder(100, 5).pointAlong([0, 1, 0]).translate(x, y, z);
|
|
198
|
-
```
|
|
141
|
+
Also works with custom placement references for cross-file parts:
|
|
199
142
|
|
|
200
|
-
### ❌ Bounding-box positioning for assembly interfaces
|
|
201
143
|
```javascript
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
```
|
|
144
|
+
// widget.forge.js — define once
|
|
145
|
+
return union(base, post).withReferences({ points: { mount: [0, -16, -4] } });
|
|
205
146
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// GOOD: connector positions are explicit and stable
|
|
209
|
-
const shelf = plank.matchTo(sidePanel, "left_tab", "shelf_slot_0");
|
|
147
|
+
// importer — consume
|
|
148
|
+
const widget = require("./widget.forge.js").placeReference("mount", [120, 40, 0]);
|
|
210
149
|
```
|
|
150
|
+
|
|
151
|
+
For cross-file parts needing proper alignment, prefer connectors over placement references.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill-group: core
|
|
3
|
+
skill-order: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ForgeCAD Core Concepts
|
|
7
|
+
|
|
8
|
+
ForgeCAD scripts are JavaScript that returns geometry. The forge API is globally available — no imports needed.
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
const width = param("Width", 50, { min: 20, max: 100, unit: "mm" });
|
|
12
|
+
return box(width, 30, 10);
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Execution Model
|
|
16
|
+
|
|
17
|
+
- Scripts re-execute on every parameter change (400ms debounce)
|
|
18
|
+
- All operations are **immutable** — return new shapes, never modify in place
|
|
19
|
+
- Must return one of: `Shape`, `Sketch`, `ShapeGroup`, `Array` of shapes/sketches/groups, `Array` of `{ name, shape?, sketch?, color? }`, or a **metadata object** (see below)
|
|
20
|
+
|
|
21
|
+
### Metadata Object Return
|
|
22
|
+
|
|
23
|
+
A script can return a plain object whose values include renderable geometry alongside non-renderable metadata. All renderable entries (Shape, Sketch, ShapeGroup, Assembly, or Array of named objects) are rendered; non-renderable entries are silently skipped. This is useful for multi-file projects where a part needs to publish interface data (bolt positions, dimensions) to other files:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
// motor-mount.forge.js — renders standalone, exports metadata via require()
|
|
27
|
+
const holePositions = [[17, 15], [-29, 15], [17, -15], [-29, -15]];
|
|
28
|
+
return {
|
|
29
|
+
shape: mount.color('#556B2F'), // rendered
|
|
30
|
+
bolts: { dia: 5.3, pos: holePositions }, // metadata — skipped in render, available via require()
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// base-body.forge.js — imports mount, accesses .bolts
|
|
34
|
+
const mount = require('./motor-mount.forge.js');
|
|
35
|
+
for (const [x, y] of mount.bolts.pos) { ... } // use metadata
|
|
36
|
+
// mount.shape is the Shape if you need it in an assembly
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Arrays inside the object are also rendered:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
return {
|
|
43
|
+
parts: [{ name: 'Left', shape: leftShape }, { name: 'Right', shape: rightShape }],
|
|
44
|
+
armWidth: 6, // metadata
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Coordinate System
|
|
49
|
+
|
|
50
|
+
Z-up right-handed: X = left/right, Y = forward/back, Z = up/down.
|
|
51
|
+
|
|
52
|
+
## Colors
|
|
53
|
+
|
|
54
|
+
`.color(hex)` works on `Shape` and `Sketch`. Colors survive transforms. In booleans the first operand's color wins.
|
|
55
|
+
|
|
56
|
+
**`union()` removes colors** — shapes merge into one solid mesh. Return named objects instead:
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
return [
|
|
60
|
+
{ name: "Base", shape: box(100, 100, 5), color: "#888888" },
|
|
61
|
+
{ name: "Column", shape: cylinder(50, 10).translate(50, 50, 5), color: "#4488cc" },
|
|
62
|
+
];
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Face Operations
|
|
66
|
+
|
|
67
|
+
Shapes carry semantic face labels through their lifecycle. The flow is:
|
|
68
|
+
|
|
69
|
+
1. **Primitives** assign canonical names — `box()` gives you `top`, `bottom`, `side-left`, etc.; `cylinder()` gives `top`, `bottom`, `side`.
|
|
70
|
+
2. **Extrusions** inherit labels from the sketch and add `top`/`bottom`.
|
|
71
|
+
3. **Transforms** (translate, rotate, scale, mirror) preserve all labels.
|
|
72
|
+
4. **Booleans** preserve labels from the first operand where geometry survives.
|
|
73
|
+
|
|
74
|
+
You resolve labels to geometry with `.face(name)` or `.face(query)` — see the Shape class docs for the full query API. Operations like `.pocket()`, `.boss()`, `.hole()`, and `faceProfile()` all consume face references.
|
|
75
|
+
|
|
76
|
+
## SDF Modeling
|
|
77
|
+
|
|
78
|
+
For organic shapes, smooth blending, TPMS lattices, and surface deformations. SDF shapes convert via `.toShape()`. See [sdf-primitives.md](sdf-primitives.md).
|