forgecad 0.9.5 → 0.9.7
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/dist/assets/{AdminPage-uTtcSXtn.js → AdminPage-DX0mpSZT.js} +1 -1
- package/dist/assets/{BlogPage-DYJMjWx3.js → BlogPage-CI_P0_Pf.js} +1 -1
- package/dist/assets/{DocsPage-C58f0K5v.js → DocsPage-DLhIIZyJ.js} +3 -3
- package/dist/assets/EditorApp-BujZvuwX.js +12874 -0
- package/dist/assets/{EditorApp-DS0AIUrZ.css → EditorApp-DfFT2Dn8.css} +1 -0
- package/dist/assets/{EmbedViewer-CMXWA2LX.js → EmbedViewer-0S0qXKog.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-CAu2OZFn.js → LandingPageProofDriven-O_yMtAri.js} +1 -1
- package/dist/assets/{PricingPage-BIgW7m3X.js → PricingPage-DGkX3Ahr.js} +1 -1
- package/dist/assets/{SettingsPage-N1l1tMXO.js → SettingsPage-DBsqTB_y.js} +82 -22
- package/dist/assets/{app-CFy7g5WP.js → app-BE2nD6Yz.js} +1246 -191
- package/dist/assets/cli/{render-BrVVdj_T.js → render-iP9qh475.js} +841 -586
- package/dist/assets/{evalWorker-c_SB9gg3.js → evalWorker-Ds5U4xtN.js} +2732 -112
- package/dist/assets/inspectWorker-Dll4eVyD.js +12620 -0
- package/dist/assets/{manifold-Dp6pvFr6.js → manifold-Bk26ViCr.js} +1 -1
- package/dist/assets/{manifold-CRoBhJKH.js → manifold-DjYsd7A_.js} +2 -2
- package/dist/assets/{manifold-Cjk7WhRs.js → manifold-sJ-axdXM.js} +1 -1
- package/dist/assets/{renderSceneState-3DfsSASX.js → renderSceneState-Bngp5MrQ.js} +1 -1
- package/dist/assets/{reportWorker-BLkuIoS8.js → reportWorker-CU8RZ4O0.js} +2715 -112
- package/dist/assets/{sectionPlaneMath-CykEnkvQ.js → sectionPlaneMath-BdTjyVfs.js} +3213 -252
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +1 -1
- package/dist/docs-raw/AI/usage.md +7 -2
- package/dist/docs-raw/CLI.md +82 -53
- package/dist/docs-raw/beta-operations.md +9 -0
- package/dist/docs-raw/coding.md +1 -1
- package/dist/docs-raw/deployment.md +38 -23
- package/dist/docs-raw/generated/concepts.md +141 -7
- package/dist/docs-raw/generated/core.md +206 -1
- package/dist/docs-raw/generated/curves.md +97 -5
- package/dist/docs-raw/generated/lib.md +17 -1
- package/dist/docs-raw/generated/sketch.md +9 -1
- package/dist/docs-raw/generated/viewport.md +1 -1
- package/dist/docs-raw/guides/inspection-bundles.md +45 -16
- package/dist/docs-raw/platform/auth.md +2 -0
- package/dist/docs-raw/platform/google-oauth-setup.md +4 -0
- package/dist/docs-raw/runbook.md +3 -3
- package/dist/docs-raw/skills/forgecad-make-a-model.md +87 -8
- package/dist/docs-raw/skills/forgecad-prepare-prompt.md +14 -6
- package/dist/docs-raw/skills/forgecad-render-inspect.md +1 -1
- package/dist/docs-raw/skills/index.md +2 -2
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +6 -6
- package/dist-cli/forgecad.js +8725 -4747
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-skill/CONTEXT.md +375 -25
- package/dist-skill/docs/CLI.md +82 -53
- package/dist-skill/docs/generated/core.md +206 -1
- package/dist-skill/docs/generated/curves.md +97 -5
- package/dist-skill/docs/generated/lib.md +17 -1
- package/dist-skill/docs/generated/sketch.md +9 -1
- package/dist-skill/docs/generated/viewport.md +1 -1
- package/dist-skill/docs/guides/inspection-bundles.md +45 -16
- package/dist-skill/docs-dev/CLI.md +82 -53
- package/dist-skill/docs-dev/coding.md +1 -1
- package/dist-skill/docs-dev/generated/core.md +206 -1
- package/dist-skill/docs-dev/generated/curves.md +97 -5
- package/dist-skill/docs-dev/generated/lib.md +17 -1
- package/dist-skill/docs-dev/generated/sketch.md +9 -1
- package/dist-skill/docs-dev/generated/viewport.md +1 -1
- package/dist-skill/docs-dev/guides/inspection-bundles.md +45 -16
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +87 -8
- package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +14 -6
- package/dist-skill/library/forgecad-prepare-prompt/references/default-profiles.md +5 -3
- package/dist-skill/library/forgecad-prepare-prompt/references/master-prompt.md +7 -5
- package/dist-skill/library/forgecad-render-inspect/SKILL.md +1 -1
- package/examples/api/bolted-service-cover.forge.js +17 -0
- package/examples/api/cable-gland-anchor.forge.js +14 -0
- package/examples/api/captured-cartridge-guide.forge.js +14 -0
- package/examples/api/captured-linear-slide.forge.js +13 -0
- package/examples/api/clevis-pin-joint.forge.js +13 -0
- package/examples/api/datum-enclosure.forge.js +16 -0
- package/examples/api/guided-loft-olive-oil-bottle.forge.js +135 -0
- package/examples/api/hose-barb-port.forge.js +14 -0
- package/examples/api/intentional-overlap-overmold.forge.js +16 -0
- package/examples/api/knuckled-hinge-assembly.forge.js +15 -0
- package/examples/api/living-hinge-cover.forge.js +14 -0
- package/examples/api/pcb-terminal-block.forge.js +22 -0
- package/examples/api/pinned-lever-pivot-stack.forge.js +14 -0
- package/examples/api/retained-shaft-knob-stack.forge.js +15 -0
- package/examples/api/routed-tube-clip.forge.js +15 -0
- package/examples/api/seated-bearing-stack.forge.js +30 -0
- package/examples/api/snap-latch-cover.forge.js +14 -0
- package/examples/api/static-assembly-connectors.forge.js +14 -16
- package/examples/api/thumb-screw-clamp.forge.js +15 -0
- package/package.json +20 -2
- package/dist/assets/EditorApp-DNH1TEz1.js +0 -12729
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: forgecad-make-a-model
|
|
3
|
-
description: Create
|
|
3
|
+
description: Create manufacture-realistic prototype ForgeCAD (.forge.js) models in the active CAD project. Handles file placement, invokes the forgecad skill for API guidance, and validates the result.
|
|
4
4
|
forgecad-public: true
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,6 +8,17 @@ forgecad-public: true
|
|
|
8
8
|
|
|
9
9
|
Create new ForgeCAD models in the user's active ForgeCAD project.
|
|
10
10
|
|
|
11
|
+
## Default Output Standard
|
|
12
|
+
|
|
13
|
+
Unless the user explicitly asks for a rough blockout, toy, pure visual study, mass-production release package, or specific manufacturing process, the output is a **manufacture-realistic prototype**.
|
|
14
|
+
|
|
15
|
+
That means the model should look and behave like a serious prototype someone could fabricate, buy parts for, assemble, inspect, and iterate in a real shop or product lab. It is not a casual concept sketch, not a universal 3D-printing exercise, and not a claim of certified production readiness.
|
|
16
|
+
|
|
17
|
+
- Choose processes that fit the artifact: machined, sheet-metal, tube, wood/composite, laser-cut, molded-look prototype, printed, or hybrid purchased-hardware construction as appropriate.
|
|
18
|
+
- Include prototype-real features: wall thickness, fastener stacks, bosses, ribs, flanges, bends, seats, bushings, gaskets, cable exits, service access, toleranced clearances, and believable purchased parts.
|
|
19
|
+
- Use production cues only when they help prototype realism. Do not invent expensive production tooling details, certification claims, or safety ratings unless the user asked for that level.
|
|
20
|
+
- If the user asks for `production-realistic`, push toward manufacturing DFM and production-intent materials. If they ask for `printable`, make the selected printed parts honest. If they ask for `visual-CAD`, keep it clearly visual rather than pretending it is build-ready.
|
|
21
|
+
|
|
11
22
|
## File Placement
|
|
12
23
|
|
|
13
24
|
All new `.forge.js` files go under the date-based directory structure:
|
|
@@ -35,6 +46,7 @@ Use today's date for the directory. Use the user's current ForgeCAD project when
|
|
|
35
46
|
1. Load the ForgeCAD skill — always invoke the `forgecad` skill first to get API docs and authoring guidance. Read at minimum the Core API reference. If any two parts are intended to touch or mate in the final model, read the positioning guide immediately and default to connectors + `matchTo()`.
|
|
36
47
|
2. Create the directory — `mkdir -p YYYY/MM/DD/[folder]` as needed.
|
|
37
48
|
3. Write the model — create the `.forge.js` file(s) following ForgeCAD conventions:
|
|
49
|
+
- Treat the default build profile as `manufacture-realistic prototype`; choose and encode the artifact's manufacturing/process cues before adding styling detail
|
|
38
50
|
- Declare `param()` / `boolParam()` for all tunable dimensions
|
|
39
51
|
- If the model is split across files, use `main.forge.js` as the primary entry point, import renderable parts from neighboring `.forge.js` files, and keep only pure helpers/constants in plain `.js` modules
|
|
40
52
|
- When there are multiple versions of the same object, expose the version as a choice parameter and render one selected version at a time
|
|
@@ -47,12 +59,12 @@ Use today's date for the directory. Use the user's current ForgeCAD project when
|
|
|
47
59
|
- Return the final geometry (single shape, array, or named objects array)
|
|
48
60
|
- Treat `fillet(shape, r)` and `chamfer(shape, r)` as experimental edge treatments: Manifold can produce incorrect results and OCCT can be very slow. Prefer simpler primitive profiles, lower segment counts, targeted edge selectors, and inspection before relying on the result.
|
|
49
61
|
4. Validate — run `forgecad run <file>` to check for errors. For multi-file projects, always validate `main.forge.js`.
|
|
50
|
-
5. Verify geometry — render the result, run `forgecad run --connectivity` when the model has multiple returned objects or visible attachments, and run `forgecad render inspect` with the relevant channels for the task (see Final Acceptance Gate and Render-Verify Loop below). For multi-file projects, render and inspect `main.forge.js`.
|
|
62
|
+
5. Verify geometry — render the result, run `forgecad run --connectivity` when the model has multiple returned objects or visible attachments, run `forgecad debug assembly --fail-on warning` when the script uses `assembly()`, run `forgecad inspect mechanical-integrity <project-or-file> --collisions` before sharing generated mechanical work, and run `forgecad render inspect` with the relevant channels for the task (see Final Acceptance Gate and Render-Verify Loop below). For multi-file projects, render and inspect `main.forge.js`.
|
|
51
63
|
|
|
52
64
|
## Manufacturing Process Is Not Assumed
|
|
53
65
|
|
|
54
66
|
Do not interpret every ForgeCAD model as a printable object.
|
|
55
|
-
Choose the manufacturing/process cues that fit the artifact unless the user explicitly asked for a specific process.
|
|
67
|
+
Choose the manufacturing/process cues that fit the artifact unless the user explicitly asked for a specific process. A manufacture-realistic prototype can be CNC-machined, bent sheet, tube-and-plate, wood/composite, molded-look low-volume, printed, or hybrid; the right answer depends on the load path and operating story.
|
|
56
68
|
|
|
57
69
|
- For rideable products such as scooters, bikes, skateboards, carts, or mobility-adjacent devices, use realistic metal/composite/wood structural members, purchased wheels/bearings/axles/brakes/grips, and standard hardware unless the user asked for a printable toy/model.
|
|
58
70
|
- For furniture and load-bearing structures, consider wood, sheet goods, tube, metal brackets, conventional joinery, and printed parts only where they are honest secondary components.
|
|
@@ -104,6 +116,52 @@ Do not reveal hidden structure by permanently cutting away the production geomet
|
|
|
104
116
|
|
|
105
117
|
When internals are hidden by the final exterior, verify them with exploration tools instead of changing the artifact: render underside or alternate camera views, use `render inspect` section channels, use viewer-only cut planes or explode controls, temporarily make a shell transparent, or add named ghost objects for fit checks. Those views are diagnostic/presentation modes; they must not replace the real model unless the user explicitly asked for a cutaway teaching model.
|
|
106
118
|
|
|
119
|
+
## Mechanical Assembly Contract
|
|
120
|
+
|
|
121
|
+
For mechanical models, a ForgeCAD script is not done when it merely looks assembled. Every visible piece must have a believable physical reason to be where it is: fused material, contact faces, a screw stack, a pin in a bore, a tab in a slot, a gasket on a land, a bearing in a seat, a cable in a channel, or a named intentional ghost.
|
|
122
|
+
|
|
123
|
+
- For bespoke fixed assemblies that do not match an existing `lib.*` helper, start from `examples/api/static-assembly-connectors.forge.js`: build each part in local coordinates, pick one root part, place every other touching part with `matchTo()`, and verify the mate with `verify.connectorDistance(...)`. Do not use final `translate()` calls as assembly contracts.
|
|
124
|
+
- If you use `assembly().addPart()`, do not treat `addFixed()`, `addRevolute()`, or `addPrismatic()` with a manual `frame: Transform.identity().translate(...)` as a physical contract. Manual joint frames are acceptable only as a temporary scaffold. Before delivery, convert mating interfaces to connectors with `connect()` / `match()` where the interfaces physically meet, or prove the manual joint with `forgecad debug assembly --fail-on warning` and documented geometry.
|
|
125
|
+
- A named assembly part should not contain unintentional disconnected bodies. If a "cover plate" contains floating pull tabs, loose screw heads, or a separate gasket, either boolean-join the manufactured features, model the fasteners/seals as separate named parts, or provide the receiving holes/lands that explain the separation.
|
|
126
|
+
- Screws are not decoration. A screw needs a clearance/counterbore in the cover, a receiving threaded hole/boss or through stack in the parent, enough material around both, and aligned axes from one shared bolt pattern.
|
|
127
|
+
- Handles and levers need a load path. Model the hub-to-arm connection, pivot pin/bore, thrust washers or shoulders, stops/detents where relevant, and the connected follower/contact surface. A handle tangent to a hub is a failed mechanism.
|
|
128
|
+
- Covers, doors, cartridges, and service panels need seats. Model ledges, gasket grooves, bosses, snap hooks, tabs, or hinge barrels, then show how the removable part is retained.
|
|
129
|
+
- Cables, wires, and tubes need receiving geometry. Model a gland, grommet, clamp, socket, ferrule, routed channel, or hose barb; do not let a cylinder end in open space.
|
|
130
|
+
- Purchased loose parts may remain separate bodies, but they should be named as purchased hardware or consumables and should sit in believable sockets, bores, races, guides, or fastener stacks.
|
|
131
|
+
- Encode interface intent with `verify.*`, not only comments. Use `verify.clearanceBetween("cover is seated on gasket", cover, gasket, -0.01, 0.05)` for contact/seated fits and clearance bands, `verify.minClearance(...)` or `verify.notColliding(...)` for keep-out/running gaps, and `verify.connectorDistance(...)` for connector-authored mates. Part counts and generic dimensions are useful supporting checks, but they do not prove an interface by themselves.
|
|
132
|
+
|
|
133
|
+
For ordinary removable covers, prefer `lib.boltedServiceCover(...)` before hand-placing plates, tabs, screw heads, gaskets, and holes. It creates the parent ledge, gasket, cover plate with fused pull tabs, shared bolt pattern, and installed screws as one mechanically accountable interface.
|
|
134
|
+
|
|
135
|
+
For electronics boxes, backplates, service-stack housings, and camera/monitor enclosures, prefer `lib.datumEnclosureAssembly(...)` before independently placing panels, ribs, bosses, ports, covers, and screws. It creates the tray, ledges, standoffs, ribs, service port, gasket, cover, and screws from one shared datum system.
|
|
136
|
+
|
|
137
|
+
For PCB-mounted terminal blocks, thermostat backplates, control boards, and wire-entry electronics panels, prefer `lib.pcbTerminalBlockAssembly(...)` before placing a loose green block near a board or cover. It creates the backplate, fused standoffs, PCB mounting screws, PCB pin holes, terminal pins, and seated purchased terminal block from one shared datum system.
|
|
138
|
+
|
|
139
|
+
For snap-retained covers, cartridges, small clasps, and housings, prefer `lib.snapLatchCoverAssembly(...)` before drawing decorative snap tabs. It creates latch windows, underside catch lands, fused snap hooks, barbs, and clearance checks so the cover is retained by real geometry.
|
|
140
|
+
|
|
141
|
+
For ordinary pinned handles, cam levers, release levers, and latch arms, prefer `lib.pinnedLeverAssembly(...)` before hand-placing a hub, arm, washers, and pin. It creates a fused lever body, aligned pivot bore, retained pin, thrust washers, support land, and low stop land as one mechanically accountable pivot stack.
|
|
142
|
+
|
|
143
|
+
For trunnions, side knobs, adjustable pivots, and clamp shafts, prefer `lib.retainedShaftAssembly(...)` before hand-placing rods, washers, and knobs. It creates bored support cheeks, a through shaft, thrust washers, knobs, retaining heads, and shared bore dimensions as one mechanically accountable stack.
|
|
144
|
+
|
|
145
|
+
For thumb screws, desk clamps, vise screws, capo pressure screws, and small fixture hold-downs, prefer `lib.thumbScrewClampAssembly(...)` before hand-placing a knob, screw cylinder, pressure pad, and bracket jaw. It creates the C-frame, threaded boss/bore, captive pressure pad, hand knob, and seated workpiece contact from one shared datum system.
|
|
146
|
+
|
|
147
|
+
For drawer slides, quick-release plates, and guided linear carriages, prefer `lib.capturedLinearSlide(...)` before hand-placing rails and a block. It creates a U-channel rail with return lips, end stops, a captured carriage, and explicit travel/clearance dimensions.
|
|
148
|
+
|
|
149
|
+
For pump cartridges, filter cassettes, battery cartridges, skeg cassettes, and removable slide-in modules, prefer `lib.capturedCartridgeGuideAssembly(...)` before placing a loose tray and block. It creates return lips, a rear stop, a captured cartridge flange, pull tab, insertion travel, and explicit clearance dimensions.
|
|
150
|
+
|
|
151
|
+
For molded flexible battery doors, sample covers, blister latches, and polypropylene-style service flaps, prefer `lib.livingHingeCoverAssembly(...)` before drawing two plates with a decorative hinge strip. It creates one fused molded strip with fixed leaf, thin flexible web, moving cover leaf, pull lip, snap barb, catch land, and web-thickness checks.
|
|
152
|
+
|
|
153
|
+
For doors, barn-door leaves, lids, locket leaves, and small hinged access panels, prefer `lib.knuckledHingeAssembly(...)` before hand-placing barrels and a pin. It creates alternating fused knuckles, two leaves, a shared bore, and a retained pin as one mechanically accountable hinge.
|
|
154
|
+
|
|
155
|
+
For crank links, damper rod ends, crossheads, and clevis-yoke pivots, prefer `lib.clevisPinJointAssembly(...)` before hand-placing an eyelet and pin. It creates bored clevis ears, a captured center link eye, a rear bridge, and a retained pin as one mechanically accountable load path.
|
|
156
|
+
|
|
157
|
+
For bearings, rollers, burr cartridges, spindle supports, and purchased radial bearings, prefer `lib.seatedBearingAssembly(...)` before hand-placing a ring and shaft near a block. It creates a bored housing, counterbore pocket, bearing shoulder, seated bearing, shaft, collars, and shared clearance dimensions as one mechanically accountable support.
|
|
158
|
+
|
|
159
|
+
For cables, wires, hoses, pump tubes, and panel pass-throughs, prefer `lib.cableGlandAnchorAssembly(...)` before hand-placing a loose cylinder near a wall. It creates the panel clearance hole, hollow gland body, compression nut, and routed cable/tube as one mechanically accountable pass-through.
|
|
160
|
+
|
|
161
|
+
For routed cables, wires, hoses, pump tubes, and sensor leads that run along a surface, prefer `lib.routedTubeClipAssembly(...)` before drawing a tube that floats between endpoints. It creates a base panel, saddle clip bores, clip screw holes, installed screws, and the retained tube route from one shared datum system.
|
|
162
|
+
|
|
163
|
+
For fluid hoses, pump inlets/outlets, filter ports, and lab tubing, prefer `lib.hoseBarbPortAssembly(...)` before drawing a tube that stops at a block. It creates the bored receiver, raised boss, hollow barbed fitting, installed hose, and clamp band as one accountable hose-port interface.
|
|
164
|
+
|
|
107
165
|
## Final Geometry Should Be Physically Plausible
|
|
108
166
|
|
|
109
167
|
Treat each returned part as real matter occupying space. In the final build, separate parts should not intersect unless the intersection is the actual manufacturing intent, such as a welded/fused region, an overmolded insert, or a boolean-unioned solid that is no longer a separate part.
|
|
@@ -112,7 +170,9 @@ Do not use final interpenetration as a placement shortcut. For joints and interf
|
|
|
112
170
|
|
|
113
171
|
Temporary collisions during construction are fine when they are part of how the model is made or verified: oversized cutter solids before `difference()`, overlapping primitives before `union()`, transparent ghost parts for fit checks, or exploratory joint layouts. Those temporary bodies should be consumed, hidden, named as ghosts, or isolated with inspection filters so final collision findings stay meaningful.
|
|
114
172
|
|
|
115
|
-
|
|
173
|
+
If a final overlap is real manufacturing intent, document the exact visible object pair with `verify.intentionalOverlap("rubber grip is overmolded on handle core", rubberGrip, handleCore, "overmolded bonded grip")`. Use this only for welded, fused, overmolded, cast-in, potted, or bonded matter. The mechanical-integrity gate honors it only when the same visible object pair has a confirmed exact collision; unused or non-visible declarations still fail.
|
|
174
|
+
|
|
175
|
+
Before delivery on any multi-part, internal, or mechanical model, run the collision inspection, read the collision channel PNGs, and check `manifest.json`. Fix unexpected overlaps. If a collision is intentional, declare the exact visible pair with `verify.intentionalOverlap(...)` or isolate that inspection with `--focus` / `--hide` so the remaining collision report proves the final assembly is real.
|
|
116
176
|
|
|
117
177
|
## Final Acceptance Gate
|
|
118
178
|
|
|
@@ -126,6 +186,24 @@ Before telling the user the model is done, prove both technical validity and vis
|
|
|
126
186
|
|
|
127
187
|
The reported component count must match the design intent. Treat unexpected islands, accidental fusion, or bbox-only "touching" that does not make physical sense as model bugs.
|
|
128
188
|
|
|
189
|
+
If the script uses `assembly()`, also run:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
forgecad debug assembly model.forge.js --fail-on warning
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Fix warnings about multiple roots, manual joint contracts, disconnected bodies inside parts, unused connectors, solve warnings, and collisions before delivery. If a warning is truly intentional, rename the part or add a short code comment so a reviewer can see the physical reason.
|
|
196
|
+
|
|
197
|
+
For generated mechanical projects or batches, also run:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
forgecad inspect mechanical-integrity . --collisions
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
This is the shareability gate. It fails on missing `verify.*` checks, missing mechanical-interface verification, fragmented named groups, uncontracted manual assemblies, positive-volume object collisions, timeouts, and runtime failures. Do not share a generated mechanical model while this gate is red unless the user explicitly asked for a rough concept/blockout.
|
|
204
|
+
|
|
205
|
+
The model should include at least one verification that proves a mechanical interface, not just object count. Prefer checks such as `verify.clearanceBetween("bearing is seated in pocket", bearing, housing, -0.01, 0.1)`, `verify.minClearance("carriage clears rail", carriage, rail, 0.15)`, `verify.notColliding("cover screw clears parent hole", screw, parent)`, or `verify.connectorDistance("leg connector is seated", bench, "Rail.leg_0", "Leg0.head", 0, 0.01)`.
|
|
206
|
+
|
|
129
207
|
2. Run a collision bundle and read both the manifest and images:
|
|
130
208
|
|
|
131
209
|
```bash
|
|
@@ -240,13 +318,14 @@ return [
|
|
|
240
318
|
|
|
241
319
|
This immediately reveals: does it fit? Does it collide with walls? Does the shaft clear the opening?
|
|
242
320
|
|
|
243
|
-
### Use console.log for
|
|
321
|
+
### Use verify for acceptance, console.log for traces
|
|
244
322
|
|
|
245
|
-
|
|
323
|
+
Use `verify.*` for dimensions and clearances that decide whether the model is acceptable. Use `console.log()` only for explanatory traces that help you read the run output.
|
|
246
324
|
|
|
247
325
|
```js
|
|
248
|
-
|
|
249
|
-
|
|
326
|
+
verify.greaterThan("wall remains around slot", (outerW - slotW) / 2, 1.6);
|
|
327
|
+
verify.greaterThan("hole clears flange edge", flangeW / 2 - holeX - holeDia / 2, 2.0);
|
|
328
|
+
console.log("wall remaining:", ((outerW - slotW) / 2).toFixed(1));
|
|
250
329
|
```
|
|
251
330
|
|
|
252
331
|
Output appears under "Script output:" in `forgecad run`.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: forgecad-prepare-prompt
|
|
3
|
-
description: Turn a fuzzy physical product, mechanism, or CAD artifact request into a concrete ForgeCAD build brief and a single master prompt for the modeling pass. Use when the engineering brief is incomplete, manufacturing/process choice is underspecified, or the work needs a specific operating story to avoid generic toy solutions.
|
|
3
|
+
description: Turn a fuzzy physical product, mechanism, or CAD artifact request into a concrete manufacture-realistic prototype ForgeCAD build brief and a single master prompt for the modeling pass. Use when the engineering brief is incomplete, manufacturing/process choice is underspecified, or the work needs a specific operating story to avoid generic toy solutions.
|
|
4
4
|
forgecad-public: true
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Prepare ForgeCAD Prompt
|
|
8
8
|
|
|
9
|
-
Use this skill before modeling when the user wants something physically real, manufacturing-aware, and buildable, but their request sounds like:
|
|
9
|
+
Use this skill before modeling when the user wants something physically real, manufacturing-aware, and buildable as a manufacture-realistic prototype, but their request sounds like:
|
|
10
10
|
|
|
11
11
|
- "make me a robot gripper"
|
|
12
12
|
- "design a real mechanism"
|
|
@@ -25,6 +25,10 @@ Choose the manufacturing/process stack from the artifact family, load path, scal
|
|
|
25
25
|
For example: scooters, bikes, skateboards, and rideable vehicles usually point toward metal/composite frames, wood/composite decks, urethane/rubber wheels, bearings, brakes, and standard hardware; furniture often points toward wood, sheet goods, tube, metal brackets, or conventional joinery; enclosures may point toward injection molding, sheet metal, CNC, or printing depending on quantity and ruggedness; fixtures may be machined, laser-cut, welded, printed, or hybrid.
|
|
26
26
|
If the user asks for "printable", "3D printed", "laser cut", "CNC", or another process, honor that process while still warning when it is unsafe or dishonest for the duty.
|
|
27
27
|
|
|
28
|
+
The default output posture is **manufacture-realistic prototype** unless the user asks for a different posture.
|
|
29
|
+
This means a serious prototype build candidate with real manufacturing cues, purchased-part boundaries, assembly logic, and validation loops. It is stronger than a visual concept or hobby sketch, but it does not claim final production tooling, certification, rider safety, medical compliance, or release-ready DFM.
|
|
30
|
+
Use `production-realistic` only when the user wants production intent, `printable` only when printing is actually the selected process, and `visual-CAD` only for visual/form studies.
|
|
31
|
+
|
|
28
32
|
Do not let the modeling prompt sound like a casual hobby sketch when the requested artifact belongs to a serious product domain.
|
|
29
33
|
Give the model a specific operating story: a named company or lab, named program, named prototype/revision, review moment, test setting, and concrete reason the part matters.
|
|
30
34
|
If the user did not provide this story, invent plausible non-famous names and details.
|
|
@@ -61,6 +65,7 @@ By the end of this skill, there should be:
|
|
|
61
65
|
- an artifact family classification
|
|
62
66
|
- an assumption bundle with units
|
|
63
67
|
- a clear build profile and manufacturing/process stack
|
|
68
|
+
- a stated output posture, defaulting to manufacture-realistic prototype unless the user chose otherwise
|
|
64
69
|
- a specific operating story
|
|
65
70
|
- a motion / load / size target
|
|
66
71
|
- a BOM boundary
|
|
@@ -124,8 +129,9 @@ By the end of this skill, there should be:
|
|
|
124
129
|
|
|
125
130
|
4. Choose manufacturing/process posture.
|
|
126
131
|
Treat process selection as part of the brief.
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
Default to `manufacture-realistic prototype`.
|
|
133
|
+
Use `production-realistic`, `prototype-realistic`, `printable`, `visual-CAD`, or a more specific process such as `sheet-metal`, `CNC-machined`, `laser-cut`, `welded tube`, `injection-molded`, `cast`, or `hybrid purchased-hardware` only when the brief justifies that more specific posture.
|
|
134
|
+
Choose the posture that is honest for the artifact rather than the easiest CAD surface to make.
|
|
129
135
|
|
|
130
136
|
5. Pick qualitative levers, not raw numbers.
|
|
131
137
|
Start from:
|
|
@@ -141,7 +147,7 @@ By the end of this skill, there should be:
|
|
|
141
147
|
- for a gripper: object style, opening band, cost/performance posture
|
|
142
148
|
- for a table: use style, span band, load style
|
|
143
149
|
- for an enclosure: electronics size, ruggedness, cooling posture
|
|
144
|
-
- for an underspecified product:
|
|
150
|
+
- for an underspecified product: manufacture-realistic prototype, production-realistic, printable, or visual-CAD posture
|
|
145
151
|
|
|
146
152
|
7. Convert choices into an engineering brief.
|
|
147
153
|
The brief must include:
|
|
@@ -151,6 +157,7 @@ By the end of this skill, there should be:
|
|
|
151
157
|
- production reason
|
|
152
158
|
- test setting
|
|
153
159
|
- what generic output would miss
|
|
160
|
+
- output posture, defaulting to manufacture-realistic prototype unless changed by the user
|
|
154
161
|
- intended objects / loads
|
|
155
162
|
- rough size envelope
|
|
156
163
|
- motion style and degrees of freedom
|
|
@@ -184,7 +191,7 @@ Good:
|
|
|
184
191
|
- "Which target feels closest: a light desk demo, a useful hobby tool, or a sturdier bench mechanism?"
|
|
185
192
|
- "Will it mostly handle soft/light things, mixed household parts, or rigid/tool-like objects?"
|
|
186
193
|
- "Should we bias for cheapest parts, balanced practicality, or stronger hardware?"
|
|
187
|
-
- "Should this be
|
|
194
|
+
- "Should this be a manufacture-realistic prototype, production-realistic, printable, or just a visual CAD study?"
|
|
188
195
|
- "Is this more like a gripper, a fixture, an enclosure, a chassis, or furniture?"
|
|
189
196
|
- "Will the table mostly hold decor, laptop-and-books, or workshop abuse?"
|
|
190
197
|
|
|
@@ -201,6 +208,7 @@ If the user says "I don't know" or gives only a broad goal:
|
|
|
201
208
|
- infer the nearest artifact family from the request
|
|
202
209
|
- invent a specific operating story for the artifact
|
|
203
210
|
- infer the manufacturing/process stack from the artifact family and operating story
|
|
211
|
+
- default the output posture to `manufacture-realistic prototype`
|
|
204
212
|
- choose `general-duty`
|
|
205
213
|
- choose `medium`
|
|
206
214
|
- choose `balanced`
|
|
@@ -16,7 +16,7 @@ They are temporary engineering anchors used only when the user has not provided
|
|
|
16
16
|
|
|
17
17
|
Use these across families before translating into numbers:
|
|
18
18
|
|
|
19
|
-
- manufacturing posture:
|
|
19
|
+
- manufacturing posture: default to `manufacture-realistic prototype` unless specified; common override values are `production-realistic`, `prototype-realistic`, `printable`, and `visual-CAD`
|
|
20
20
|
- duty level: `light-duty`, `general-duty`, `sturdy-duty`
|
|
21
21
|
- scale level: `compact`, `medium`, `large`
|
|
22
22
|
- cost posture: `cheapest`, `balanced`, `performance-first`
|
|
@@ -29,6 +29,8 @@ Do not use 3D printing as the universal default.
|
|
|
29
29
|
Choose the process stack from the artifact family, load path, scale, safety expectations, material properties, quantity/iteration needs, and operating story.
|
|
30
30
|
Only use print defaults when the user explicitly requested printing or the selected process stack includes printed parts.
|
|
31
31
|
|
|
32
|
+
The default posture is `manufacture-realistic prototype`: a credible prototype build candidate with real materials, real purchased parts, plausible fabrication routes, serviceable interfaces, and validation checks. It should be manufacturable enough for a prototype review, but it should not claim final production tooling, certification, or release readiness unless the user asks for that stronger bar.
|
|
33
|
+
|
|
32
34
|
Examples:
|
|
33
35
|
|
|
34
36
|
- rideable vehicles: metal/composite/wood structure, urethane/rubber wheels, bearings, brakes, fasteners, and purchased safety-critical hardware
|
|
@@ -274,7 +276,7 @@ Do not make rideable load paths printed by default.
|
|
|
274
276
|
|
|
275
277
|
### Family Questions
|
|
276
278
|
|
|
277
|
-
- Is this a visual/product CAD study, a
|
|
279
|
+
- Is this a visual/product CAD study, a manufacture-realistic prototype build candidate, or a specifically printable toy/model?
|
|
278
280
|
- Is it for child-scale, adult-scale, display-scale, or cargo/utility scale?
|
|
279
281
|
- Does it need steering, braking, folding, suspension, or only static product form?
|
|
280
282
|
|
|
@@ -288,7 +290,7 @@ Do not make rideable load paths printed by default.
|
|
|
288
290
|
|
|
289
291
|
`general-duty`
|
|
290
292
|
|
|
291
|
-
- adult product form or
|
|
293
|
+
- adult product form or manufacture-realistic prototype scooter/bike/cart architecture
|
|
292
294
|
- aluminum or steel tube/frame members, machined or cast fork/dropout-like features, wood/composite/aluminum deck where appropriate
|
|
293
295
|
- urethane/rubber wheels, real bearings, axles, fasteners, spacers, grip tape, grips, and purchased brake/steering hardware where appropriate
|
|
294
296
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# ForgeCAD
|
|
1
|
+
# ForgeCAD Manufacture-Realistic Prototype Master Prompt
|
|
2
2
|
|
|
3
3
|
Fill the placeholders and return the finished prompt as one block.
|
|
4
4
|
|
|
5
5
|
```text
|
|
6
|
-
You are producing a ForgeCAD
|
|
6
|
+
You are producing a ForgeCAD manufacture-realistic prototype package, not a concept sketch.
|
|
7
7
|
|
|
8
8
|
Treat this as a serious product-team prototype assignment.
|
|
9
|
-
The goal is to produce a credible internal engineering package for a real build candidate, not a generic maker example.
|
|
9
|
+
The goal is to produce a credible internal engineering package for a real prototype build candidate, not a generic maker example.
|
|
10
10
|
Use the specific operating story below to drive engineering choices; do not flatten it into a vague domain label.
|
|
11
11
|
|
|
12
12
|
Target artifact:
|
|
@@ -25,6 +25,7 @@ Specific operating story:
|
|
|
25
25
|
- benchmark class / public comparison anchor, if useful: {benchmark_class}
|
|
26
26
|
|
|
27
27
|
Chosen intake classification:
|
|
28
|
+
- output posture: manufacture-realistic prototype unless the user explicitly selected another posture
|
|
28
29
|
- artifact family: {artifact_family}
|
|
29
30
|
- duty level: {duty_level}
|
|
30
31
|
- scale level: {scale_level}
|
|
@@ -46,6 +47,7 @@ Hard constraints:
|
|
|
46
47
|
- if the mechanism has moving parts, use a real `assembly()` from iteration 1
|
|
47
48
|
- define real joints, limits, axes, and intended operating ranges
|
|
48
49
|
- choose manufacturing/processes that fit the artifact, load path, scale, safety expectations, and operating story
|
|
50
|
+
- default to manufacture-realistic prototype: real prototype materials, fabrication cues, purchased parts, assembly logic, serviceability, and validation without pretending to be production-certified or release-ready
|
|
49
51
|
- do not assume FDM, 3D printing, or "printable" unless the user explicitly asked for it or the chosen process stack includes printed parts
|
|
50
52
|
- include realistic process-appropriate clearances and mechanically honest interfaces
|
|
51
53
|
- include manufactured, printed, and purchased parts only where each is an honest choice
|
|
@@ -64,7 +66,7 @@ Acceptable final states:
|
|
|
64
66
|
1. `BUILD-READY`
|
|
65
67
|
2. `BEST-EFFORT BUILD CANDIDATE`
|
|
66
68
|
|
|
67
|
-
`BUILD-READY` means the output is specific enough that a competent builder could start fabricating, machining, printing, buying parts, assembling, and testing immediately without inventing missing details.
|
|
69
|
+
`BUILD-READY` means the output is specific enough that a competent builder could start fabricating, machining, printing selected printed parts, buying parts, assembling, and testing the prototype immediately without inventing missing details.
|
|
68
70
|
|
|
69
71
|
`BEST-EFFORT BUILD CANDIDATE` means you still provide the strongest concrete design possible, but you explicitly name the smallest unavoidable validation loop that remains.
|
|
70
72
|
|
|
@@ -105,7 +107,7 @@ Required outputs:
|
|
|
105
107
|
- Specify the actuator class, approximate required torque/force, transmission approach, and why they fit the chosen profile.
|
|
106
108
|
|
|
107
109
|
6. Manufacturing package
|
|
108
|
-
- For each critical part: material, manufacturing process, setup/orientation/tooling/finish assumptions, serviceability notes, and features sensitive to process accuracy.
|
|
110
|
+
- For each critical part: material, manufacturing process, prototype setup/orientation/tooling/finish assumptions, serviceability notes, and features sensitive to process accuracy.
|
|
109
111
|
- If the selected process includes printed parts, include print orientation, likely support strategy, and print-sensitive features for those parts.
|
|
110
112
|
|
|
111
113
|
7. Bill of materials
|
|
@@ -158,7 +158,7 @@ PNG review order:
|
|
|
158
158
|
## Interpretation Rules
|
|
159
159
|
|
|
160
160
|
- Collision findings are positive-volume boolean overlaps. Face-touching is not a collision.
|
|
161
|
-
- Connectivity
|
|
161
|
+
- Connectivity uses bbox as a broadphase, then exact overlap evidence for component grouping. Bbox-only contact does not merge separate scene objects by default; use the collisions channel for positive-volume overlap evidence.
|
|
162
162
|
- Distance is a bbox-gap metric between physical components, not exact closest surface distance.
|
|
163
163
|
- Thickness is a mesh/raycast approximation. Gray or high unresolved area means the visual heatmap is incomplete, not that the model is safe.
|
|
164
164
|
- Depth is a visual heatmap, not raw floating-point depth data.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Bolted service cover: parent ledge, gasket, fused pull tabs, aligned holes, and installed screws.
|
|
2
|
+
|
|
3
|
+
const cover = lib.boltedServiceCover({
|
|
4
|
+
width: 90,
|
|
5
|
+
depth: 56,
|
|
6
|
+
coverThickness: 3,
|
|
7
|
+
parentThickness: 8,
|
|
8
|
+
ledgeWidth: 10,
|
|
9
|
+
screwSize: 'M4',
|
|
10
|
+
boltInset: [6, 6],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
verify.equal('four retained cover screws', cover.screws.length, 4);
|
|
14
|
+
verify.greaterThan('cover has edge margin around service opening', cover.dims.ledgeWidth, 6);
|
|
15
|
+
verify.notColliding('cover does not collide with gasket', cover.cover, cover.gasket);
|
|
16
|
+
|
|
17
|
+
return cover.parts;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const anchor = lib.cableGlandAnchorAssembly({
|
|
2
|
+
cableDiameter: 6,
|
|
3
|
+
panelThickness: 3,
|
|
4
|
+
panelWidth: 62,
|
|
5
|
+
panelHeight: 44,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
verify.equal('cable gland anchor has four retained parts', anchor.parts.length, 4);
|
|
9
|
+
verify.greaterThan('panel leaves material around gland flange', anchor.dims.panelHeight - anchor.dims.flangeDiameter, 8);
|
|
10
|
+
verify.notColliding('cable clears gland bore', anchor.cable, anchor.gland);
|
|
11
|
+
verify.notColliding('gland clears panel hole', anchor.gland, anchor.panel);
|
|
12
|
+
verify.clearanceBetween('gland flange is seated at panel pocket', anchor.gland, anchor.panel, 0.01, 0.2);
|
|
13
|
+
|
|
14
|
+
return anchor.parts;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const cassette = lib.capturedCartridgeGuideAssembly({
|
|
2
|
+
length: 150,
|
|
3
|
+
cartridgeLength: 72,
|
|
4
|
+
insertion: 28,
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
verify.equal('cartridge guide has guide and removable cassette', cassette.parts.length, 2);
|
|
8
|
+
verify.notColliding('cartridge clears guide rails and rear stop', cassette.cartridge, cassette.guide);
|
|
9
|
+
verify.greaterThan('cartridge flange is captured by guide lips', cassette.dims.cartridgeWidth, cassette.dims.throatWidth);
|
|
10
|
+
verify.lessThan('cartridge still clears inner guide width', cassette.dims.cartridgeWidth, cassette.dims.innerWidth);
|
|
11
|
+
verify.greaterThan('cartridge body passes through the guide throat', cassette.dims.throatWidth, cassette.dims.cartridgeBodyWidth);
|
|
12
|
+
verify.inRange('cartridge insertion stays inside travel', cassette.dims.insertion, 0, cassette.dims.maxInsertion);
|
|
13
|
+
|
|
14
|
+
return cassette.parts;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const slide = lib.capturedLinearSlide({
|
|
2
|
+
length: 160,
|
|
3
|
+
railWidth: 38,
|
|
4
|
+
carriageLength: 52,
|
|
5
|
+
travel: 42,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
verify.equal('captured slide has rail and carriage parts', slide.parts.length, 2);
|
|
9
|
+
verify.greaterThan('carriage is wider than the throat opening', slide.dims.carriageWidth, slide.dims.throatWidth);
|
|
10
|
+
verify.greaterThan('slide retains usable travel', slide.dims.maxTravel, 80);
|
|
11
|
+
verify.minClearance('carriage clears captured rail', slide.carriage, slide.rail, 0.05);
|
|
12
|
+
|
|
13
|
+
return slide.parts;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const clevis = lib.clevisPinJointAssembly({
|
|
2
|
+
pinDiameter: 4,
|
|
3
|
+
linkThickness: 6,
|
|
4
|
+
linkArmLength: 38,
|
|
5
|
+
earThickness: 4,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
verify.equal('clevis joint has three retained parts', clevis.parts.length, 3);
|
|
9
|
+
verify.greaterThan('link eye has material around pin bore', clevis.dims.eyeOuterRadius - clevis.dims.boreDiameter / 2, 4);
|
|
10
|
+
verify.greaterThan('clevis gap clears the link eye', clevis.dims.clevisGap, clevis.dims.linkThickness);
|
|
11
|
+
verify.minClearance('link eye clears clevis yoke', clevis.link, clevis.clevis, 0.05);
|
|
12
|
+
|
|
13
|
+
return clevis.parts;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const enclosure = lib.datumEnclosureAssembly({
|
|
2
|
+
width: 96,
|
|
3
|
+
depth: 64,
|
|
4
|
+
height: 18,
|
|
5
|
+
screwSize: 'M3',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
verify.equal('datum enclosure has base gasket cover and four screws', enclosure.parts.length, 7);
|
|
9
|
+
verify.greaterThan('internal cavity keeps usable width', enclosure.dims.innerWidth, 80);
|
|
10
|
+
verify.greaterThan('standoff wall remains around screw envelope', enclosure.dims.standoffDiameter - enclosure.dims.threadEnvelopeDia, 4);
|
|
11
|
+
verify.greaterThan('service port leaves top wall material', enclosure.dims.height - enclosure.dims.baseThickness - enclosure.dims.portHeight, 6);
|
|
12
|
+
verify.notColliding('cover clears seated gasket', enclosure.cover, enclosure.gasket);
|
|
13
|
+
verify.notColliding('first screw clears standoff thread envelope', enclosure.screws[0], enclosure.base);
|
|
14
|
+
verify.inRange('cover stack has small seating clearance', enclosure.dims.faceClearance, 0.01, 0.08);
|
|
15
|
+
|
|
16
|
+
return enclosure.parts;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guided loft vs ProductSkin: olive oil bottle.
|
|
3
|
+
*
|
|
4
|
+
* Left: the new namespaced Loft.withGuideRails(...) primitive. Right: the
|
|
5
|
+
* equivalent Product.skin(...) authoring style for comparison.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
Product.scenePreset('product');
|
|
9
|
+
|
|
10
|
+
viewConfig({
|
|
11
|
+
camera: { position: [190, -250, 150], target: [8, 0, 88], fov: 34 },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const darkOlive = {
|
|
15
|
+
color: '#34462f',
|
|
16
|
+
material: {
|
|
17
|
+
opacity: 0.58,
|
|
18
|
+
roughness: 0.14,
|
|
19
|
+
metalness: 0,
|
|
20
|
+
clearcoat: 1,
|
|
21
|
+
clearcoatRoughness: 0.04,
|
|
22
|
+
transmission: 0.28,
|
|
23
|
+
thickness: 4,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const labelStock = Product.materials.mattePlastic('#eee8d8');
|
|
27
|
+
const blackCap = Product.materials.softRubber({ color: '#171a15' });
|
|
28
|
+
|
|
29
|
+
const guidedStations = [
|
|
30
|
+
Loft.station(roundedRect(52, 34, 8), 0),
|
|
31
|
+
Loft.station(roundedRect(60, 38, 11), 78),
|
|
32
|
+
Loft.station(roundedRect(42, 27, 10), 128),
|
|
33
|
+
Loft.station(circle2d(12, 64), 166),
|
|
34
|
+
Loft.station(circle2d(14, 64), 184),
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const leftSilhouette = path()
|
|
38
|
+
.moveTo(-26, 0)
|
|
39
|
+
.bezierTo(-31, 30, -33, 55, -31, 72)
|
|
40
|
+
.bezierTo(-30, 90, -27, 107, -25, 118)
|
|
41
|
+
.bezierTo(-20, 142, -12, 152, -12, 166)
|
|
42
|
+
.lineTo(-14, 184);
|
|
43
|
+
|
|
44
|
+
const rightSilhouette = path()
|
|
45
|
+
.moveTo(26, 0)
|
|
46
|
+
.bezierTo(31, 30, 33, 55, 31, 72)
|
|
47
|
+
.bezierTo(30, 90, 27, 107, 25, 118)
|
|
48
|
+
.bezierTo(20, 142, 12, 152, 12, 166)
|
|
49
|
+
.lineTo(14, 184);
|
|
50
|
+
|
|
51
|
+
const backCrown = path()
|
|
52
|
+
.moveTo(-17, 0)
|
|
53
|
+
.bezierTo(-21, 30, -22, 56, -20, 72)
|
|
54
|
+
.bezierTo(-19, 92, -17, 108, -16, 118)
|
|
55
|
+
.bezierTo(-13, 142, -10, 154, -10, 166)
|
|
56
|
+
.lineTo(-12, 184);
|
|
57
|
+
|
|
58
|
+
const frontCrown = path()
|
|
59
|
+
.moveTo(17, 0)
|
|
60
|
+
.bezierTo(22, 30, 24, 56, 22, 72)
|
|
61
|
+
.bezierTo(21, 92, 19, 108, 18, 118)
|
|
62
|
+
.bezierTo(14, 142, 10, 154, 10, 166)
|
|
63
|
+
.lineTo(12, 184);
|
|
64
|
+
|
|
65
|
+
const leftRail = Loft.pathOnXz(leftSilhouette);
|
|
66
|
+
const rightRail = Loft.pathOnXz(rightSilhouette);
|
|
67
|
+
const backRail = Loft.pathOnYz(backCrown);
|
|
68
|
+
const frontRail = Loft.pathOnYz(frontCrown);
|
|
69
|
+
|
|
70
|
+
const guidedBottle = Loft.withGuideRails(
|
|
71
|
+
guidedStations,
|
|
72
|
+
[
|
|
73
|
+
Loft.leftRail(leftRail),
|
|
74
|
+
Loft.rightRail(rightRail),
|
|
75
|
+
Loft.backRail(backRail),
|
|
76
|
+
Loft.frontRail(frontRail),
|
|
77
|
+
],
|
|
78
|
+
{ samples: 19, edgeLength: 1.3 },
|
|
79
|
+
)
|
|
80
|
+
.as('guided-loft-olive-glass')
|
|
81
|
+
.material(darkOlive.material)
|
|
82
|
+
.color(darkOlive.color);
|
|
83
|
+
|
|
84
|
+
const guidedLabel = Product.applyMaterial(
|
|
85
|
+
roundedRect(34, 58, 4)
|
|
86
|
+
.extrude(0.8)
|
|
87
|
+
.rotateX(90)
|
|
88
|
+
.translate(0, 22.5, 76)
|
|
89
|
+
.as('guided-loft-cream-label'),
|
|
90
|
+
labelStock,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const guidedCap = Product.applyMaterial(cylinder(18, 12, 12, 64).translate(0, 0, 184).as('guided-loft-black-cap'), blackCap);
|
|
94
|
+
|
|
95
|
+
const guided = group(
|
|
96
|
+
{ name: 'body', shape: guidedBottle },
|
|
97
|
+
{ name: 'label', shape: guidedLabel },
|
|
98
|
+
{ name: 'cap', shape: guidedCap },
|
|
99
|
+
).translate(-52, 0, 0);
|
|
100
|
+
|
|
101
|
+
const productBottle = Product.skin('product-skin-olive-glass')
|
|
102
|
+
.axis('Z')
|
|
103
|
+
.stations([
|
|
104
|
+
Product.station('base').z(0).roundedRect(52, 34, 8),
|
|
105
|
+
Product.station('body').z(78).roundedRect(60, 38, 11),
|
|
106
|
+
Product.station('shoulder').z(128).roundedRect(42, 27, 10),
|
|
107
|
+
Product.station('neck').z(166).circle(24),
|
|
108
|
+
Product.station('lip').z(184).circle(28),
|
|
109
|
+
])
|
|
110
|
+
.rails({
|
|
111
|
+
leftSilhouette: Product.rail.polyline(leftRail),
|
|
112
|
+
frontCrown: Product.rail.polyline(frontRail),
|
|
113
|
+
})
|
|
114
|
+
.material(darkOlive)
|
|
115
|
+
.edgeLength(1.3)
|
|
116
|
+
.build();
|
|
117
|
+
|
|
118
|
+
const productLabel = Product.applyMaterial(
|
|
119
|
+
roundedRect(34, 58, 4)
|
|
120
|
+
.extrude(0.8)
|
|
121
|
+
.rotateX(90)
|
|
122
|
+
.translate(0, 22.5, 76)
|
|
123
|
+
.as('product-skin-cream-label'),
|
|
124
|
+
labelStock,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const productCap = Product.applyMaterial(cylinder(18, 12, 12, 64).translate(0, 0, 184).as('product-skin-black-cap'), blackCap);
|
|
128
|
+
|
|
129
|
+
const productSkinComparison = group(
|
|
130
|
+
{ name: 'body', shape: productBottle.toShape() },
|
|
131
|
+
{ name: 'label', shape: productLabel },
|
|
132
|
+
{ name: 'cap', shape: productCap },
|
|
133
|
+
).translate(52, 0, 0);
|
|
134
|
+
|
|
135
|
+
return [guided, productSkinComparison];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const hosePort = lib.hoseBarbPortAssembly({
|
|
2
|
+
hoseInnerDiameter: 6,
|
|
3
|
+
hoseOuterDiameter: 10,
|
|
4
|
+
barbCount: 3,
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
verify.equal('hose barb port has receiver fitting hose and clamp', hosePort.parts.length, 4);
|
|
8
|
+
verify.greaterThan('barb peaks retain nominal hose ID', hosePort.dims.barbPeakDiameter, hosePort.dims.hoseInnerDiameter);
|
|
9
|
+
verify.greaterThan('hose has wall around installed barb envelope', hosePort.dims.hoseOuterDiameter - hosePort.dims.installedHoseBoreDiameter, 1.2);
|
|
10
|
+
verify.notColliding('hose clears barb peaks', hosePort.hose, hosePort.fitting);
|
|
11
|
+
verify.notColliding('clamp clears hose outside', hosePort.clamp, hosePort.hose);
|
|
12
|
+
verify.inRange('fitting shoulder seats near boss face', hosePort.dims.faceClearance, 0.01, 0.08);
|
|
13
|
+
|
|
14
|
+
return hosePort.parts;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Intentional overlap: an overmolded grip shares volume with its rigid handle core.
|
|
2
|
+
const handleCore = box(64, 12, 8).color('#64748b');
|
|
3
|
+
const rubberGrip = box(42, 18, 10).translate(6, 0, 0).color('#111827');
|
|
4
|
+
|
|
5
|
+
verify.intentionalOverlap(
|
|
6
|
+
'rubber grip is overmolded on handle core',
|
|
7
|
+
rubberGrip,
|
|
8
|
+
handleCore,
|
|
9
|
+
'overmolded bonded grip around rigid insert',
|
|
10
|
+
);
|
|
11
|
+
verify.greaterThan('rubber grip wraps beyond core width', rubberGrip.boundingBox().max[1], handleCore.boundingBox().max[1]);
|
|
12
|
+
|
|
13
|
+
return [
|
|
14
|
+
{ name: 'Rigid handle core', shape: handleCore },
|
|
15
|
+
{ name: 'Overmolded rubber grip', shape: rubberGrip },
|
|
16
|
+
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const hinge = lib.knuckledHingeAssembly({
|
|
2
|
+
length: 70,
|
|
3
|
+
leafLength: 28,
|
|
4
|
+
leafThickness: 1.8,
|
|
5
|
+
barrelOuterRadius: 3.2,
|
|
6
|
+
pinDiameter: 2,
|
|
7
|
+
openAngleDeg: 42,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
verify.equal('hinge has two leaves and one retained pin', hinge.parts.length, 3);
|
|
11
|
+
verify.greaterThan('barrel wall remains around pin bore', hinge.dims.barrelOuterRadius - hinge.dims.boreDiameter / 2, 1.5);
|
|
12
|
+
verify.greaterThan('hinge has meaningful knuckle length', hinge.dims.knuckleLength, hinge.dims.pinDiameter * 2);
|
|
13
|
+
verify.minClearance('moving leaf clears fixed leaf', hinge.movingLeaf, hinge.fixedLeaf, 0.05);
|
|
14
|
+
|
|
15
|
+
return hinge.parts;
|