forgecad 0.9.4 → 0.9.5
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-jwoEgwE_.js → AdminPage-uTtcSXtn.js} +1 -1
- package/dist/assets/{BlogPage-Ck7g3ue2.js → BlogPage-DYJMjWx3.js} +1 -1
- package/dist/assets/{DocsPage-9WaRC14b.js → DocsPage-C58f0K5v.js} +1 -6
- package/dist/assets/{EditorApp-Dja2jMmW.js → EditorApp-DNH1TEz1.js} +282 -62
- package/dist/assets/{EmbedViewer-37_PfMwv.js → EmbedViewer-CMXWA2LX.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-CO8WL0CY.js → LandingPageProofDriven-CAu2OZFn.js} +1 -1
- package/dist/assets/{PricingPage-DADKGuOa.js → PricingPage-BIgW7m3X.js} +1 -1
- package/dist/assets/{SettingsPage-DKKI4W49.js → SettingsPage-N1l1tMXO.js} +1 -1
- package/dist/assets/{app-CwI02pTA.js → app-CFy7g5WP.js} +74 -12
- package/dist/assets/cli/{render-Kw5hLEcL.js → render-BrVVdj_T.js} +453 -41
- package/dist/assets/{evalWorker-D6ub3kfS.js → evalWorker-c_SB9gg3.js} +2057 -446
- package/dist/assets/{manifold-lru0jwVw.js → manifold-CRoBhJKH.js} +2 -2
- package/dist/assets/{manifold-CwDdMKyc.js → manifold-Cjk7WhRs.js} +1 -1
- package/dist/assets/{manifold-DTvmxSDf.js → manifold-Dp6pvFr6.js} +1 -1
- package/dist/assets/{renderSceneState-tvtNKNRi.js → renderSceneState-3DfsSASX.js} +1 -1
- package/dist/assets/{reportWorker-DeqktDGt.js → reportWorker-BLkuIoS8.js} +2052 -443
- package/dist/assets/{sectionPlaneMath-C8N0w8o3.js → sectionPlaneMath-CykEnkvQ.js} +2258 -518
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/AI/usage.md +0 -1
- package/dist/docs-raw/API/core/concepts.md +11 -1
- package/dist/docs-raw/CLI.md +64 -13
- package/dist/docs-raw/generated/assembly.md +8 -3
- package/dist/docs-raw/generated/concepts.md +44 -41
- package/dist/docs-raw/generated/core.md +97 -47
- package/dist/docs-raw/generated/curves.md +6 -580
- package/dist/docs-raw/generated/lib.md +40 -3
- package/dist/docs-raw/generated/output.md +6 -1
- package/dist/docs-raw/generated/sdf.md +50 -4
- package/dist/docs-raw/generated/viewport.md +1 -9
- package/dist/docs-raw/guides/inspection-bundles.md +31 -6
- package/dist/docs-raw/skills/forgecad-blockout-model.md +1 -0
- package/dist/docs-raw/skills/forgecad-image-replicator.md +3 -1
- package/dist/docs-raw/skills/forgecad-make-a-model.md +48 -4
- package/dist/docs-raw/skills/forgecad-render-inspect.md +3 -1
- package/dist/docs-raw/skills/forgecad-visual-spec.md +2 -0
- package/dist/docs-raw/skills/forgecad.md +2 -1
- package/dist/docs-raw/skills/index.md +0 -1
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +6 -6
- package/dist-cli/blender/render.py +43 -8
- package/dist-cli/forgecad.js +4941 -1758
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-skill/CONTEXT.md +255 -656
- package/dist-skill/SKILL-dev.md +2 -1
- package/dist-skill/SKILL.md +2 -1
- package/dist-skill/docs/API/core/concepts.md +11 -1
- package/dist-skill/docs/CLI.md +64 -13
- package/dist-skill/docs/generated/assembly.md +8 -3
- package/dist-skill/docs/generated/core.md +97 -47
- package/dist-skill/docs/generated/curves.md +6 -580
- package/dist-skill/docs/generated/lib.md +40 -3
- package/dist-skill/docs/generated/output.md +6 -1
- package/dist-skill/docs/generated/sdf.md +50 -4
- package/dist-skill/docs/generated/viewport.md +1 -9
- package/dist-skill/docs/guides/inspection-bundles.md +31 -6
- package/dist-skill/docs-dev/API/core/concepts.md +11 -1
- package/dist-skill/docs-dev/CLI.md +64 -13
- package/dist-skill/docs-dev/generated/assembly.md +8 -3
- package/dist-skill/docs-dev/generated/core.md +97 -47
- package/dist-skill/docs-dev/generated/curves.md +6 -580
- package/dist-skill/docs-dev/generated/lib.md +40 -3
- package/dist-skill/docs-dev/generated/output.md +6 -1
- package/dist-skill/docs-dev/generated/sdf.md +50 -4
- package/dist-skill/docs-dev/generated/viewport.md +1 -9
- package/dist-skill/docs-dev/guides/inspection-bundles.md +31 -6
- package/dist-skill/library/README.md +0 -1
- package/dist-skill/library/forgecad-blockout-model/SKILL.md +1 -0
- package/dist-skill/library/forgecad-image-replicator/SKILL.md +3 -1
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +48 -4
- package/dist-skill/library/forgecad-render-inspect/SKILL.md +3 -1
- package/dist-skill/library/forgecad-visual-spec/SKILL.md +2 -0
- package/examples/api/drive-wheel-regions.forge.js +43 -0
- package/examples/api/sdf-circular-array-knurling.forge.js +19 -0
- package/examples/api/sdf-pattern2d-ceramic-ripple-set.forge.js +83 -0
- package/examples/api/sdf-pattern2d-grip-tread.forge.js +72 -0
- package/examples/api/sdf-pattern2d-orbital-jewelry.forge.js +62 -0
- package/examples/api/sdf-surface-basket-weave.forge.js +67 -0
- package/examples/api/sector-gear-body.forge.js +34 -0
- package/package.json +1 -1
- package/dist/docs-raw/skills/forgecad-api-dogfood.md +0 -130
- package/dist-skill/library/forgecad-api-dogfood/SKILL.md +0 -125
|
@@ -10,6 +10,7 @@ Pre-built fasteners, gears, pipes, structural profiles, and utility shapes. Acce
|
|
|
10
10
|
## Contents
|
|
11
11
|
|
|
12
12
|
- [TangentLoop2D](#tangentloop2d)
|
|
13
|
+
- [DriveWheelBuilder](#drivewheelbuilder)
|
|
13
14
|
- [lib](#lib)
|
|
14
15
|
|
|
15
16
|
---
|
|
@@ -50,6 +51,32 @@ toProfile(): Sketch
|
|
|
50
51
|
offsetBand(thickness: number): Sketch
|
|
51
52
|
```
|
|
52
53
|
|
|
54
|
+
### `DriveWheelBuilder`
|
|
55
|
+
|
|
56
|
+
#### `addSpurTeethBetween()` — Add an involute spur-tooth window on part of the pitch circle.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
addSpurTeethBetween(options: DriveWheelSpurTeethRegionOptions): this
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### `addSolidArcBetween()` — Add a constant-radius solid arc region such as a dwell, stop, or pusher.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
addSolidArcBetween(options: DriveWheelSolidArcRegionOptions): this
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### `addShapeRegion()` — Add a fully custom region shape while preserving region metadata.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
addShapeRegion(name: string, shape: Shape, options?: DriveWheelShapeRegionOptions): this
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### `build()` — Build the final wheel shape with a bore connector and region metadata.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
build(): Shape
|
|
78
|
+
```
|
|
79
|
+
|
|
53
80
|
---
|
|
54
81
|
|
|
55
82
|
## Constants
|
|
@@ -58,7 +85,7 @@ offsetBand(thickness: number): Sketch
|
|
|
58
85
|
|
|
59
86
|
Pre-built parametric parts available in user scripts as `lib.*`.
|
|
60
87
|
|
|
61
|
-
Every key in this object becomes a method on the `lib`
|
|
88
|
+
Every key in this object becomes a method or namespace on the `lib` object exposed to `.forge.js` scripts. The catalog includes:
|
|
62
89
|
|
|
63
90
|
**Fasteners:** `bolt`, `nut`, `washer`, `fastenerSet`, `fastenerHole`, `boltHole`, `counterbore`, `hexNut`, `holePattern`
|
|
64
91
|
|
|
@@ -68,7 +95,9 @@ Every key in this object becomes a method on the `lib` namespace exposed to `.fo
|
|
|
68
95
|
|
|
69
96
|
**Threads:** `thread`
|
|
70
97
|
|
|
71
|
-
**Gears:** `spurGear`, `bevelGear`, `faceGear`, `sideGear`, `ringGear`, `rackGear`, `gearPair`, `bevelGearPair`, `faceGearPair`, `sideGearPair`
|
|
98
|
+
**Gears:** `spurGear`, `sectorGear`, `driveWheel`, `bevelGear`, `faceGear`, `sideGear`, `ringGear`, `rackGear`, `gearPair`, `bevelGearPair`, `faceGearPair`, `sideGearPair`
|
|
99
|
+
|
|
100
|
+
**Gear bodies:** `gearBodies.disk`, `gearBodies.diskWithHub`, `gearBodies.spoked`, `gearBodies.fromProfile` plus direct aliases `gearBodyDisk`, `gearBodyDiskWithHub`, `gearBodySpoked`, `gearBodyFromProfile`
|
|
72
101
|
|
|
73
102
|
**Gear ratios (pure math helpers):** `gearRatio`, `rackRatio`, `planetaryRatio`
|
|
74
103
|
|
|
@@ -76,7 +105,7 @@ Every key in this object becomes a method on the `lib` namespace exposed to `.fo
|
|
|
76
105
|
|
|
77
106
|
**Utilities:** `explode`
|
|
78
107
|
|
|
79
|
-
|
|
108
|
+
Sizes outside the supported ranges will throw at runtime with a descriptive error.
|
|
80
109
|
|
|
81
110
|
- `boltHole(diameter: number, depth: number): Shape` — Simple cylindrical through-hole cutter centered on Z=0. Subtract the result from a part to produce a plain cylindrical clearance hole. For ISO metric sizes with fit classes and counterbore/countersink, use {
|
|
82
111
|
- `fastenerHole(opts: FastenerHoleOptions): Shape` — ISO metric fastener hole cutter with optional counterbore or countersink. **Details** Returns a cutter shape (subtract from a solid to produce the hole). Sizes outside M2–M10 will throw. Extend `METRIC_HOLE_TABLE` in this file to add new sizes. **Example** ```ts const plate = box(60, 40, 8) .subtract(lib.fastenerHole({ size: 'M5', fit: 'normal', depth: 8 }) .translate(15, 10, 4)); ```
|
|
@@ -114,3 +143,11 @@ Extend this by adding new entries here and registering the corresponding runner
|
|
|
114
143
|
- `rackRatio(module: number, pinionTeeth: number): number` — Coupling ratio between a pinion and a rack. When the pinion rotates by `θ` degrees, the rack slides by `θ × (π × module × teeth / 360)` mm. Equivalently, 1mm of rack travel = `180 / (π × pitchRadius)` degrees of pinion rotation.
|
|
115
144
|
- `planetaryRatio(sunTeeth: number, ringTeeth: number): number` — Planetary gear reduction ratio when the ring is held fixed. Input: sun. Output: carrier. Ratio: `1 + ringTeeth / sunTeeth`. One turn of the sun produces `1 / ratio` turns of the carrier.
|
|
116
145
|
- `boltPattern(options: BoltPatternOptions): BoltPattern` — Define a bolt pattern once and cut it from multiple parts. const base = bolts.cut(box(60, 50, 10), 12, { from: -1 }); const cover = bolts.cut(box(60, 50, 3), 5, { from: -1 }); // Same positions in both parts — guaranteed aligned. ```
|
|
146
|
+
- `driveWheel(options?: DriveWheelOptions): DriveWheelBuilder` — Start a composable exceptional gear or drive wheel.
|
|
147
|
+
- `readDriveWheelMeta(shape: Shape): DriveWheelMeta | null` — Read the functional-region metadata attached by `driveWheel().build()`.
|
|
148
|
+
- `sectorGear(options: SectorGearOptions): Shape` — Involute sector gear with teeth on only part of the pitch circle. Specify the full-circle pitch as `teethOnFullCircle`, then choose the active tooth window with `firstTooth` and `toothCount`. The body is separate from the tooth region: pass a `gearBody...` shape for spokes, hubs, and product styling, or omit it for a simple root-radius disk. **Example** ```ts const body = lib.gearBodies.spoked({ outerRadius: 22, rimWidth: 3, hubDiameter: 10, spokeCount: 5, spokeWidth: 2.5, faceWidth: 8, boreDiameter: 5, }); const sector = lib.sectorGear({ module: 1.25, teethOnFullCircle: 36, toothCount: 10, faceWidth: 8, body, }); ```
|
|
149
|
+
- `gearBodies: { ... }` — Gear body preset namespace: disk, diskWithHub, spoked, and fromProfile.
|
|
150
|
+
- `gearBodyDisk(options: GearBodyDiskOptions): Shape` — Solid disk/ring gear body, independent from any tooth geometry.
|
|
151
|
+
- `gearBodyDiskWithHub(options: GearBodyDiskWithHubOptions): Shape` — Disk gear body with a raised center hub.
|
|
152
|
+
- `gearBodySpoked(options: GearBodySpokedOptions): Shape` — Spoked gear body with an outer rim, center hub, and radial spokes.
|
|
153
|
+
- `gearBodyFromProfile(profile: Sketch, options: GearBodyFromProfileOptions): Shape` — Extrude a custom 2D profile into a gear body.
|
|
@@ -144,7 +144,12 @@ robotExport(options: RobotExportOptions): CollectedRobotExport
|
|
|
144
144
|
|
|
145
145
|
`AssemblyPartDef`: `{ name: string, part: AssemblyPart, base: Transform, metadata?: PartMetadata }`
|
|
146
146
|
|
|
147
|
-
**`PartMetadata
|
|
147
|
+
**`PartMetadata`**
|
|
148
|
+
|
|
149
|
+
| Option | Type | Description |
|
|
150
|
+
|--------|------|-------------|
|
|
151
|
+
| `tags?` | `string \| readonly string[]` | Viewport organization tags applied to scene objects produced from this part. |
|
|
152
|
+
| `material?`, `process?`, `tolerance?`, `qty?`, `notes?`, `densityKgM3?`, `massKg?` | | — |
|
|
148
153
|
|
|
149
154
|
**`AssemblyJointDef`**: `name: string`, `type: JointType`, `parent: string`, `child: string`, `frame: Transform`, `axis: Vec3`, `min?: number`, `max?: number`, `defaultValue: number`, `unit?: string`, `effort?: number`, `velocity?: number`, `damping?: number`, `friction?: number`, `connectorRefs?: JointConnectorRefs`
|
|
150
155
|
|
|
@@ -191,6 +191,36 @@ intersect(...others: SdfShape[]): SdfShape
|
|
|
191
191
|
clipBox(x: number, y: number, z: number): SdfShape
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
+
#### `fillWith()` — Keep only the material where this shape overlaps another SDF pattern.
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
fillWith(pattern: SdfShape): SdfShape
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### `fillWithGyroid()` — Keep only the gyroid lattice inside this shape.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
fillWithGyroid(options: TpmsOptions): SdfShape
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### `fillWithSchwarzP()` — Keep only the Schwarz-P lattice inside this shape.
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
fillWithSchwarzP(options: TpmsOptions): SdfShape
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### `fillWithDiamond()` — Keep only the diamond TPMS lattice inside this shape.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
fillWithDiamond(options: TpmsOptions): SdfShape
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### `fillWithLidinoid()` — Keep only the lidinoid TPMS lattice inside this shape.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
fillWithLidinoid(options: TpmsOptions): SdfShape
|
|
222
|
+
```
|
|
223
|
+
|
|
194
224
|
#### `smoothUnion()` — Smooth union — blends shapes together with a smooth radius.
|
|
195
225
|
|
|
196
226
|
```ts
|
|
@@ -269,6 +299,14 @@ bend(radius: number): SdfShape
|
|
|
269
299
|
repeat(spacing: Vec3, count?: Vec3): SdfShape
|
|
270
300
|
```
|
|
271
301
|
|
|
302
|
+
#### `circularArray()` — Arrange this SDF in a circular array around the Z axis.
|
|
303
|
+
|
|
304
|
+
The source shape is translated by `offset` in +X before arraying. This uses angular domain folding, so evaluation stays O(1): the source SDF is sampled twice no matter how many copies are requested.
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
circularArray(count: number, offset?: number): SdfShape
|
|
308
|
+
```
|
|
309
|
+
|
|
272
310
|
#### `shell()` — Hollow out, keeping only a shell of given thickness.
|
|
273
311
|
|
|
274
312
|
```ts
|
|
@@ -281,8 +319,8 @@ shell(thickness: number): SdfShape
|
|
|
281
319
|
// Function displacement
|
|
282
320
|
shape.displace((x, y, z) => Math.sin(x) * 0.5)
|
|
283
321
|
|
|
284
|
-
// Pattern displacement
|
|
285
|
-
shape.displace(sdf.
|
|
322
|
+
// Pattern displacement from a 3D SDF field
|
|
323
|
+
shape.displace(sdf.knurl({ pitch: 2, depth: 0.3 }))
|
|
286
324
|
```
|
|
287
325
|
|
|
288
326
|
```ts
|
|
@@ -295,10 +333,16 @@ Automatically detects the shape's UV parametrization (sphere, cylinder, torus) f
|
|
|
295
333
|
|
|
296
334
|
UV coordinates are in **surface millimeters** — patterns defined with `spacing: 3` always produce 3mm spacing, regardless of shape size.
|
|
297
335
|
|
|
336
|
+
Prefer `sdf.pattern2d()` or built-in surface patterns when the relief should stay on the native shader and meshing path. Callback functions are supported for experimentation, but they are opaque to the typed pattern optimizer.
|
|
337
|
+
|
|
298
338
|
```js
|
|
299
|
-
//
|
|
339
|
+
// Native typed pattern — auto-detects sphere UV
|
|
340
|
+
const p = sdf.pattern2d()
|
|
341
|
+
const ribs = p.stripes({ spacing: 3, width: 0.8, depth: 0.35 })
|
|
342
|
+
.add(p.sineWave({ direction: [0, 1], wavelength: 14, amplitude: 0.08 }))
|
|
343
|
+
|
|
300
344
|
sdf.sphere(27).shell(3)
|
|
301
|
-
.surfaceDisplace(
|
|
345
|
+
.surfaceDisplace(ribs)
|
|
302
346
|
.toShape()
|
|
303
347
|
|
|
304
348
|
// Custom 2D pattern via function
|
|
@@ -370,9 +414,11 @@ return {
|
|
|
370
414
|
- `brick(options?: BrickOptions): SdfShape` — Brick/stone wall pattern — running bond with mortar grooves.
|
|
371
415
|
- `weave(options?: WeaveOptions): SdfShape` — Grid lattice pattern — two families of infinite slabs crossing at 90°.
|
|
372
416
|
- `basketWeave(options?: BasketWeaveOptions): SurfacePattern` — Basket weave surface pattern — threads with over-under crossings in UV space. Returns a SurfacePattern for use with `.surfaceDisplace()`.
|
|
417
|
+
- `pattern2d(): Pattern2DBuilder` — Create typed, composable 2D surface patterns for `.surfaceDisplace()`.
|
|
373
418
|
- `twist(shape: SdfShape, degreesPerUnit: number): SdfShape` — Twist an SDF shape around the Z axis.
|
|
374
419
|
- `bend(shape: SdfShape, radius: number): SdfShape` — Bend an SDF shape around the Z axis.
|
|
375
420
|
- `repeat(shape: SdfShape, spacing: Vec3, count?: Vec3): SdfShape` — Repeat an SDF shape in space.
|
|
421
|
+
- `circularArray(shape: SdfShape, count: number, offset?: number): SdfShape` — Arrange an SDF shape in a circular array around the Z axis with O(1) folded-domain evaluation.
|
|
376
422
|
- `SurfacePattern: typeof SurfacePattern` — A 2D surface pattern — a heightmap function for use with `.surfaceDisplace()`.
|
|
377
423
|
- `fromFunction(fn: SdfFunctionSource, options: SdfFunctionOptions): SdfShape` — Create a custom SDF from one expression; shader-safe expressions raymarch directly.
|
|
378
424
|
- `Sculpt: { sphere: (radius: number) => SdfShape; box: (x: number, y: number, z: number, options?: SculptBoxOptions) => SdfShape; cylinder: (height: number, radius: number) => SdfShape; disk: (radius: number, thickness?: number) => SdfShape; circle: (radius: number, thickness?: number) => SdfShape; capsule: (height: number, radius: number) => SdfShape; torus: (majorRadius: number, minorRadius: number) => SdfShape; cone: (height: number, radius: number) => SdfShape; tube: (points: SculptPointList, options?: SculptTubeOptions) => SdfShape; curve: (points: SculptPointList, options?: SculptTubeOptions) => SdfShape; path: (points: SculptPointList, options?: SculptTubeOptions) => SdfShape; blend: (first?: SculptBlendInput | SculptBlendOptions, optionsOrShape?: SculptBlendInput | SculptBlendOptions, ...rest: (SculptBlendInput | SculptBlendOptions)[]) => SdfShape; union: (first?: SculptBlendInput, ...rest: SculptBlendInput[]) => SdfShape; carve: (base: SdfShape, cutters: SculptBlendInput, options?: SculptBlendOptions) => SdfShape; keep: (first?: SculptBlendInput | SculptBlendOptions, optionsOrShape?: SculptBlendInput | SculptBlendOptions, ...rest: (SculptBlendInput | SculptBlendOptions)[]) => SdfShape; polish: (shape: SdfShape, input?: SculptPolishInput) => SdfShape; material: (input?: SculptPolishInput) => ShapeMaterialProps & { color?: string; }; look: (preset?: SculptLookPreset) => SceneOptions; knownMaterials: typeof knownSculptMaterialPresets; }` — Sculpt-like facade: friendly liquid-modeling verbs backed by the same SDF kernel.
|
|
@@ -59,7 +59,7 @@ When `lights` is specified, **all** default lights are removed. You must include
|
|
|
59
59
|
|
|
60
60
|
Setting `camera.position` overrides auto-framing — the viewport will no longer auto-fit the geometry on script reload.
|
|
61
61
|
|
|
62
|
-
Named render views let scripts check in repeatable cameras next to the model code. The canonical shape is `{ camera: { position, target } }`, and a direct camera shorthand `{ position, target }` is also accepted. Use the canonical shape when you may add view metadata later. Use it from the CLI with `forgecad render 3d
|
|
62
|
+
Named render views let scripts check in repeatable cameras next to the model code. The canonical shape is `{ camera: { position, target } }`, and a direct camera shorthand `{ position, target }` is also accepted. Use the canonical shape when you may add view metadata later. Use it from the CLI with `--view hero` on `forgecad render 3d`, `forgecad render hq`, or `forgecad capture`.
|
|
63
63
|
|
|
64
64
|
Model journeys let scripts check in a compact guided path through named objects. Each journey has ordered `steps`; each step can name a `focus` target by object name/tree path, provide a caption, and optionally provide an explicit camera. In the viewer, journeys are opt-in: they appear as a small Explore control and do not move the camera until the user starts them. Use `forgecad run model.forge.js --journeys` or `--journeys-json` to inspect resolved targets.
|
|
65
65
|
|
|
@@ -128,7 +128,6 @@ scene(options: SceneOptions): void
|
|
|
128
128
|
| `behavior?` | `"opt-in" \| "auto"` | Whether the viewer should offer or auto-open the journey. First slice supports opt-in. |
|
|
129
129
|
| `steps` | `SceneJourneyStepConfig[]` | Ordered journey spine. Branches can be added later without changing this core contract. |
|
|
130
130
|
| `valid?` | `boolean` | True unless any journey or step diagnostic has level "error". |
|
|
131
|
-
| `diagnostics?` | `SceneJourneyDiagnostic[]` | Whole-journey diagnostics, including unresolved startsAt and step target diagnostics. |
|
|
132
131
|
|
|
133
132
|
**`SceneJourneyStepConfig`**
|
|
134
133
|
|
|
@@ -141,9 +140,6 @@ scene(options: SceneOptions): void
|
|
|
141
140
|
| `camera?` | `SceneViewCameraConfig` | Optional explicit camera for this step. When omitted, the viewer fits `focus`. |
|
|
142
141
|
| `resolvedFocusId?` | `string \| null` | Resolved object id after script execution, when `focus` matched exactly one object. |
|
|
143
142
|
| `resolvedFocusPath?` | `string \| null` | Resolved object tree path or name after script execution. |
|
|
144
|
-
| `diagnostics?` | `SceneJourneyDiagnostic[]` | Resolution diagnostics for this step. |
|
|
145
|
-
|
|
146
|
-
`SceneJourneyDiagnostic`: `{ level: SceneJourneyDiagnosticLevel, message: string, stepId?: string, suggestions?: string[] }`
|
|
147
143
|
|
|
148
144
|
**`SceneLightConfig`**
|
|
149
145
|
|
|
@@ -219,10 +215,6 @@ viewConfig({
|
|
|
219
215
|
viewConfig(options?: ViewConfigOptions): void
|
|
220
216
|
```
|
|
221
217
|
|
|
222
|
-
`ViewConfigOptions`: `{ jointOverlay?: JointOverlayViewConfigOptions }`
|
|
223
|
-
|
|
224
|
-
**`JointOverlayViewConfigOptions`**: `enabled?: boolean`, `axisColor?: string`, `axisCoreColor?: string`, `arcColor?: string`, `zeroColor?: string`, `arcVisualLimitDeg?: number`, `axisLengthScale?: number`, `axisLengthMin?: number`, `axisLineRadiusScale?: number`, `axisLineRadiusMin?: number`, `axisLineRadiusMax?: number`, `spokeLineRadiusScale?: number`, `spokeLineRadiusMin?: number`, `spokeLineRadiusMax?: number`, `arcLineRadiusScale?: number`, `arcLineRadiusMin?: number`, `arcLineRadiusMax?: number`, `axisDotRadiusScale?: number`, `axisDotRadiusMin?: number`, `axisArrowRadiusScale?: number`, `axisArrowRadiusMin?: number`, `axisArrowLengthScale?: number`, `axisArrowLengthMin?: number`, `axisArrowOffsetFactor?: number`, `arcRadiusScale?: number`, `arcRadiusMin?: number`, `arcDotRadiusScale?: number`, `arcDotRadiusMin?: number`, `arcArrowRadiusScale?: number`, `arcArrowRadiusMin?: number`, `arcArrowLengthScale?: number`, `arcArrowLengthMin?: number`, `arcArrowOffsetFactor?: number`, `arcStepDeg?: number`, `arcMinSteps?: number`, `arcTubeSegmentsMin?: number`, `arcTubeSegmentsFactor?: number`, `arcTubeRadialSegments?: number`
|
|
225
|
-
|
|
226
218
|
#### `explodeView()` — Configure how the viewport explode slider offsets returned objects.
|
|
227
219
|
|
|
228
220
|
Offsets are resolved from the returned object tree, not a flat list. In `radial` mode each node follows its parent branch direction, then fans locally from the immediate parent center — nested assemblies peel apart level by level. In fixed-axis or fixed-vector modes, the branch follows that axis/vector but nested descendants fan out perpendicular by default.
|
|
@@ -7,8 +7,9 @@ skill-order: 2
|
|
|
7
7
|
|
|
8
8
|
`forgecad render inspect` writes a deterministic directory bundle for agents,
|
|
9
9
|
tests, and automation. Use it when a single shaded PNG is too ambiguous and the
|
|
10
|
-
consumer needs geometry-aware signals such as depth, normals,
|
|
11
|
-
physical connected components, collisions, local thickness, or
|
|
10
|
+
consumer needs geometry-aware signals such as depth, normals, surface roughness,
|
|
11
|
+
part identity, physical connected components, collisions, local thickness, or
|
|
12
|
+
cross-sections.
|
|
12
13
|
|
|
13
14
|
## When To Use It
|
|
14
15
|
|
|
@@ -28,14 +29,16 @@ forgecad render inspect model.forge.js --channels rgb,mask,section
|
|
|
28
29
|
forgecad render inspect model.forge.js --channels collisions --focus Bench
|
|
29
30
|
forgecad render inspect model.forge.js --channels rgb,mask --hide "Bench.Slat0,Bench.Slat1"
|
|
30
31
|
forgecad render inspect model.forge.js --channels thickness --min-thickness 1.2 --warn-thickness 2.0
|
|
32
|
+
forgecad render inspect channels
|
|
31
33
|
```
|
|
32
34
|
|
|
33
35
|
The default output directory is `<script-name>-inspect/` next to the input file.
|
|
34
36
|
Pass `--force` to replace an existing bundle directory.
|
|
35
37
|
|
|
36
38
|
There are no default channels. Pass `--channels` every time as a
|
|
37
|
-
comma-separated subset.
|
|
38
|
-
|
|
39
|
+
comma-separated subset. Run `forgecad render inspect channels` to list the
|
|
40
|
+
supported channels in the installed CLI. Keep bundles targeted to the current
|
|
41
|
+
question so heavy analyses do not run unnecessarily.
|
|
39
42
|
|
|
40
43
|
`--focus` and `--hide` use the same object-name filtering semantics as
|
|
41
44
|
`forgecad run` and `forgecad render 3d`. A bare `--focus` hides mock objects;
|
|
@@ -91,12 +94,13 @@ implemented channel in one bundle:
|
|
|
91
94
|
|
|
92
95
|
```bash
|
|
93
96
|
forgecad render inspect model.forge.js --channels depth,normals
|
|
97
|
+
forgecad render inspect model.forge.js --channels rgb,roughness
|
|
94
98
|
forgecad render inspect model.forge.js --channels rgb,mask,collisions
|
|
95
99
|
forgecad render inspect model.forge.js --channels rgb,section,thickness
|
|
96
100
|
```
|
|
97
101
|
|
|
98
|
-
Supported channels are `rgb`, `depth`, `normals`, `
|
|
99
|
-
`distance`, `collisions`, `thickness`, and `section`.
|
|
102
|
+
Supported channels are `rgb`, `depth`, `normals`, `roughness`, `mask`,
|
|
103
|
+
`connectivity`, `distance`, `collisions`, `thickness`, and `section`.
|
|
100
104
|
|
|
101
105
|
## Channel Semantics
|
|
102
106
|
|
|
@@ -123,6 +127,27 @@ normal = normalize((rgb / 255) * 2 - 1)
|
|
|
123
127
|
|
|
124
128
|
Background pixels are black and should be treated as `null`.
|
|
125
129
|
|
|
130
|
+
`roughness` emits a mesh-dihedral surface-quality heatmap. Smooth and gently
|
|
131
|
+
curved triangles render as a faint translucent shadow over black, while
|
|
132
|
+
triangles adjacent to sharp, harsh, boundary, or non-manifold mesh edges render
|
|
133
|
+
in orange or magenta:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
shadow = max adjacent angle < sharpAngleDeg
|
|
137
|
+
orange = sharpAngleDeg <= angle < harshAngleDeg
|
|
138
|
+
magenta = angle >= harshAngleDeg, boundary, or non-manifold
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The default thresholds are `smoothAngleDeg=5`, `sharpAngleDeg=30`, and
|
|
142
|
+
`harshAngleDeg=90`. The manifest stores the method, thresholds, palette, object
|
|
143
|
+
list, per-object triangle and edge counts, area percentages by smooth,
|
|
144
|
+
moderate, sharp, and harsh classes, angle percentiles, maximum angle, quality
|
|
145
|
+
score, and warnings. Moderate angles are reported in the manifest but stay in
|
|
146
|
+
the shadow layer by default so intentionally curved surfaces do not light up as
|
|
147
|
+
defects. Use this channel to spot spiky tessellation, accidental faceting,
|
|
148
|
+
jagged boolean residue, and dense sharp-corner regions without losing the
|
|
149
|
+
silhouette of otherwise smooth surfaces.
|
|
150
|
+
|
|
126
151
|
`mask` emits one object-color image per view. Black is background. Non-black
|
|
127
152
|
pixels resolve through `manifest.channels.mask.objects`, which includes object
|
|
128
153
|
index, RGB color, object id, name, group, tree path, and mock flag. Edge pixels
|
|
@@ -72,6 +72,7 @@ Use today's date for the directory. Use the user's current ForgeCAD project when
|
|
|
72
72
|
- Use at most a handful of top-level `param()` values when comparing rough proportions. Do not parameterize every dimension.
|
|
73
73
|
- Name uncertainty honestly: `armLengthGuess`, `baseWidthApprox`, `screenVolume`, `clearanceEnvelope`.
|
|
74
74
|
- Do not add text labels, callout arrows, legends, coordinate labels, or explanatory plaques to the model. Use named return objects and a short written note outside the geometry.
|
|
75
|
+
- Do not cut away a shell, remove covers, or permanently explode parts just to show hidden intent. Even a blockout should represent the object in its normal assembled state unless the user explicitly asks for a presentation view.
|
|
75
76
|
- Use transparent ghost geometry for:
|
|
76
77
|
- sweep arcs
|
|
77
78
|
- keep-out volumes
|
|
@@ -17,6 +17,8 @@ The reference image is evidence. It is not the deliverable.
|
|
|
17
17
|
|
|
18
18
|
The deliverable is a real parametric object that remains believable from front, back, side, top, bottom, and reference camera views. A model that matches one image but falls apart from other angles has failed, even if the comparison board looks close.
|
|
19
19
|
|
|
20
|
+
If a reference image is cutaway, sectioned, exploded, partly hidden, or transparent, treat that as evidence about the complete object. Do not make the default ForgeCAD result a permanently cutaway or exploded display unless the user explicitly asked for a teaching/display model. Build the closed artifact first, then use ForgeCAD viewer/inspection tools to recreate explanatory views.
|
|
21
|
+
|
|
20
22
|
### Required Companion Skills
|
|
21
23
|
|
|
22
24
|
- Use `forgecad` for API docs, model authoring, and renderer behavior.
|
|
@@ -85,7 +87,7 @@ Reference matching is a validation step after the object exists.
|
|
|
85
87
|
When multiple images are attached, do not choose one as the target and ignore the rest. Assign each image a camera, evidence list, and confidence level. Optimize one shared geometry against the whole set. If an image is decorative, distorted, or contradictory, state how it was weighted.
|
|
86
88
|
|
|
87
89
|
10. Inspect the final object.
|
|
88
|
-
Run `forgecad run`, render the reference comparison boards, render canonical views, and use `forgecad render inspect` with relevant channels. For multi-part, mechanical, internal, or fit-sensitive models, include collisions and section
|
|
90
|
+
Run `forgecad run`, render the reference comparison boards, render canonical views, and use `forgecad render inspect` with relevant channels. For multi-part, mechanical, internal, or fit-sensitive models, include collisions and section-channel inspection, but keep the delivered model as the complete closed artifact.
|
|
89
91
|
|
|
90
92
|
### Renderer Camera Support
|
|
91
93
|
|
|
@@ -45,12 +45,14 @@ Use today's date for the directory. Use the user's current ForgeCAD project when
|
|
|
45
45
|
- When there are multiple versions of the same object, expose the version as a choice parameter and render one selected version at a time
|
|
46
46
|
- Use clear variable names
|
|
47
47
|
- Build any implied internal structure as real geometry, even when it will be hidden in the final view
|
|
48
|
+
- Build the complete physical artifact first: closed shells, installed covers, real part positions, and all meaningful internal structure in place
|
|
48
49
|
- Make final mating geometry physically plausible: parts may touch, clear each other, or be boolean-joined, but should not unintentionally pass through each other
|
|
49
50
|
- Model the physical artifact, not an educational diagram: no explanatory arrows, floating labels, section labels, legends, or text plaques unless the user explicitly requested a presentation/teaching view
|
|
51
|
+
- Do not make the default returned model a cutaway, sectioned shell, permanently exploded assembly, or hidden-parts teaching view. ForgeCAD gives the user viewer and inspection tools for slicing, exploding, hiding, and looking inside after the real CAD exists.
|
|
50
52
|
- Return the final geometry (single shape, array, or named objects array)
|
|
51
|
-
-
|
|
53
|
+
- 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.
|
|
52
54
|
4. Validate — run `forgecad run <file>` to check for errors. For multi-file projects, always validate `main.forge.js`.
|
|
53
|
-
5. Verify geometry — render the result and run `forgecad render inspect` with the relevant channels for the task (see Render-Verify Loop below). For multi-file projects, render and inspect `main.forge.js`.
|
|
55
|
+
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`.
|
|
54
56
|
|
|
55
57
|
### Manufacturing Process Is Not Assumed
|
|
56
58
|
|
|
@@ -103,7 +105,9 @@ Build hidden features as actual geometry:
|
|
|
103
105
|
- Mechanism clearances, travel envelopes, stops, guides, rails, hinges, gear spaces, and service access
|
|
104
106
|
- Process-specific features such as bends, tubes, sheet-metal flanges, machined bosses, cast ribs, molded draft, weld tabs, laser-cut slots, or print-oriented ribs where appropriate
|
|
105
107
|
|
|
106
|
-
|
|
108
|
+
Do not reveal hidden structure by permanently cutting away the production geometry. Keep the returned default model faithful to the real closed artifact, with covers installed and parts in their actual assembled positions.
|
|
109
|
+
|
|
110
|
+
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.
|
|
107
111
|
|
|
108
112
|
### Final Geometry Should Be Physically Plausible
|
|
109
113
|
|
|
@@ -115,6 +119,46 @@ Temporary collisions during construction are fine when they are part of how the
|
|
|
115
119
|
|
|
116
120
|
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, document it in the model naming/comments or isolate that inspection with `--focus` / `--hide` so the remaining collision report proves the final assembly is real.
|
|
117
121
|
|
|
122
|
+
### Final Acceptance Gate
|
|
123
|
+
|
|
124
|
+
Before telling the user the model is done, prove both technical validity and visual plausibility. A model can pass `forgecad run` and still be wrong because a rail, cable, trim line, handle, or fastener is merely hovering over a curved surface. Use this gate for any model with multiple bodies, surface-mounted details, cables/strings, rails/tracks, handles, product skins, visible hardware, or hidden mating geometry.
|
|
125
|
+
|
|
126
|
+
1. State the intended physical component graph. Decide whether the final artifact should be one connected component, several intentionally separate components, or a selected assembly plus named ghosts. Then run:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
forgecad run model.forge.js --connectivity
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
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.
|
|
133
|
+
|
|
134
|
+
2. Run a collision bundle and read both the manifest and images:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
forgecad render inspect model.forge.js /tmp/model-inspect --channels rgb,mask,collisions --force --size 700
|
|
138
|
+
jq '.channels.collisions | {collisionCount, collisions, warnings}' /tmp/model-inspect/manifest.json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`collisionCount` should be zero unless an overlap is deliberately manufactured, fused, welded, overmolded, or isolated with `--focus` / `--hide`. Do not ignore the channel PNGs; visually inspect where the findings or warnings appear.
|
|
142
|
+
|
|
143
|
+
3. Render risk-specific views, not only a hero shot. At minimum, render one hero view plus the orthographic views that expose the likely failure modes:
|
|
144
|
+
|
|
145
|
+
- long products, vehicles, weapons, rails, handles, and tools: side and top
|
|
146
|
+
- sockets, underside joins, stands, brackets, and handles: side plus underside; use section-channel inspection only when hidden geometry must be checked
|
|
147
|
+
- cables, strings, belts, tubes, and hoses: top plus side so endpoints and sag/clearance are visible
|
|
148
|
+
- surface details on curved ProductSkin bodies: grazing side view plus top/iso to confirm they conform or are embedded as intended
|
|
149
|
+
|
|
150
|
+
4. Do a visual attachment audit. For every detail that should be connected, ask: "Where does this physically enter, seat, wrap, terminate, or fasten?" Check that view directly. Common failures to fix before delivery:
|
|
151
|
+
|
|
152
|
+
- a flat rail or arrow bed sitting on top of a curved shell instead of being recessed, saddled, socketed, or structurally blended into the body
|
|
153
|
+
- strings/cables that pass through space without terminal knots, hooks, holes, posts, ferrules, pulleys, or anchors
|
|
154
|
+
- decorative brass/trim lines floating above the body instead of following a ProductSkin surface or being built as inset/raised strips with believable thickness
|
|
155
|
+
- handles/grips touching only by a tangent or thin face instead of having a neck, bridge, socket, screws, or overmolded landing
|
|
156
|
+
- small hardware or gems that are bbox-connected but visually read as levitating; replace with flush/inset seats or explicit brackets
|
|
157
|
+
|
|
158
|
+
5. Treat ProductSkin and surface-member limitations honestly. If `render inspect` reports boolean-test warnings because a sampled `Product.skin` loft has boundary edges, distinguish that from real collision findings. You may still deliver if `collisionCount` is clean, the intended connectivity is correct, and the visual attachment audit passes. Mention the residual warning briefly in the final response.
|
|
159
|
+
|
|
160
|
+
6. Final response must name the evidence: commands run, component count, collision count, and any residual warnings or intentional exceptions. Do not just say "validated."
|
|
161
|
+
|
|
118
162
|
### Render-Verify Loop
|
|
119
163
|
|
|
120
164
|
You are building blind unless you render. `forgecad run` only checks that code executes — it cannot tell you a hole is in the wrong place or a part doesn't fit. Render and look at the result.
|
|
@@ -236,7 +280,7 @@ Key primitives:
|
|
|
236
280
|
|
|
237
281
|
- `box(x, y, z)`, `cylinder(h, r, rTop?, segments?)`, `sphere(r)`, `torus(R, r)`
|
|
238
282
|
- `union()`, `difference()`, `intersection()`
|
|
239
|
-
- `.fillet()`, `.chamfer()` for edge treatments
|
|
283
|
+
- `.fillet()`, `.chamfer()` for experimental edge treatments only
|
|
240
284
|
- `param(name, default, opts)`, `boolParam(name, default)`
|
|
241
285
|
- Return `[{ name, shape, color }]` for multi-part colored models
|
|
242
286
|
|
|
@@ -15,6 +15,8 @@ Use `forgecad render inspect` when a shaded viewport render is too ambiguous and
|
|
|
15
15
|
|
|
16
16
|
This skill owns the inspection workflow: choosing channels, generating the bundle, reading the manifest, visually inspecting the relevant PNGs, and turning the findings into model fixes or a verification report.
|
|
17
17
|
|
|
18
|
+
Inspection is not a substitute artifact. Use section, mask, transparency, focus, and hide channels to look inside a real model; do not edit the model into a cutaway or exploded default just to make the inspection easier.
|
|
19
|
+
|
|
18
20
|
### Trigger Boundary
|
|
19
21
|
|
|
20
22
|
Use this skill for:
|
|
@@ -148,7 +150,7 @@ Manifest fields to check first:
|
|
|
148
150
|
- `channels.thickness.objects`: inspect `minThickness`, `p05Thickness`, critical/warning percentages, and unresolved area.
|
|
149
151
|
- `channels.connectivity.componentCount`: compare to the expected number of physical components.
|
|
150
152
|
- `channels.distance.maxRootDistance` and per-object `nearestGap`: check suspicious isolation or spacing.
|
|
151
|
-
- `channels.section.planes`: look for missing slices, wrong path counts, or empty internal cuts.
|
|
153
|
+
- `channels.section.planes`: look for missing slices, wrong path counts, or empty internal cuts. These are inspection views, not instructions to section the returned production geometry.
|
|
152
154
|
|
|
153
155
|
PNG review order:
|
|
154
156
|
|
|
@@ -37,6 +37,7 @@ The image should not:
|
|
|
37
37
|
- smooth away the mechanism into a fake consumer shell
|
|
38
38
|
- invent flashy sci-fi styling that hides how it works
|
|
39
39
|
- pretend to be a CAD drawing, dimensioned blueprint, or engineering diagram
|
|
40
|
+
- turn the artifact into a cutaway, sectioned shell, or exploded teaching view unless the user explicitly asks for that representation
|
|
40
41
|
|
|
41
42
|
### Default Strategy
|
|
42
43
|
|
|
@@ -124,6 +125,7 @@ Bias harder toward interfaces, seams, mounted actuators, and subsystem boundarie
|
|
|
124
125
|
Use when the user wants assembly logic or modular breakdown.
|
|
125
126
|
|
|
126
127
|
Keep the explosion restrained. Separate only major modules, not every screw.
|
|
128
|
+
This is a visual-spec support image, not a default ForgeCAD modeling instruction; the CAD artifact should still be the complete assembled product.
|
|
127
129
|
|
|
128
130
|
#### Workshop Prototype Realism
|
|
129
131
|
|
|
@@ -25,6 +25,7 @@ Author or modify ForgeCAD models, sketches, assemblies, and CLI workflows. Prefe
|
|
|
25
25
|
8. Validate with `forgecad run <file>` (add `--debug-imports` for import chain issues, and pass `--backend manifold|occt|truck` when the backend matters).
|
|
26
26
|
9. For `jointsView()` animations, keep wrapped revolute tracks continuous across branch cuts; do not assume the viewport will auto-fix `-180/180` jumps.
|
|
27
27
|
10. Model the physical artifact, not an educational diagram. Do not add explanatory labels, arrows, legends, or text plaques unless the user explicitly asks for a presentation or teaching view. Product markings are allowed only when they would exist on the real object.
|
|
28
|
+
11. Build the real closed CAD first. Do not bake cutaways, sectioned shells, permanently exploded layouts, or hidden-parts views into the default model just to show internals. Use viewer-only cut planes, `explodeView`, object hiding, transparency, or `render inspect` section channels after the artifact exists.
|
|
28
29
|
|
|
29
30
|
#### Import and Composition
|
|
30
31
|
|
|
@@ -92,7 +93,7 @@ Parametric bolts, nuts, washers, standard hardware, gears, pipes, and structural
|
|
|
92
93
|
- `docs/permanent/generated/lib.md`
|
|
93
94
|
- `docs/permanent/generated/wood.md`
|
|
94
95
|
|
|
95
|
-
#### 9. Runtime Viewport APIs (for cut planes,
|
|
96
|
+
#### 9. Runtime Viewport APIs (for cut planes, exploded views, hiding, and animation playback)
|
|
96
97
|
|
|
97
98
|
Viewer-only APIs such as cutPlane, explodeView, jointsView, and animation behavior.
|
|
98
99
|
|
|
@@ -9,7 +9,6 @@ forgecad skill install
|
|
|
9
9
|
| Skill | Installed by | Purpose |
|
|
10
10
|
| --- | --- | --- |
|
|
11
11
|
| [forgecad](/docs/skills/forgecad) | `forgecad skill install` | ForgeCAD model authoring, editing, debugging, and execution guidance for .forge.js, SVG-import, assembly, and CLI workflows. Use when building or modifying ForgeCAD geometry, structuring multi-file projects, validating scripts, or using ForgeCAD export/render tooling. |
|
|
12
|
-
| [forgecad-api-dogfood](/docs/skills/forgecad-api-dogfood) | `forgecad skill install` | Build a ForgeCAD model while actively hunting for API friction — missing helpers, awkward patterns, bad defaults, verbose boilerplate. Use when asked to dogfood, stress-test the API, or build a model with the goal of improving ForgeCAD. |
|
|
13
12
|
| [forgecad-blockout-model](/docs/skills/forgecad-blockout-model) | `forgecad skill install` | Create rough high-level ForgeCAD concept models from simple primitives to explore layout, proportions, motion, and part relationships without production detail. Use when asked for a quick model sketch, blockout, spatial mockup, or intuitive low-detail 3D concept. |
|
|
14
13
|
| [forgecad-component-model](/docs/skills/forgecad-component-model) | `forgecad skill install` | Enforce the ForgeCAD Component Model when building multi-part assemblies. Parts build at origin, connectors position them, data flows down from parent. Use when building or reviewing any multi-file ForgeCAD project. |
|
|
15
14
|
| [forgecad-high-level-spec](/docs/skills/forgecad-high-level-spec) | `forgecad skill install` | Write a high-level design document (HLD) for a model, mechanism, or assembly before detailed specification or coding. Use when starting a new design, rethinking an existing one, or when the user asks to spec out, plan, or think through a model at a high level. Works backwards from requirements — defines the problem, explores alternatives, records decisions. Produces a right-sized design document for review and iteration. |
|
package/dist/index.html
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
56
56
|
html, body, #root { width: 100%; min-height: 100%; background: var(--fc-bg); color: var(--fc-text); font-family: system-ui, -apple-system, sans-serif; }
|
|
57
57
|
</style>
|
|
58
|
-
<script type="module" crossorigin src="/assets/app-
|
|
58
|
+
<script type="module" crossorigin src="/assets/app-CFy7g5WP.js"></script>
|
|
59
59
|
<link rel="stylesheet" crossorigin href="/assets/app-CsHnaBWt.css">
|
|
60
60
|
</head>
|
|
61
61
|
<body>
|
package/dist/sitemap.xml
CHANGED
|
@@ -2,37 +2,37 @@
|
|
|
2
2
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3
3
|
<url>
|
|
4
4
|
<loc>https://forgecad.io/</loc>
|
|
5
|
-
<lastmod>2026-05-
|
|
5
|
+
<lastmod>2026-05-16</lastmod>
|
|
6
6
|
<changefreq>weekly</changefreq>
|
|
7
7
|
<priority>1.0</priority>
|
|
8
8
|
</url>
|
|
9
9
|
<url>
|
|
10
10
|
<loc>https://forgecad.io/docs</loc>
|
|
11
|
-
<lastmod>2026-05-
|
|
11
|
+
<lastmod>2026-05-16</lastmod>
|
|
12
12
|
<changefreq>weekly</changefreq>
|
|
13
13
|
<priority>0.8</priority>
|
|
14
14
|
</url>
|
|
15
15
|
<url>
|
|
16
16
|
<loc>https://forgecad.io/blog</loc>
|
|
17
|
-
<lastmod>2026-05-
|
|
17
|
+
<lastmod>2026-05-16</lastmod>
|
|
18
18
|
<changefreq>weekly</changefreq>
|
|
19
19
|
<priority>0.7</priority>
|
|
20
20
|
</url>
|
|
21
21
|
<url>
|
|
22
22
|
<loc>https://forgecad.io/pricing</loc>
|
|
23
|
-
<lastmod>2026-05-
|
|
23
|
+
<lastmod>2026-05-16</lastmod>
|
|
24
24
|
<changefreq>monthly</changefreq>
|
|
25
25
|
<priority>0.6</priority>
|
|
26
26
|
</url>
|
|
27
27
|
<url>
|
|
28
28
|
<loc>https://forgecad.io/examples</loc>
|
|
29
|
-
<lastmod>2026-05-
|
|
29
|
+
<lastmod>2026-05-16</lastmod>
|
|
30
30
|
<changefreq>weekly</changefreq>
|
|
31
31
|
<priority>0.6</priority>
|
|
32
32
|
</url>
|
|
33
33
|
<url>
|
|
34
34
|
<loc>https://forgecad.io/blog/hello-forgecad-io</loc>
|
|
35
|
-
<lastmod>2026-05-
|
|
35
|
+
<lastmod>2026-05-16</lastmod>
|
|
36
36
|
<changefreq>monthly</changefreq>
|
|
37
37
|
<priority>0.5</priority>
|
|
38
38
|
</url>
|
|
@@ -28,7 +28,7 @@ import sys
|
|
|
28
28
|
import json
|
|
29
29
|
import math
|
|
30
30
|
import os
|
|
31
|
-
from mathutils import Vector
|
|
31
|
+
from mathutils import Matrix, Vector
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
# ---------------------------------------------------------------------------
|
|
@@ -414,18 +414,26 @@ def setup_camera(config, objects):
|
|
|
414
414
|
|
|
415
415
|
cam_config = config.get('camera') or {}
|
|
416
416
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
417
|
+
projection_mode = cam_config.get('projectionMode') or cam_config.get('type') or 'perspective'
|
|
418
|
+
if projection_mode == 'orthographic':
|
|
419
|
+
cam_data.type = 'ORTHO'
|
|
420
|
+
if cam_config.get('orthoScale'):
|
|
421
|
+
cam_data.ortho_scale = float(cam_config['orthoScale'])
|
|
422
|
+
elif cam_config.get('orthoZoom'):
|
|
423
|
+
cam_data.ortho_scale = 960.0 / float(cam_config['orthoZoom'])
|
|
424
|
+
else:
|
|
425
|
+
cam_data.ortho_scale = 960.0
|
|
426
|
+
else:
|
|
427
|
+
cam_data.type = 'PERSP'
|
|
428
|
+
fov = cam_config.get('fov', 45)
|
|
429
|
+
cam_data.lens_unit = 'FOV'
|
|
430
|
+
cam_data.angle = math.radians(fov)
|
|
421
431
|
|
|
422
432
|
if cam_config.get('position') and cam_config.get('target'):
|
|
423
433
|
pos = Vector(cam_config['position'])
|
|
424
434
|
target = Vector(cam_config['target'])
|
|
425
435
|
cam_obj.location = pos
|
|
426
|
-
|
|
427
|
-
rot_quat = direction.to_track_quat('-Z', 'Y')
|
|
428
|
-
cam_obj.rotation_euler = rot_quat.to_euler()
|
|
436
|
+
set_camera_orientation(cam_obj, pos, target, cam_config.get('up'))
|
|
429
437
|
else:
|
|
430
438
|
# Auto-frame: compute bounding box of all mesh objects
|
|
431
439
|
auto_frame_camera(cam_obj, objects)
|
|
@@ -433,6 +441,33 @@ def setup_camera(config, objects):
|
|
|
433
441
|
return cam_obj
|
|
434
442
|
|
|
435
443
|
|
|
444
|
+
def set_camera_orientation(cam_obj, pos, target, up_values=None):
|
|
445
|
+
direction = target - pos
|
|
446
|
+
if direction.length <= 1e-8:
|
|
447
|
+
return
|
|
448
|
+
|
|
449
|
+
if up_values:
|
|
450
|
+
forward = direction.normalized()
|
|
451
|
+
up = Vector(up_values)
|
|
452
|
+
if up.length > 1e-8:
|
|
453
|
+
up.normalize()
|
|
454
|
+
right = up.cross(forward)
|
|
455
|
+
if right.length > 1e-8:
|
|
456
|
+
right.normalize()
|
|
457
|
+
true_up = forward.cross(right)
|
|
458
|
+
true_up.normalize()
|
|
459
|
+
rotation = Matrix((
|
|
460
|
+
(right.x, true_up.x, -forward.x),
|
|
461
|
+
(right.y, true_up.y, -forward.y),
|
|
462
|
+
(right.z, true_up.z, -forward.z),
|
|
463
|
+
))
|
|
464
|
+
cam_obj.rotation_euler = rotation.to_euler()
|
|
465
|
+
return
|
|
466
|
+
|
|
467
|
+
rot_quat = direction.to_track_quat('-Z', 'Y')
|
|
468
|
+
cam_obj.rotation_euler = rot_quat.to_euler()
|
|
469
|
+
|
|
470
|
+
|
|
436
471
|
def auto_frame_camera(cam_obj, objects):
|
|
437
472
|
"""Position camera to frame all objects nicely — iso view."""
|
|
438
473
|
if not objects:
|