forgecad 0.7.0 → 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 +1 -1
- package/dist/assets/{AdminPage-DAu1C1ST.js → AdminPage-D4bocK4E.js} +1 -1
- package/dist/assets/{DocsPage-Gc_BCdqC.js → DocsPage-D3A_g8V3.js} +85 -45
- package/dist/assets/{EditorApp-DG1-oUSV.css → EditorApp-BWYUSpUN.css} +133 -51
- package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
- package/dist/assets/{EmbedViewer-CEO8XbV8.js → EmbedViewer-kWjKaC_t.js} +1 -1
- package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
- package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
- package/dist/assets/{PricingPage-BSrxu6d7.js → PricingPage-BsU5vzEx.js} +1 -1
- package/dist/assets/{SettingsPage-FUCSIRq6.js → SettingsPage-PqvpAKIs.js} +1 -1
- package/dist/assets/{evalWorker-KoR0SNKq.js → evalWorker-C-hzNUMy.js} +2218 -286
- package/dist/assets/{index-wTEK39at.js → index-Pz321YAt.js} +7416 -1481
- package/dist/assets/{index-CyVd1D4D.css → index-ay13WNfa.css} +501 -2
- package/dist/assets/{manifold-B1sGWdYk.js → manifold-BcbjWLIo.js} +3 -3
- package/dist/assets/{manifold-D7o0N50J.js → manifold-DBckbFgx.js} +1 -1
- package/dist/assets/{manifold-G5sBaXzi.js → manifold-O2AAGXyj.js} +1 -1
- package/dist/assets/{reportWorker-DYcRHhv9.js → reportWorker-Dxr-5A7w.js} +2003 -259
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +488 -0
- package/dist/docs-raw/generated/assembly.md +19 -11
- package/dist/docs-raw/generated/concepts.md +1023 -360
- package/dist/docs-raw/generated/core.md +1165 -264
- package/dist/docs-raw/generated/curves.md +168 -1
- package/dist/docs-raw/generated/lib.md +10 -5
- package/dist/docs-raw/generated/output.md +1 -1
- package/dist/docs-raw/generated/sdf.md +208 -0
- package/dist/docs-raw/generated/sketch.md +1281 -329
- package/dist/docs-raw/generated/viewport.md +29 -2
- 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 +3148 -555
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-cli/{solver-FV7TJZGI.js → solver-46FFSK2U.js} +1 -3
- package/dist-cli/{solver-FV7TJZGI.js.map → solver-46FFSK2U.js.map} +1 -1
- package/dist-skill/CONTEXT.md +3700 -1153
- package/dist-skill/SKILL-dev.md +15 -17
- package/dist-skill/SKILL.md +14 -9
- package/dist-skill/docs/API/core/concepts.md +28 -1
- package/dist-skill/docs/CLI.md +488 -0
- package/dist-skill/docs/generated/assembly.md +19 -11
- package/dist-skill/docs/generated/core.md +1165 -264
- package/dist-skill/docs/generated/curves.md +168 -1
- package/dist-skill/docs/generated/lib.md +10 -5
- package/dist-skill/docs/generated/output.md +1 -1
- package/dist-skill/docs/generated/sdf.md +208 -0
- package/dist-skill/docs/generated/sketch.md +1281 -329
- package/dist-skill/docs/generated/viewport.md +29 -2
- package/dist-skill/docs/guides/joint-design.md +78 -0
- package/dist-skill/docs-dev/API/core/concepts.md +28 -1
- package/dist-skill/docs-dev/CLI.md +488 -0
- package/dist-skill/docs-dev/coding.md +1 -1
- package/dist-skill/docs-dev/component-model.md +164 -0
- package/dist-skill/docs-dev/generated/assembly.md +19 -11
- package/dist-skill/docs-dev/generated/core.md +1165 -264
- package/dist-skill/docs-dev/generated/curves.md +168 -1
- package/dist-skill/docs-dev/generated/lib.md +10 -5
- package/dist-skill/docs-dev/generated/output.md +1 -1
- package/dist-skill/docs-dev/generated/sdf.md +208 -0
- package/dist-skill/docs-dev/generated/sketch.md +1281 -329
- package/dist-skill/docs-dev/generated/viewport.md +29 -2
- package/dist-skill/docs-dev/guides/joint-design.md +78 -0
- package/examples/api/attachTo-basics.forge.js +3 -3
- 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 +2 -2
- package/examples/api/bounding-box-visualizer.forge.js +1 -1
- package/examples/api/clone-duplicate.forge.js +1 -1
- package/examples/api/connector-assembly.forge.js +4 -2
- package/examples/api/connector-basics.forge.js +5 -5
- 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 +4 -4
- package/examples/api/fillet-showcase.forge.js +1 -1
- package/examples/api/gears-tier1.forge.js +5 -5
- package/examples/api/group-test.forge.js +2 -2
- package/examples/api/mesh-import-slats.forge.js +3 -3
- package/examples/api/patterns.forge.js +3 -3
- package/examples/api/pointAlong-orientation.forge.js +2 -2
- package/examples/api/profile-2020-b-slot6.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 +3 -3
- 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/furniture/adjustable-table.forge.js +13 -13
- package/examples/furniture/bathroom.forge.js +15 -15
- package/examples/furniture/chair.forge.js +12 -12
- 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 +7 -7
- package/examples/generative/frost-spires.forge.js +6 -6
- package/examples/generative/golden-spiral-tower.forge.js +8 -8
- 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 +9 -9
- package/examples/mechanical/5-finger-robot-hand.forge.js +4 -4
- package/examples/mechanical/airplane-propeller.forge.js +7 -7
- 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 +14 -10
- package/examples/mechanical/headphone-hanger-v2.forge.js +9 -9
- package/examples/mechanical/robot_hand.forge.js +10 -10
- package/examples/mechanical/robot_hand_2.forge.js +17 -17
- package/examples/nurbs-surface.forge.js +8 -0
- package/examples/nurbs-tube.forge.js +7 -0
- package/examples/products/bottle.forge.js +7 -7
- package/examples/products/chess-set.forge.js +6 -6
- package/examples/products/classical-piano.forge.js +9 -9
- package/examples/products/clock.forge.js +21 -21
- package/examples/products/cup.forge.js +5 -5
- package/examples/products/iphone.forge.js +12 -12
- package/examples/products/laptop.forge.js +9 -9
- 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 +5 -5
- package/examples/products/origami-fish.forge.js +6 -6
- package/examples/products/spiderman-cake.forge.js +2 -2
- package/examples/shelf/container.forge.js +5 -5
- package/examples/shelf/shelf-unit.forge.js +6 -6
- package/examples/toolbox/bolted-joint.forge.js +5 -5
- package/package.json +3 -1
- package/dist/assets/EditorApp-D9bJvtf7.js +0 -11338
- package/dist/assets/LandingPage-CdCuEOdC.js +0 -451
- package/dist-cli/chunk-PZ5AY32C.js +0 -10
- package/dist-cli/chunk-PZ5AY32C.js.map +0 -1
- package/dist-skill/docs/CLI/export.md +0 -91
- package/dist-skill/docs/CLI/projects.md +0 -107
- package/dist-skill/docs/CLI/studio_publishing.md +0 -52
- package/dist-skill/docs/CLI/validation.md +0 -66
- package/dist-skill/docs-dev/API/core/sdf-advanced.md +0 -92
- package/dist-skill/docs-dev/API/core/sdf-primitives.md +0 -58
- package/dist-skill/docs-dev/API/core/sdf-workflow.md +0 -42
- package/dist-skill/docs-dev/CLI/export.md +0 -91
- package/dist-skill/docs-dev/CLI/projects.md +0 -107
- package/dist-skill/docs-dev/CLI/studio_publishing.md +0 -52
- package/dist-skill/docs-dev/CLI/validation.md +0 -66
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill-group: dev-conventions
|
|
3
|
+
skill-order: 4
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The Component Model
|
|
7
|
+
|
|
8
|
+
## Parts Are Components. Assemblies Are Composition.
|
|
9
|
+
|
|
10
|
+
ForgeCAD's multi-part design model follows one principle:
|
|
11
|
+
|
|
12
|
+
> **A part is a function from props to shape + connectors. It knows nothing about where it sits in the world. The assembly decides.**
|
|
13
|
+
|
|
14
|
+
This is how React changed UI: components render content, the layout system positions them. Components don't know their screen coordinates. Before React, jQuery code positioned elements in page-space. After React, components are local and composable.
|
|
15
|
+
|
|
16
|
+
ForgeCAD applies the same principle to mechanical design. Before: parts compute their assembly-space coordinates (translate to the right X, Y, Z, using a shared-dims file). After: parts build at origin in local space, declare connectors, and the assembly uses `connect()` to position everything.
|
|
17
|
+
|
|
18
|
+
## The Three Rules
|
|
19
|
+
|
|
20
|
+
### Rule 1: Parts Build at Origin
|
|
21
|
+
|
|
22
|
+
A part is built in its own local coordinate system. Origin at `[0, 0, 0]`. No knowledge of the assembly. No imports of sibling part files. No global coordinate offsets.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// WRONG — part positions itself in assembly space
|
|
26
|
+
const rackPlaced = rack.translate(pinionPitchR, 0, layout.pinionZ);
|
|
27
|
+
|
|
28
|
+
// RIGHT — part builds at origin, connector declares the interface
|
|
29
|
+
const rack = lib.rackGear({ ... }).rotateZ(90);
|
|
30
|
+
// pitch line at X=0, teeth face -X, local coordinates only
|
|
31
|
+
return rack.withConnectors({
|
|
32
|
+
teeth: connector("rack-slide", { origin: [0, 0, faceWidth/2], axis: [0, 1, 0] }),
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Rule 2: Connectors Are the Interface
|
|
37
|
+
|
|
38
|
+
Every part that participates in an assembly declares connectors. A connector says: "here's where I connect, and here's what direction I face." It's the part's public interface — the only thing the assembly needs to know.
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
return mount.withConnectors({
|
|
42
|
+
flange: connector("bolt-face", {
|
|
43
|
+
origin: [0, 0, 0], // where the mating surface is
|
|
44
|
+
axis: [0, 0, 1], // direction it faces (outward from part)
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Connectors meet **face-to-face**. Both axes point outward from their respective parts. The system brings them together from opposite sides — like plugging a USB cable into a port.
|
|
50
|
+
|
|
51
|
+
### Rule 3: The Assembly Is Pure Composition
|
|
52
|
+
|
|
53
|
+
The assembly file does three things: instantiate parts with props, connect them, and define motion. Zero coordinate math. Zero translate calls. Zero shared-dims imports.
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
assembly("Gripper")
|
|
57
|
+
.addPart("Base", base)
|
|
58
|
+
.addPart("Mount", mount)
|
|
59
|
+
.connect("Base.mount_face", "Mount.flange", { as: "mount-fix" })
|
|
60
|
+
.addPart("Pinion", pinion)
|
|
61
|
+
.connect("Base.pinion_seat", "Pinion.bore", { as: "spin" })
|
|
62
|
+
// ...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If you're writing `translate()` in an assembly file, something is wrong. Either the part should have a connector, or the prop should carry the dimension.
|
|
66
|
+
|
|
67
|
+
## Data Flow: Props Down, Metadata Up
|
|
68
|
+
|
|
69
|
+
Data flows in one direction: from parent (assembly) to children (parts).
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Assembly (root)
|
|
73
|
+
├── passes { servo, wall, clearance } → Motor Mount
|
|
74
|
+
│ └── returns { shape, boltPattern, flange connector }
|
|
75
|
+
├── passes { gears, boltPattern } → Base Body
|
|
76
|
+
│ └── returns { shape, pinionZ, rack connectors }
|
|
77
|
+
├── passes { gears, rackZ, armSpan } → Jaw Unit
|
|
78
|
+
│ └── returns { shape, armWidth, rack connector }
|
|
79
|
+
└── passes { boltPattern, armSlot } → Cover Plate
|
|
80
|
+
└── returns { shape, seat connector }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Props flow down:** The assembly knows the cross-cutting decisions (base height, wall thickness, servo model) and passes them to parts as `require()` param overrides.
|
|
84
|
+
|
|
85
|
+
**Metadata flows up:** Parts return their shape + connectors + any computed data that siblings need. The assembly reads this metadata and passes relevant pieces to other parts.
|
|
86
|
+
|
|
87
|
+
**Siblings never import each other.** The cover plate doesn't import the motor mount to read bolt positions. The assembly reads the mount's bolt pattern and passes it to the cover plate. The parent mediates all sibling communication.
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
// Assembly mediates sibling data flow
|
|
91
|
+
const mount = require('./motor-mount.forge.js', { Wall: wall });
|
|
92
|
+
const base = require('./base-body.forge.js', {
|
|
93
|
+
Height: baseH,
|
|
94
|
+
BoltPattern: mount.boltPattern, // parent passes mount's data to base
|
|
95
|
+
});
|
|
96
|
+
const cover = require('./cover-plate.forge.js', {
|
|
97
|
+
BoltPattern: mount.boltPattern, // same data to cover
|
|
98
|
+
ArmSlot: jaw.armProfile, // jaw's data to cover
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Why This Matters
|
|
103
|
+
|
|
104
|
+
### For Humans
|
|
105
|
+
|
|
106
|
+
Each part file tells a complete story. You open `motor-mount.forge.js` and see everything: its geometry, its connectors, its parameters, its verifications. No chasing imports across 8 files. No 266-line shared-dims.js to understand.
|
|
107
|
+
|
|
108
|
+
Modifying one part doesn't break siblings — connectors are the contract. Change the mount's internal cavity dimensions and nothing else changes, as long as the flange connector stays at the same position.
|
|
109
|
+
|
|
110
|
+
### For AIs
|
|
111
|
+
|
|
112
|
+
Each part file is self-contained context. An AI generates `base-body.forge.js` without reading `jaw-unit.forge.js`. The assembly file is a high-level plan — generate it from a natural language description. Props are the interface contract — the AI knows exactly what each part needs and provides.
|
|
113
|
+
|
|
114
|
+
### For Swap-ability
|
|
115
|
+
|
|
116
|
+
Change the servo model → the mount rebuilds with new cavity dimensions → its bolt pattern updates → the assembly passes the new pattern to base and cover → everything adapts. One change, cascading update, zero manual re-derivation.
|
|
117
|
+
|
|
118
|
+
## The Connector Convention
|
|
119
|
+
|
|
120
|
+
Connectors follow one convention: **face-to-face**.
|
|
121
|
+
|
|
122
|
+
Each connector's axis points **outward** from its part — the direction the connection faces. When two connectors mate, the system negates one axis so they approach from opposite sides.
|
|
123
|
+
|
|
124
|
+
- **Fixed joints** (bolt flange): both faces point outward, system brings them together
|
|
125
|
+
- **Revolute joints** (hinge): both parts point outward along the hinge line, system opposes them
|
|
126
|
+
- **Prismatic joints** (slider): both connectors point along the slide direction (co-directional exception — the slide axis IS the shared direction)
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
// Base bottom face points down, mount flange points up → meet in the middle
|
|
130
|
+
base.withConnectors({ mount_face: connector("bolt-face", { origin: [0,0,0], axis: [0,0,-1] }) });
|
|
131
|
+
mount.withConnectors({ flange: connector("bolt-face", { origin: [0,0,0], axis: [0,0,1] }) });
|
|
132
|
+
|
|
133
|
+
// Hinge: frame points up along hinge line, door points down → shared rotation axis
|
|
134
|
+
frame.withConnectors({ hinge: connector("hinge", { origin: [0,0,40], axis: [0,0,1] }) });
|
|
135
|
+
door.withConnectors({ hinge: connector("hinge", { origin: [0,0,40], axis: [0,0,-1] }) });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## One File vs. Many Files
|
|
139
|
+
|
|
140
|
+
**Default: one file per assembly.** For a project-specific assembly (robot gripper, drone frame), put everything in one file. Parts are sections separated by comments. Shared data is just variables. This maximizes locality — you see the whole design by scrolling.
|
|
141
|
+
|
|
142
|
+
**Split when:** A part is reusable across projects (standard servo cradle, parametric gear pair), or the file exceeds ~300 lines. Split parts into separate `.forge.js` files that export component functions.
|
|
143
|
+
|
|
144
|
+
**Never split for "organization."** Eight files with 40 lines each is worse than one file with 300 lines. The context-switching cost of 8 files destroys locality.
|
|
145
|
+
|
|
146
|
+
## What This Forbids
|
|
147
|
+
|
|
148
|
+
1. **No shared-dims files.** If you're writing a file whose only job is to compute derived dimensions from component specs, the assembly should be doing that work (or the parts should derive their own internal dimensions from props).
|
|
149
|
+
|
|
150
|
+
2. **No sibling imports.** A part file never `require()`s another part file. Data flows through the parent.
|
|
151
|
+
|
|
152
|
+
3. **No assembly-space coordinates in parts.** A part doesn't know `pinionZ = 14`. It receives `rackZ: 14` as a prop, or it computes its own internal Z from its own props.
|
|
153
|
+
|
|
154
|
+
4. **No `translate()` in assembly files.** If you're translating a part to position it, use a connector instead. The exception: ghost/reference geometry that isn't structural.
|
|
155
|
+
|
|
156
|
+
5. **No console.log validation.** Use `verify.*` for spatial checks. It's structured, clickable, and fails visibly.
|
|
157
|
+
|
|
158
|
+
## Design Gate
|
|
159
|
+
|
|
160
|
+
**Every new multi-part example and every agent-built assembly must follow this model:**
|
|
161
|
+
|
|
162
|
+
> Can you understand each part file without reading any other file? Does the assembly file contain zero coordinate math? Do all inter-part relationships flow through connectors and props?
|
|
163
|
+
|
|
164
|
+
If the answer to any is no, refactor until it's yes.
|
|
@@ -33,6 +33,8 @@ bomToCsv(rows: BomRow[]): string
|
|
|
33
33
|
|
|
34
34
|
#### `assembly()` — Create an assembly container with named parts and joints for kinematic mechanisms.
|
|
35
35
|
|
|
36
|
+
**Use this from iteration 1 for any model with moving parts.** Hinges, sliders, gears, articulated fingers, doors — all start with `assembly()`, not with manual rotation math. Don't build a static "extended pose" first and refactor to an assembly later: joint sliders, animations, sweeps, collision detection, and robot export all flow from the kinematic graph.
|
|
37
|
+
|
|
36
38
|
An assembly models a mechanism as a directed graph of parts connected by joints. Parts are the nodes; joints are directed edges from parent to child. The graph must be a forest (no cycles). Root parts (those with no incoming joint) are anchored to world space.
|
|
37
39
|
|
|
38
40
|
Three joint types are supported: `'revolute'` (hinge), `'prismatic'` (slider), and `'fixed'` (rigid attachment). Use `addPart()` to add geometry, `addJoint()` (or the shorthands `addRevolute()`, `addPrismatic()`, `addFixed()`) to connect parts, and `solve()` to compute world-space positions at a given joint state.
|
|
@@ -62,7 +64,7 @@ assembly(name?: string): Assembly
|
|
|
62
64
|
|
|
63
65
|
#### `joint()` — Create a revolute joint that auto-generates a parameter slider and rotates the shape.
|
|
64
66
|
|
|
65
|
-
This is a convenience wrapper for single-shape, single-joint use cases. It calls
|
|
67
|
+
This is a convenience wrapper for single-shape, single-joint use cases. It calls `param()` to create a named angle slider, then applies `rotateAroundAxis()` to the shape. Use the full `Assembly` API for mechanisms with multiple parts and joints.
|
|
66
68
|
|
|
67
69
|
```ts
|
|
68
70
|
const arm = joint("Shoulder", armShape, [0, 0, 20], {
|
|
@@ -268,22 +270,28 @@ addFixed(name: string, parent: string, child: string, options?: JointOptions): A
|
|
|
268
270
|
|
|
269
271
|
Connector references use `"PartName.connectorName"` format. The system aligns connector origins (child connector lands exactly on parent connector) and derives the joint frame and axis from the connector geometry — no manual `frame` or `axis` math needed.
|
|
270
272
|
|
|
271
|
-
|
|
273
|
+
**Face-to-face convention:** Connectors always meet face-to-face, like a USB plug meeting a socket. Each connector's axis points "outward" from its part. When two connectors mate, the system brings them together so their axes oppose (anti-parallel). This is the same convention used by `matchTo()`.
|
|
274
|
+
|
|
275
|
+
For a revolute joint (hinge), both connectors' axes should point outward from their respective parts along the hinge line. For a prismatic joint (slider), both axes should point along the slide direction from their part's perspective.
|
|
276
|
+
|
|
277
|
+
The joint type is inferred from the connector's `kind` field if not specified in `options`.
|
|
272
278
|
|
|
273
279
|
When connectors are defined with `start`/`end`, you can control which point on each connector meets via `align` / `parentAlign` / `childAlign` (`'start'`, `'middle'`, `'end'`).
|
|
274
280
|
|
|
275
281
|
Use `connect()` when connector origins must physically coincide (flange-to-flange, bolt-into-bore). For mechanisms where parts share an axis but are deliberately spaced apart, use `addRevolute()` with pre-positioned parts instead.
|
|
276
282
|
|
|
277
283
|
```ts
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
284
|
+
// Hinge: both axes point outward along the hinge line
|
|
285
|
+
const frame = box(100, 10, 80).withConnectors({
|
|
286
|
+
hinge: connector("hinge", { origin: [0, 0, 40], axis: [0, 0, 1] }),
|
|
287
|
+
});
|
|
288
|
+
const door = box(60, 4, 80).withConnectors({
|
|
289
|
+
hinge: connector("hinge", { origin: [0, 0, 40], axis: [0, 0, -1] }),
|
|
290
|
+
});
|
|
291
|
+
assembly("Door")
|
|
292
|
+
.addPart("Frame", frame)
|
|
293
|
+
.addPart("Door", door)
|
|
294
|
+
.connect("Frame.hinge", "Door.hinge", { as: "swing", min: 0, max: 110 });
|
|
287
295
|
```
|
|
288
296
|
|
|
289
297
|
```ts
|