forgecad 0.1.1 → 0.1.3
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/{evalWorker-DuS4V-H5.js → evalWorker-1m873KWd.js} +107 -107
- package/dist/assets/{index-d60dJDhX.js → index-Dvz3nSDc.js} +342 -326
- package/dist/assets/{manifold-DEOPQqeC.js → manifold-C38sUiKu.js} +1 -1
- package/dist/assets/{manifold-cL7A7HeM.js → manifold-Dk2u-lhj.js} +1 -1
- package/dist/assets/{manifold-DbvY5u9x.js → manifold-rOWQW9fU.js} +1 -1
- package/dist/assets/{reportWorker-GZVKtf9S.js → reportWorker-Cj587shw.js} +129 -129
- package/dist/index.html +1 -1
- package/dist-cli/forgecad.js +204 -19
- package/dist-skill/SKILL.md +31 -4561
- package/dist-skill/docs/API/README.md +24 -0
- package/dist-skill/docs/API/guides/modeling-recipes.md +246 -0
- package/dist-skill/docs/API/internals/compiler.md +300 -0
- package/dist-skill/docs/API/internals/manifold.md +7 -0
- package/dist-skill/docs/API/model-building/README.md +31 -0
- package/dist-skill/docs/API/model-building/assembly.md +205 -0
- package/dist-skill/docs/API/model-building/coordinate-system.md +43 -0
- package/dist-skill/docs/API/model-building/entities.md +282 -0
- package/dist-skill/docs/API/model-building/geometry-conventions.md +104 -0
- package/dist-skill/docs/API/model-building/positioning.md +170 -0
- package/dist-skill/docs/API/model-building/reference.md +1936 -0
- package/dist-skill/docs/API/model-building/sheet-metal.md +180 -0
- package/dist-skill/docs/API/model-building/sketch-anchor.md +32 -0
- package/dist-skill/docs/API/model-building/sketch-booleans.md +101 -0
- package/dist-skill/docs/API/model-building/sketch-core.md +68 -0
- package/dist-skill/docs/API/model-building/sketch-extrude.md +57 -0
- package/dist-skill/docs/API/model-building/sketch-on-face.md +98 -0
- package/dist-skill/docs/API/model-building/sketch-operations.md +92 -0
- package/dist-skill/docs/API/model-building/sketch-path.md +70 -0
- package/dist-skill/docs/API/model-building/sketch-primitives.md +104 -0
- package/dist-skill/docs/API/model-building/sketch-transforms.md +60 -0
- package/dist-skill/docs/API/output/bom.md +53 -0
- package/dist-skill/docs/API/output/brep-export.md +82 -0
- package/dist-skill/docs/API/output/dimensions.md +62 -0
- package/dist-skill/docs/API/runtime/viewport.md +229 -0
- package/dist-skill/docs/CLI.md +672 -0
- package/dist-skill/docs/CODING.md +345 -0
- package/dist-skill/docs/PROGRAM-LEAD.md +180 -0
- package/dist-skill/docs/VISION.md +77 -0
- package/examples/api/import-group-assembly.forge.js +34 -0
- package/examples/api/import-group-source.forge.js +35 -0
- package/package.json +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Sketch Primitives
|
|
2
|
+
|
|
3
|
+
2D primitive shapes for creating sketches.
|
|
4
|
+
|
|
5
|
+
## Functions
|
|
6
|
+
|
|
7
|
+
### `rect(width, height, center?)`
|
|
8
|
+
Creates a rectangle.
|
|
9
|
+
|
|
10
|
+
**Parameters:**
|
|
11
|
+
- `width` (number) - Width
|
|
12
|
+
- `height` (number) - Height
|
|
13
|
+
- `center` (boolean, optional) - If true, centers at origin. Default: false (corner at origin)
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const r = rect(50, 30);
|
|
17
|
+
const centered = rect(50, 30, true);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### `circle2d(radius, segments?)`
|
|
21
|
+
Creates a circle.
|
|
22
|
+
|
|
23
|
+
**Parameters:**
|
|
24
|
+
- `radius` (number) - Circle radius
|
|
25
|
+
- `segments` (number, optional) - Number of segments. Default: auto (smooth)
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
const c = circle2d(25);
|
|
29
|
+
const octagon = circle2d(25, 8);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### `roundedRect(width, height, radius, center?)`
|
|
33
|
+
Creates a rectangle with rounded corners.
|
|
34
|
+
|
|
35
|
+
**Parameters:**
|
|
36
|
+
- `width` (number) - Width
|
|
37
|
+
- `height` (number) - Height
|
|
38
|
+
- `radius` (number) - Corner radius
|
|
39
|
+
- `center` (boolean, optional) - If true, centers at origin. Default: false
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
const rounded = roundedRect(60, 40, 5);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `polygon(points)`
|
|
46
|
+
Creates a polygon from an array of [x, y] points or Point2D objects.
|
|
47
|
+
|
|
48
|
+
**Parameters:**
|
|
49
|
+
- `points` (([number, number] | Point2D)[]) - Array of vertex coordinates or Point2D objects
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const triangle = polygon([[0, 0], [50, 0], [25, 40]]);
|
|
53
|
+
|
|
54
|
+
// Also accepts Point2D objects
|
|
55
|
+
const p1 = point(0, 0), p2 = point(50, 0), p3 = point(25, 40);
|
|
56
|
+
const triangle2 = polygon([p1, p2, p3]);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `ngon(sides, radius)`
|
|
60
|
+
Creates a regular polygon (equilateral).
|
|
61
|
+
|
|
62
|
+
**Parameters:**
|
|
63
|
+
- `sides` (number) - Number of sides
|
|
64
|
+
- `radius` (number) - Radius from center to vertex
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const hex = ngon(6, 25);
|
|
68
|
+
const triangle = ngon(3, 30);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `ellipse(rx, ry, segments?)`
|
|
72
|
+
Creates an ellipse.
|
|
73
|
+
|
|
74
|
+
**Parameters:**
|
|
75
|
+
- `rx` (number) - X radius
|
|
76
|
+
- `ry` (number) - Y radius
|
|
77
|
+
- `segments` (number, optional) - Number of segments. Default: 64
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
const oval = ellipse(40, 20);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `slot(length, width)`
|
|
84
|
+
Creates an oblong shape (rectangle with semicircle ends).
|
|
85
|
+
|
|
86
|
+
**Parameters:**
|
|
87
|
+
- `length` (number) - Total length
|
|
88
|
+
- `width` (number) - Width
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
const oblong = slot(60, 20);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `star(points, outerRadius, innerRadius)`
|
|
95
|
+
Creates a star shape.
|
|
96
|
+
|
|
97
|
+
**Parameters:**
|
|
98
|
+
- `points` (number) - Number of star points
|
|
99
|
+
- `outerRadius` (number) - Outer radius (tip of points)
|
|
100
|
+
- `innerRadius` (number) - Inner radius (between points)
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
const star5 = star(5, 30, 15);
|
|
104
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Sketch Transforms
|
|
2
|
+
|
|
3
|
+
2D transformations for sketches. All transforms are **chainable** and **immutable** (return new sketches). Colors are preserved through all transforms.
|
|
4
|
+
|
|
5
|
+
## Methods
|
|
6
|
+
|
|
7
|
+
### `.clone()` / `.duplicate()`
|
|
8
|
+
Create an explicit copy handle of a sketch (same profile/color) so variants are easy to branch.
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
const profile = rect(40, 20);
|
|
12
|
+
const left = profile.clone().translate(-30, 0);
|
|
13
|
+
const right = profile.duplicate().translate(30, 0);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### `.translate(x, y?)`
|
|
17
|
+
Moves the sketch.
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const moved = rect(50, 30).translate(100, 50);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### `.rotate(degrees)`
|
|
24
|
+
Rotates around the origin.
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const rotated = rect(50, 30).rotate(45);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### `.rotateAround(degrees, pivot)`
|
|
31
|
+
Rotates around a specific point instead of origin.
|
|
32
|
+
|
|
33
|
+
**Parameters:**
|
|
34
|
+
- `degrees` (number) — Rotation angle
|
|
35
|
+
- `pivot` ([number, number]) — Point to rotate around
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const hook = rect(4, 20).rotateAround(-35, [2, 0]);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `.scale(v)`
|
|
42
|
+
Scales the sketch.
|
|
43
|
+
|
|
44
|
+
**Parameters:**
|
|
45
|
+
- `v` (number | [number, number]) — Uniform scale or per-axis scale
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const bigger = circle2d(10).scale(2);
|
|
49
|
+
const stretched = rect(10, 10).scale([2, 0.5]);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### `.mirror(normal)`
|
|
53
|
+
Mirrors across a line defined by its normal vector.
|
|
54
|
+
|
|
55
|
+
**Parameters:**
|
|
56
|
+
- `normal` ([number, number]) — Line normal (doesn't need to be unit length)
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
const mirrored = sketch.mirror([1, 0]); // Mirror across Y axis
|
|
60
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Bill of Materials
|
|
2
|
+
|
|
3
|
+
These APIs annotate a model for report/export workflows. They do not change geometry, so they are outside the required model-building reading set.
|
|
4
|
+
|
|
5
|
+
## `bom(quantity, description, opts?)`
|
|
6
|
+
|
|
7
|
+
Register a bill-of-materials entry for report export.
|
|
8
|
+
|
|
9
|
+
Use this for real-world parts or materials that cannot be inferred reliably from geometry alone.
|
|
10
|
+
|
|
11
|
+
**Parameters:**
|
|
12
|
+
- `quantity` (number) - must be finite and `>= 0`; `0` is ignored
|
|
13
|
+
- `description` (string) - human-readable item description
|
|
14
|
+
- `opts` (object, optional):
|
|
15
|
+
- `unit` (string) - default `"pieces"`
|
|
16
|
+
- `key` (string) - explicit aggregation key when multiple descriptions should collapse to one line item
|
|
17
|
+
|
|
18
|
+
**Returns:** `void`
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const tubeLen = param("Tube Length", 1200, { min: 300, max: 4000, unit: "mm" });
|
|
22
|
+
const boltCount = param("Bolt Count", 16, { min: 0, max: 200, integer: true });
|
|
23
|
+
const boltLength = param("Bolt Length", 16, { min: 6, max: 80, unit: "mm" });
|
|
24
|
+
|
|
25
|
+
bom(tubeLen, "iron tube 30 x 20", { unit: "mm" });
|
|
26
|
+
bom(boltCount, `M4 bolt of ${boltLength} mm length`, { unit: "pieces" });
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Aggregation behavior:
|
|
30
|
+
- rows are grouped by normalized `description + unit`
|
|
31
|
+
- `key` overrides the default grouping rule
|
|
32
|
+
- grouped rows render on the report's Bill of Materials page
|
|
33
|
+
|
|
34
|
+
## Assembly BOM Helpers
|
|
35
|
+
|
|
36
|
+
Assembly graphs can also carry metadata for downstream reporting:
|
|
37
|
+
|
|
38
|
+
- `addPart(name, shape, { metadata? })`
|
|
39
|
+
- `solved.bom()`
|
|
40
|
+
- `solved.bomCsv()`
|
|
41
|
+
- `bomToCsv(rows)`
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
const mech = assembly("Arm")
|
|
45
|
+
.addPart("base", box(80, 80, 20, true), {
|
|
46
|
+
metadata: { material: "PETG", process: "FDM", qty: 1 },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const solved = mech.solve();
|
|
50
|
+
const csv = solved.bomCsv();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See `examples/api/bill-of-materials.forge.js` for a complete script-authored BOM example.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# BREP Export Parity
|
|
2
|
+
|
|
3
|
+
This file tracks exact STEP/BREP export support. It is intentionally separated from the model-building docs because it describes output coverage, not the authoring surface itself.
|
|
4
|
+
|
|
5
|
+
This table is the source of truth for ForgeCAD exact STEP/BREP export support.
|
|
6
|
+
|
|
7
|
+
Update it whenever:
|
|
8
|
+
- a Forge operation becomes exactly exportable
|
|
9
|
+
- support becomes partial or regresses
|
|
10
|
+
- a planned feature moves to implemented
|
|
11
|
+
|
|
12
|
+
## Current Backend
|
|
13
|
+
|
|
14
|
+
- Export executor: `uv run cli/forge-brep-export.py`
|
|
15
|
+
- Compiler target: `cadquery-occt`
|
|
16
|
+
- Exact kernel backend: CadQuery on OpenCascade
|
|
17
|
+
- Default export policy: exact-subset only, never silent mesh-to-fake-BREP conversion
|
|
18
|
+
- Optional CLI fallback: `--allow-faceted` exports closed mesh solids as explicit faceted OCCT solids for STEP/BREP; this is not exact replay
|
|
19
|
+
|
|
20
|
+
## Parity Table
|
|
21
|
+
|
|
22
|
+
| Forge Feature | Status | Exact Export | Notes |
|
|
23
|
+
| --- | --- | --- | --- |
|
|
24
|
+
| `box()` | Supported | Yes | Native OCCT solid replay |
|
|
25
|
+
| `cylinder()` | Supported | Yes | Straight cylinder and cone-style `radiusTop` replay |
|
|
26
|
+
| `sphere()` | Supported | Yes | Native OCCT solid replay |
|
|
27
|
+
| `rect()` | Supported | Yes | As a profile for supported extrude/revolve flows |
|
|
28
|
+
| `circle2d()` | Supported | Yes | As a profile for supported extrude/revolve flows |
|
|
29
|
+
| `roundedRect()` | Supported | Yes | Replayed as an exact rounded wire/profile |
|
|
30
|
+
| `rect(...).translate()` | Supported | Yes | Recorded as profile transforms |
|
|
31
|
+
| `circle2d(...).translate()` | Supported | Yes | Recorded as profile transforms |
|
|
32
|
+
| `roundedRect(...).translate()` | Supported | Yes | Recorded as profile transforms |
|
|
33
|
+
| `rect(...).rotate()` | Supported | Yes | Recorded as profile transforms |
|
|
34
|
+
| `circle2d(...).rotate()` | Supported | Yes | Recorded as profile transforms |
|
|
35
|
+
| `roundedRect(...).rotate()` | Supported | Yes | Recorded as profile transforms |
|
|
36
|
+
| `rect/circle/roundedRect.scale(...)` | Supported | Yes | Recorded as exact affine profile transforms |
|
|
37
|
+
| `polygon()` / `ngon()` / polygon-backed `ellipse()` / `star()` | Supported | Yes | Replayed as exact line-segment profiles from recorded point loops |
|
|
38
|
+
| `slot()` | Supported | Yes | Built from exact rect/circle booleans |
|
|
39
|
+
| Sketch booleans (`union2d`, `difference2d`, `intersection2d`) | Supported | Yes | Only when every child profile is exact-exportable |
|
|
40
|
+
| `rect/circle/roundedRect.extrude(height)` | Supported | Yes | `twist` / `divisions` must be absent |
|
|
41
|
+
| `rect/circle/roundedRect.extrude(height, { scaleTop })` | Supported | Yes | Replayed as exact lofts; sketch booleans are decomposed into 3D booleans when needed |
|
|
42
|
+
| `rect/circle/roundedRect.revolve(degrees)` | Supported | Yes | Replayed around Forge's revolve axis convention |
|
|
43
|
+
| `Sketch.offset(delta, 'Round')` | Partial | Yes | Exact round-offset replay for exact-exportable profiles; `Square` / `Miter` still drop the plan |
|
|
44
|
+
| `shape.translate()` | Supported | Yes | Recorded as exact solid transform |
|
|
45
|
+
| `shape.rotate(x, y, z)` | Supported | Yes | Euler replay only |
|
|
46
|
+
| `shape.scale(v)` | Supported | Yes | Recorded as an exact affine solid transform when every scale factor is finite and non-zero |
|
|
47
|
+
| `rotateAround(...)` | Supported | Yes | Exact arbitrary-axis rotation is recorded with axis + pivot |
|
|
48
|
+
| `pointAlong(...)` | Supported | Yes | Replayed via exact arbitrary-axis rotation from Forge's +Z axis |
|
|
49
|
+
| `mirror(...)` | Supported | Yes | Replayed as an exact mirror transform across the origin plane normal |
|
|
50
|
+
| `Shape.transform(matrix)` | Partial | Yes | Rigid affine subset only: orthonormal rotation + translation; scale/shear/perspective still unsupported |
|
|
51
|
+
| `union()` | Supported | Yes | Only when every operand is exact-exportable |
|
|
52
|
+
| `difference()` | Supported | Yes | Only when every operand is exact-exportable |
|
|
53
|
+
| `intersection()` | Supported | Yes | Only when every operand is exact-exportable |
|
|
54
|
+
| `split(cutter)` | Supported | Yes | Replayed as the exact pair `intersection(base, cutter)` and `difference(base, cutter)` when both operands are exact-exportable |
|
|
55
|
+
| Returned multi-object scene | Supported | Yes | Exported as a STEP/BREP compound |
|
|
56
|
+
| Returned mixed sketch + solid scene | Supported | Yes | Exact solids export; sketch-only objects are skipped with a warning |
|
|
57
|
+
| Sketch `mirror()` | Supported | Yes | Recorded as an exact profile reflection across the origin line normal |
|
|
58
|
+
| `loft()` | Partial | Yes | Forge now records loft intent in the compile graph and exports compatible section stacks through CadQuery/OCCT lofting, but runtime preview remains sampled/level-set and some mixed-topology stacks can still exceed OCCT loft compatibility |
|
|
59
|
+
| `sweep()` | Partial | Yes | Forge now records sweep intent in the compile graph and exports compile-covered profiles along the canonical sampled polyline path; runtime preview remains sampled/level-set and `Curve3D` paths export through that sampled path representation |
|
|
60
|
+
| `levelSet()` | Unsupported | No | Mesh/SDF output by design |
|
|
61
|
+
| `smoothOut()` / `refine*()` / `simplify()` | Unsupported | No | Mesh post-processing, not exact BREP |
|
|
62
|
+
| `warp()` | Unsupported | No | Deformation is mesh-domain today |
|
|
63
|
+
| `hull3d()` / `Shape.hull()` / `hull2d()` / `Sketch.hull()` | Partial | No | Hull intent is now preserved in the Forge compile graph and reported explicitly, but there is still no exact convex-hull OCCT replay; `--allow-faceted` can export closed hull solids as faceted geometry |
|
|
64
|
+
| `trimByPlane()` / `splitByPlane()` | Supported | Yes | Replayed through an exact plane half-space trim in CadQuery/OCCT; `splitByPlane()` lowers to the pair of positive-side and opposite-side trims |
|
|
65
|
+
| `Shape.hole()` | Partial | Yes | Circular through/blind holes plus counterbores, countersinks, and planar `upToFace` termination on supported face-query targets now replay exactly; patterned, drafted/two-sided, threaded, and combined counterbore+countersink workflows are still outside the defended subset |
|
|
66
|
+
| `Shape.cutout()` | Partial | Yes | Sketch must already be placed with `onFace(...)`; blind/through and planar `upToFace` cut extents on defended face-query targets stay exact, but drafted, two-sided, and pattern-owned cut workflows are still unsupported |
|
|
67
|
+
| `sheetMetal(...).folded()` / `sheetMetal(...).flatPattern()` | Supported | Yes | Compiler-owned v1 sheet-metal subset: base panel, up to four `90°` edge flanges, explicit thickness/radius/K-factor, rectangular corner reliefs, and planar panel/flange cutouts all replay exactly from one semantic model; arbitrary solid conversion, hems, jogs, lofted bends, bend cutouts, and nonuniform thickness remain unsupported |
|
|
68
|
+
| `projectToPlane()`-driven downstream features | Partial | Yes | Exact replay is supported when the source reduces to one defended planar basis: straight placed extrusions, compatible shell/hole/cut descendants, and compatible boolean unions on matching parallel target planes; boolean difference/intersection, trim/fillet/chamfer silhouette changes, and non-parallel bases still reject with diagnostics |
|
|
69
|
+
| `Shape.shell(thickness, { openFaces })` | Partial | Yes | Compiler-owned shell v1 rewrites compatible `box()`, `cylinder()`, and straight `extrude()` bases plus rigid transforms into exact boolean/extrude/cylinder plans; tapered extrudes, scale transforms, and general boolean/revolve/loft/sweep/hull/trim bases are still unsupported |
|
|
70
|
+
| `filletEdge()` / `chamferEdge()` | Partial | Yes | Compiler-owned tracked-edge subset: vertical edges from compile-covered `box()` bodies and `rectangle(...).extrude(...)` flows, plus preserved propagated sibling edges after earlier supported edge-finish rewrites when a later supported boolean union still records one defended lineage; shell, hole/cut, boolean difference/intersection, unsupported unions, and the already-finished merged edge itself are still outside the defended exact subset |
|
|
71
|
+
| `TrackedShape` topology preservation | Partial | Synthetic only | Export succeeds for supported base solids, but named topology is not written to STEP/BREP |
|
|
72
|
+
| Colors/materials in STEP/BREP | Partial | STEP only | Scene-object colors are written to STEP via CadQuery assembly export; `.brep` remains geometry-only |
|
|
73
|
+
| STEP assembly structure/BOM metadata | Partial | Names only | STEP export writes a flat scene-object assembly to preserve names/colors; Forge assembly/BOM metadata is still not exported |
|
|
74
|
+
|
|
75
|
+
The current defended exact subset is exercised by the ordinary-parts corpus in [`examples/compiler-corpus/README.md`](../../../../examples/compiler-corpus/README.md).
|
|
76
|
+
|
|
77
|
+
## Planned Expansion Order
|
|
78
|
+
|
|
79
|
+
1. Exact provenance-preserving replay for library helpers such as `lib.elbow()`, `lib.bolt()`, and related fastener/tube builders
|
|
80
|
+
2. Safe exact affine scale replay where OCCT can preserve exact solids, especially scaled-sphere / pad workflows
|
|
81
|
+
3. Broader exact OCCT-native feature coverage where BREP matters most: wider `shell()` coverage, broader fillet/chamfer coverage, richer face-driven feature ops
|
|
82
|
+
4. Optional STEP product structure and metadata export
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Dimension Annotations
|
|
2
|
+
|
|
3
|
+
Dimension annotations are visual callouts used in the viewport and report export.
|
|
4
|
+
They are not constraints and do not change geometry, so they live outside the core model-building docs.
|
|
5
|
+
|
|
6
|
+
## `dim(from, to, opts?)`
|
|
7
|
+
|
|
8
|
+
Add a dimension between two points.
|
|
9
|
+
|
|
10
|
+
**Parameters:**
|
|
11
|
+
- `from` (`[number, number] | [number, number, number] | Point2D`)
|
|
12
|
+
- `to` (`[number, number] | [number, number, number] | Point2D`)
|
|
13
|
+
- `opts` (optional):
|
|
14
|
+
- `offset` (number, default `10`)
|
|
15
|
+
- `label` (string)
|
|
16
|
+
- `color` (string hex, for example `"#ffaa44"`)
|
|
17
|
+
- `component` (`string | string[]`) - explicit report ownership by returned object name
|
|
18
|
+
- `currentComponent` (boolean) - bind to the owning returned component instance
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const w = 120;
|
|
22
|
+
const h = 60;
|
|
23
|
+
const plate = box(w, 30, h, true);
|
|
24
|
+
|
|
25
|
+
dim([-w / 2, 0, 0], [w / 2, 0, 0], { label: "Width" });
|
|
26
|
+
dim([0, 0, -h / 2], [0, 0, h / 2], { label: "Height", offset: 14 });
|
|
27
|
+
|
|
28
|
+
return plate;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Ownership examples:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
dim([0, 0, 0], [0, 80, 0], {
|
|
35
|
+
label: "Leg Width",
|
|
36
|
+
currentComponent: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
dim([0, 0, 0], [0, 0, 18], {
|
|
40
|
+
label: "Top Gap",
|
|
41
|
+
component: "Tabletop",
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## `dimLine(line, opts?)`
|
|
46
|
+
|
|
47
|
+
Add a dimension along a `Line2D`.
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
const a = point(0, 0);
|
|
51
|
+
const b = point(100, 0);
|
|
52
|
+
dimLine(line(a, b), { label: "Span", offset: -8 });
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Ownership Rules (Report Pages)
|
|
56
|
+
|
|
57
|
+
- Use `currentComponent: true` when authoring imported parts and you want deterministic ownership by the calling instance.
|
|
58
|
+
- Use `component: "Part Name"` to route a dimension to another named returned object.
|
|
59
|
+
- If multiple owners are bound, the dimension is shared and appears on the assembly overview page.
|
|
60
|
+
- If no ownership is set, report export attempts automatic ownership via endpoint-in-bbox inference.
|
|
61
|
+
|
|
62
|
+
See `examples/api/dimensioned-bracket.forge.js` for baseline usage.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Viewport Runtime APIs
|
|
2
|
+
|
|
3
|
+
These APIs affect the viewer and scene presentation. They do not change the underlying model geometry contract, so they are not part of the required model-building reading set.
|
|
4
|
+
|
|
5
|
+
## `cutPlane(name, normal, offsetOrOptions?, options?)`
|
|
6
|
+
|
|
7
|
+
Define a named section plane for inspection.
|
|
8
|
+
|
|
9
|
+
**Parameters:**
|
|
10
|
+
- `name` (string) - label shown in the viewport controls
|
|
11
|
+
- `normal` (`[number, number, number]`) - direction toward the clipped side
|
|
12
|
+
- `offsetOrOptions` (number or object, optional):
|
|
13
|
+
- number: plane offset from origin along `normal`
|
|
14
|
+
- object: `{ offset?: number, exclude?: string | string[] }`
|
|
15
|
+
- `options` (object, optional; used with numeric offset):
|
|
16
|
+
- `exclude` (`string | string[]`) - returned object `name` values to keep uncut
|
|
17
|
+
|
|
18
|
+
**Returns:** `void`
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const cutZ = param("Cut Height", 10, { min: -50, max: 50, unit: "mm" });
|
|
22
|
+
|
|
23
|
+
cutPlane("Inspection", [0, 0, 1], cutZ, {
|
|
24
|
+
exclude: ["Probe", "Fasteners"],
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Notes:
|
|
29
|
+
- planes are registered per script run
|
|
30
|
+
- viewport toggle state persists across parameter changes
|
|
31
|
+
- clipping is applied to returned named objects, so `exclude` only works when names are stable
|
|
32
|
+
- newly exposed section faces render with a hatched overlay; pre-existing coplanar boundary faces are left unhatched
|
|
33
|
+
|
|
34
|
+
## `explodeView(options?)`
|
|
35
|
+
|
|
36
|
+
Override how the viewport explode slider offsets returned objects.
|
|
37
|
+
|
|
38
|
+
Explode offsets are resolved from the returned object tree, not from a flat list.
|
|
39
|
+
In `radial` mode each node follows its parent branch direction, then adds a smaller
|
|
40
|
+
local fan from the immediate parent/subassembly center, so nested assemblies peel
|
|
41
|
+
apart level by level without losing their branch structure.
|
|
42
|
+
|
|
43
|
+
In fixed-axis or fixed-vector modes, the branch itself follows that axis/vector, but
|
|
44
|
+
nested descendants fan out perpendicular to the branch by default so deep trees do
|
|
45
|
+
not keep stacking farther along the same axis.
|
|
46
|
+
|
|
47
|
+
By default this is container-oriented: named groups/subassemblies advance along the
|
|
48
|
+
tree, while plain leaves inside a group stay much closer and mostly fan locally
|
|
49
|
+
around their parent cluster unless you override them explicitly.
|
|
50
|
+
|
|
51
|
+
**Parameters:**
|
|
52
|
+
- `enabled` (boolean) - disable explode offsets for this script when `false`
|
|
53
|
+
- `amountScale` (number) - multiply the UI explode amount
|
|
54
|
+
- `stages` (number[]) - per-depth multipliers (depth 1 = first level, defaults to `1, 1/2, 1/3, ...`)
|
|
55
|
+
- `mode` (`'radial' | 'x' | 'y' | 'z' | [x, y, z]`) - default explode direction
|
|
56
|
+
- `axisLock` (`'x' | 'y' | 'z'`) - optional global axis lock
|
|
57
|
+
- `byName` (`Record<string, { stage?, direction?, axisLock? }>`)- per-object overrides keyed by returned object `name`
|
|
58
|
+
- `byPath` (`Record<string, { stage?, direction?, axisLock? }>`)- per-tree-path overrides using slash-separated object tree paths such as `"Drive/Shaft"`
|
|
59
|
+
|
|
60
|
+
**Returns:** `void`
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
explodeView({
|
|
64
|
+
amountScale: 1.2,
|
|
65
|
+
stages: [0.35, 0.8],
|
|
66
|
+
mode: 'radial',
|
|
67
|
+
byPath: {
|
|
68
|
+
"Drive/Shaft": { direction: [1, 0, 0], stage: 1.6 },
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## `jointsView(options?)`
|
|
74
|
+
|
|
75
|
+
Register viewport-only mechanism controls that animate returned objects without rerunning the script.
|
|
76
|
+
|
|
77
|
+
Use this when you want interactive articulation in the viewer but the geometry itself stays fixed.
|
|
78
|
+
|
|
79
|
+
Animation values are interpolated linearly between keyframes. Forge does **not**
|
|
80
|
+
auto-wrap revolute values across `-180/180` or `0/360` for you, because doing
|
|
81
|
+
that globally would break intentional multi-turn tracks.
|
|
82
|
+
|
|
83
|
+
**Key options:**
|
|
84
|
+
- `enabled`
|
|
85
|
+
- `joints`: `{ name, child, parent?, type?, axis?, pivot?, min?, max?, default?, unit? }[]`
|
|
86
|
+
- `couplings`: `{ joint, terms, offset? }[]`
|
|
87
|
+
- `animations`: `{ name, duration?, loop?, continuous?, keyframes }[]`
|
|
88
|
+
- `defaultAnimation`
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
jointsView({
|
|
92
|
+
joints: [
|
|
93
|
+
{
|
|
94
|
+
name: "Shoulder",
|
|
95
|
+
child: "Upper Arm",
|
|
96
|
+
parent: "Base",
|
|
97
|
+
type: "revolute",
|
|
98
|
+
axis: [0, -1, 0],
|
|
99
|
+
pivot: [0, 0, 46],
|
|
100
|
+
min: -30,
|
|
101
|
+
max: 110,
|
|
102
|
+
default: 15,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
animations: [
|
|
106
|
+
{
|
|
107
|
+
name: "Walk Cycle",
|
|
108
|
+
duration: 1.6,
|
|
109
|
+
loop: true,
|
|
110
|
+
keyframes: [
|
|
111
|
+
{ at: 0.0, values: { "Shoulder": 20 } },
|
|
112
|
+
{ at: 0.5, values: { "Shoulder": -10 } },
|
|
113
|
+
{ at: 1.0, values: { "Shoulder": 20 } },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`continuous: true` is for looping tracks that should keep accumulating across
|
|
121
|
+
cycles instead of snapping back to the first keyframe each time. Use it for
|
|
122
|
+
monotonic multi-turn drives such as `0 -> 360 -> 720`.
|
|
123
|
+
|
|
124
|
+
### Animation continuity for revolute joints
|
|
125
|
+
|
|
126
|
+
If an animation channel comes from `atan2(...)`, `normalizeAngleDeg(...)`, or
|
|
127
|
+
any other wrapped angle source, keep the sampled keyframes continuous before
|
|
128
|
+
passing them to `jointsView()`.
|
|
129
|
+
|
|
130
|
+
Bad branch-cut sample stream:
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
keyframes: [
|
|
134
|
+
{ at: 0.48, values: { "Power Rod": -171 } },
|
|
135
|
+
{ at: 0.50, values: { "Power Rod": -180 } },
|
|
136
|
+
{ at: 0.52, values: { "Power Rod": 171 } },
|
|
137
|
+
]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
That `-180 -> 171` jump is interpreted literally and the viewer will spin the
|
|
141
|
+
part the long way around.
|
|
142
|
+
|
|
143
|
+
Good continuous sample stream:
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
keyframes: [
|
|
147
|
+
{ at: 0.48, values: { "Power Rod": -171 } },
|
|
148
|
+
{ at: 0.50, values: { "Power Rod": -180 } },
|
|
149
|
+
{ at: 0.52, values: { "Power Rod": -189 } },
|
|
150
|
+
]
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Guidelines:
|
|
154
|
+
- Keep high-speed multi-turn joints authored as continuous angles (`0`, `360`,
|
|
155
|
+
`720`, etc.).
|
|
156
|
+
- Only unwrap channels that represent cyclic angles. Do not apply angle
|
|
157
|
+
unwrapping blindly to prismatic or other scalar values.
|
|
158
|
+
- If you build sampled helper utilities, let them unwrap a named set of joints
|
|
159
|
+
instead of guessing from every numeric channel.
|
|
160
|
+
|
|
161
|
+
## `viewConfig(options?)`
|
|
162
|
+
|
|
163
|
+
Configure viewport helper visuals for the current script.
|
|
164
|
+
|
|
165
|
+
Current support:
|
|
166
|
+
- `jointOverlay.enabled`
|
|
167
|
+
- joint overlay colors such as `axisColor`, `axisCoreColor`, `arcColor`, `zeroColor`
|
|
168
|
+
- joint overlay sizing and tessellation controls such as `axisLengthScale`, `arcVisualLimitDeg`, `arcStepDeg`
|
|
169
|
+
|
|
170
|
+
**Returns:** `void`
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
viewConfig({
|
|
174
|
+
jointOverlay: {
|
|
175
|
+
axisColor: "#13dfff",
|
|
176
|
+
arcColor: "#ff7a1a",
|
|
177
|
+
axisLineRadiusScale: 0.03,
|
|
178
|
+
arcLineRadiusScale: 0.022,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## `lib.explode(items, options?)`
|
|
184
|
+
|
|
185
|
+
Apply deterministic exploded-view offsets to an assembly tree while preserving names, colors, and nesting.
|
|
186
|
+
|
|
187
|
+
`radial` separation is branch-aware and parent-relative: each child follows the
|
|
188
|
+
direction of its parent branch, then fans out locally inside that branch. This keeps
|
|
189
|
+
subassemblies visually grouped while still letting their internals break apart.
|
|
190
|
+
|
|
191
|
+
For non-radial fixed-axis or fixed-vector modes, nested descendants keep the branch
|
|
192
|
+
offset but spread perpendicular to it by default.
|
|
193
|
+
|
|
194
|
+
Default behavior is tree-like rather than flat: containers separate recursively,
|
|
195
|
+
while unconfigured leaves inside a container use a smaller local fan so sibling parts
|
|
196
|
+
stay visually associated with their parent group.
|
|
197
|
+
|
|
198
|
+
Works with:
|
|
199
|
+
- arrays of shapes/sketches/named items
|
|
200
|
+
- nested `{ name, group: [...] }` structures
|
|
201
|
+
- `ShapeGroup` outputs
|
|
202
|
+
|
|
203
|
+
**Parameters:**
|
|
204
|
+
- `items` (`ExplodeItem[] | ShapeGroup`)
|
|
205
|
+
- `options`:
|
|
206
|
+
- `amount` (number)
|
|
207
|
+
- `stages` (number[])
|
|
208
|
+
- `mode` (`'radial' | 'x' | 'y' | 'z' | [x, y, z]`)
|
|
209
|
+
- `axisLock` (`'x' | 'y' | 'z'`)
|
|
210
|
+
- `byName`
|
|
211
|
+
- `byPath`
|
|
212
|
+
|
|
213
|
+
Named items may also include:
|
|
214
|
+
- `explode: { stage?, direction?, axisLock? }`
|
|
215
|
+
|
|
216
|
+
**Returns:** same structure type as input, with translated geometry
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const explodeAmt = param("Explode", 0, { min: 0, max: 40, unit: "mm" });
|
|
220
|
+
|
|
221
|
+
return lib.explode(assembly, {
|
|
222
|
+
amount: explodeAmt,
|
|
223
|
+
stages: [0.4, 0.8],
|
|
224
|
+
mode: 'radial',
|
|
225
|
+
byName: {
|
|
226
|
+
"Shaft": { direction: [1, 0, 0], stage: 1.4 },
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
```
|