forgecad 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -12
- package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-D4bocK4E.js} +250 -151
- package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
- package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-D3A_g8V3.js} +329 -163
- package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-BWYUSpUN.css} +590 -136
- package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
- package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-kWjKaC_t.js} +2 -4
- package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
- package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
- package/dist/assets/PricingPage-BsU5vzEx.js +232 -0
- package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-PqvpAKIs.js} +129 -5
- package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-C-hzNUMy.js} +8949 -3161
- package/dist/assets/{Viewport-CoB46f5R.js → index-Pz321YAt.js} +38382 -7501
- package/dist/assets/{index-2hfs_ub0.css → index-ay13WNfa.css} +726 -53
- package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
- package/dist/assets/{manifold-CqNMHHKO.js → manifold-BcbjWLIo.js} +4 -3
- package/dist/assets/{manifold-Cce9wRFz.js → manifold-DBckbFgx.js} +1 -1
- package/dist/assets/{manifold-D6BeHIOo.js → manifold-O2AAGXyj.js} +1 -1
- package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-Dxr-5A7w.js} +8760 -3559
- package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +341 -718
- package/dist/docs-raw/generated/assembly.md +699 -112
- package/dist/docs-raw/generated/concepts.md +1834 -1346
- package/dist/docs-raw/generated/core.md +1012 -1059
- package/dist/docs-raw/generated/curves.md +759 -116
- package/dist/docs-raw/generated/lib.md +43 -748
- package/dist/docs-raw/generated/output.md +139 -245
- package/dist/docs-raw/generated/sdf.md +208 -0
- package/dist/docs-raw/generated/sheet-metal.md +473 -21
- package/dist/docs-raw/generated/sketch.md +1518 -362
- package/dist/docs-raw/generated/viewport.md +368 -299
- package/dist/docs-raw/generated/wood.md +104 -0
- package/dist/index.html +2 -2
- package/dist/landing/proof-ams-adapter.png +0 -0
- package/dist/landing/proof-bolt-and-nut.png +0 -0
- package/dist/landing/proof-fillet-enclosure.png +0 -0
- package/dist/landing/proof-glasses.png +0 -0
- package/dist/landing/proof-gyroid.png +0 -0
- package/dist/sitemap.xml +6 -6
- package/dist-cli/forgecad.js +12321 -5700
- package/dist-cli/forgecad.js.map +1 -0
- package/dist-cli/solver-46FFSK2U.js +363 -0
- package/dist-cli/solver-46FFSK2U.js.map +1 -0
- package/dist-skill/CONTEXT.md +4890 -6302
- package/dist-skill/SKILL-dev.md +22 -66
- package/dist-skill/SKILL.md +20 -59
- package/dist-skill/docs/API/core/concepts.md +37 -92
- package/dist-skill/docs/CLI.md +341 -718
- package/dist-skill/docs/generated/assembly.md +699 -112
- package/dist-skill/docs/generated/core.md +1012 -1059
- package/dist-skill/docs/generated/curves.md +759 -116
- package/dist-skill/docs/generated/lib.md +43 -748
- package/dist-skill/docs/generated/output.md +139 -245
- package/dist-skill/docs/generated/sdf.md +208 -0
- package/dist-skill/docs/generated/sheet-metal.md +473 -21
- package/dist-skill/docs/generated/sketch.md +1518 -362
- package/dist-skill/docs/generated/viewport.md +368 -299
- package/dist-skill/docs/generated/wood.md +104 -0
- package/dist-skill/docs/guides/coordinate-system.md +11 -17
- package/dist-skill/docs/guides/geometry-conventions.md +13 -70
- package/dist-skill/docs/guides/joint-design.md +78 -0
- package/dist-skill/docs/guides/modeling-recipes.md +22 -195
- package/dist-skill/docs/guides/positioning.md +88 -147
- package/dist-skill/docs-dev/API/core/concepts.md +78 -0
- package/dist-skill/docs-dev/CLI.md +488 -0
- package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
- package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
- package/dist-skill/{docs → docs-dev}/coding.md +2 -4
- package/dist-skill/docs-dev/component-model.md +164 -0
- package/dist-skill/docs-dev/generated/assembly.md +779 -0
- package/dist-skill/docs-dev/generated/core.md +1676 -0
- package/dist-skill/docs-dev/generated/curves.md +855 -0
- package/dist-skill/docs-dev/generated/lib.md +55 -0
- package/dist-skill/docs-dev/generated/output.md +234 -0
- package/dist-skill/docs-dev/generated/sdf.md +208 -0
- package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
- package/dist-skill/docs-dev/generated/sketch.md +1753 -0
- package/dist-skill/docs-dev/generated/viewport.md +513 -0
- package/dist-skill/docs-dev/generated/wood.md +104 -0
- package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
- package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
- package/dist-skill/docs-dev/guides/joint-design.md +78 -0
- package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
- package/dist-skill/docs-dev/guides/positioning.md +151 -0
- package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
- package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
- package/examples/api/attachTo-basics.forge.js +8 -8
- package/examples/api/bill-of-materials.forge.js +9 -9
- package/examples/api/bolt-pattern.forge.js +5 -5
- package/examples/api/boolean-operations.forge.js +5 -5
- package/examples/api/bounding-box-visualizer.forge.js +3 -3
- package/examples/api/clone-duplicate.forge.js +2 -2
- package/examples/api/colors-union-vs-array.forge.js +6 -6
- package/examples/api/connector-assembly.forge.js +8 -6
- package/examples/api/connector-basics.forge.js +7 -7
- package/examples/api/constrained-sketch-mechanical.forge.js +4 -4
- package/examples/api/elbow-test.forge.js +3 -3
- package/examples/api/extrude-options.forge.js +8 -14
- package/examples/api/feature-created-faces.forge.js +6 -10
- package/examples/api/fillet-showcase.forge.js +2 -2
- package/examples/api/folded-service-panel-cover.forge.js +2 -2
- package/examples/api/gears-tier1.forge.js +5 -5
- package/examples/api/group-test.forge.js +3 -3
- package/examples/api/group-vs-union.forge.js +1 -1
- package/examples/api/highlight-debug.forge.js +4 -0
- package/examples/api/js-module-pillars.js +1 -1
- package/examples/api/js-module-scene.js +2 -2
- package/examples/api/mesh-import-slats.forge.js +4 -4
- package/examples/api/patterns.forge.js +3 -3
- package/examples/api/pointAlong-orientation.forge.js +3 -3
- package/examples/api/profile-2020-b-slot6.forge.js +4 -5
- package/examples/api/route-perimeter-flange.forge.js +1 -1
- package/examples/api/sdf-rover-demo.forge.js +10 -10
- package/examples/api/sketch-on-face-demo.forge.js +2 -2
- package/examples/api/sketch-regions.forge.js +4 -4
- package/examples/api/sketch-rounding-strategies.forge.js +1 -1
- package/examples/api/smooth-curve-connections.forge.js +1 -1
- package/examples/api/transition-curves.forge.js +4 -4
- package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
- package/examples/api/variable-sweep-test.forge.js +2 -2
- package/examples/api/wood-joinery.forge.js +60 -0
- package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
- package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
- package/examples/constraints/01-fully-constrained-rect.forge.js +2 -2
- package/examples/constraints/02-underconstrained-triangle.forge.js +1 -1
- package/examples/constraints/03-redundant-constraints.forge.js +2 -2
- package/examples/constraints/05-parallel-with-linedistance.forge.js +2 -2
- package/examples/constraints/06-complex-spectrogram.forge.js +1 -1
- package/examples/constraints/07-perpendicular-chain.forge.js +4 -4
- package/examples/constraints/08-symmetric-bracket.forge.js +4 -4
- package/examples/constraints/09-stress-spiral.forge.js +1 -1
- package/examples/constraints/10-stress-honeycomb.forge.js +1 -1
- package/examples/constraints/11-surface-grid.forge.js +2 -2
- package/examples/constraints/12-surface-nested.forge.js +4 -4
- package/examples/constraints/13-surface-complex.forge.js +1 -1
- package/examples/exact-arc-housing.forge.js +12 -0
- package/examples/experiments/drone-arm.forge.js +53 -0
- package/examples/furniture/adjustable-table.forge.js +15 -15
- package/examples/furniture/bathroom.forge.js +26 -26
- package/examples/furniture/chair.forge.js +13 -13
- package/examples/furniture/picture-frame.forge.js +6 -6
- package/examples/furniture/shoe-rack-doors.forge.js +8 -8
- package/examples/furniture/shoe-rack.forge.js +7 -7
- package/examples/furniture/table-lamp.forge.js +8 -8
- package/examples/gcode/lissajous-vase.forge.js +4 -4
- package/examples/gcode/math-surface.forge.js +3 -3
- package/examples/gcode/parametric-vase.forge.js +4 -4
- package/examples/gcode/spiral-tower.forge.js +4 -4
- package/examples/generative/crystal-growth.forge.js +9 -9
- package/examples/generative/frost-spires.forge.js +9 -9
- package/examples/generative/golden-spiral-tower.forge.js +11 -11
- package/examples/generative/molten-forge.forge.js +6 -6
- package/examples/generative/neon-coral.forge.js +7 -7
- package/examples/mechanical/3d-printer.forge.js +37 -37
- package/examples/mechanical/5-finger-robot-hand.forge.js +19 -19
- package/examples/mechanical/airplane-propeller.forge.js +9 -9
- package/examples/mechanical/bolt-and-nut.forge.js +10 -10
- package/examples/mechanical/door-with-hinges.forge.js +7 -7
- package/examples/mechanical/fillet-enclosure.forge.js +15 -11
- package/examples/mechanical/headphone-hanger-v2.forge.js +11 -11
- package/examples/mechanical/robot_hand.forge.js +24 -24
- package/examples/mechanical/robot_hand_2.forge.js +26 -26
- package/examples/nurbs-surface.forge.js +8 -0
- package/examples/nurbs-tube.forge.js +7 -0
- package/examples/products/bottle.forge.js +8 -8
- package/examples/products/chess-set.forge.js +25 -25
- package/examples/products/classical-piano.forge.js +20 -20
- package/examples/products/clock.forge.js +33 -33
- package/examples/products/cup.forge.js +5 -5
- package/examples/products/iphone.forge.js +20 -20
- package/examples/products/laptop.forge.js +24 -24
- package/examples/products/laser-cut-box.forge.js +6 -6
- package/examples/products/laser-cut-tray.forge.js +6 -6
- package/examples/products/liquid-soap-dispenser.forge.js +23 -23
- package/examples/products/origami-fish.forge.js +14 -12
- package/examples/products/spiderman-cake.forge.js +6 -6
- package/examples/shelf/container.forge.js +5 -5
- package/examples/shelf/shelf-unit.forge.js +6 -6
- package/examples/toolbox/bolted-joint.forge.js +7 -7
- package/package.json +9 -4
- package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
- package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
- package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
- package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
- package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
- package/dist/assets/index-1CYp3zUp.js +0 -1455
- package/dist-skill/docs/API/API.md +0 -1666
- package/dist-skill/docs/API/README.md +0 -37
- package/dist-skill/docs/API/assembly/assembly.md +0 -617
- package/dist-skill/docs/API/core/edge-queries.md +0 -130
- package/dist-skill/docs/API/core/parameters.md +0 -122
- package/dist-skill/docs/API/core/reserved-terms.md +0 -137
- package/dist-skill/docs/API/core/sdf.md +0 -326
- package/dist-skill/docs/API/core/skill-cli.md +0 -194
- package/dist-skill/docs/API/core/skill-guide.md +0 -205
- package/dist-skill/docs/API/core/specs.md +0 -186
- package/dist-skill/docs/API/core/topology.md +0 -372
- package/dist-skill/docs/API/entities.md +0 -268
- package/dist-skill/docs/API/output/bom.md +0 -58
- package/dist-skill/docs/API/output/brep-export.md +0 -87
- package/dist-skill/docs/API/output/dimensions.md +0 -67
- package/dist-skill/docs/API/output/export.md +0 -110
- package/dist-skill/docs/API/output/gcode.md +0 -195
- package/dist-skill/docs/API/runtime/viewport.md +0 -420
- package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
- package/dist-skill/docs/API/sketch/anchor.md +0 -37
- package/dist-skill/docs/API/sketch/booleans.md +0 -91
- package/dist-skill/docs/API/sketch/core.md +0 -73
- package/dist-skill/docs/API/sketch/extrude.md +0 -62
- package/dist-skill/docs/API/sketch/on-face.md +0 -104
- package/dist-skill/docs/API/sketch/operations.md +0 -78
- package/dist-skill/docs/API/sketch/path.md +0 -75
- package/dist-skill/docs/API/sketch/primitives.md +0 -146
- package/dist-skill/docs/API/sketch/regions.md +0 -80
- package/dist-skill/docs/API/sketch/text.md +0 -108
- package/dist-skill/docs/API/sketch/transforms.md +0 -65
- package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
- package/dist-skill/docs/INDEX.md +0 -94
- package/dist-skill/docs/RELEASING.md +0 -55
- package/dist-skill/docs/cli-monetization.md +0 -111
- package/dist-skill/docs/deployment.md +0 -281
- package/dist-skill/docs/generated/concepts.md +0 -2112
- package/dist-skill/docs/internals/shape-from-slices.md +0 -152
- package/dist-skill/docs/platform/admin.md +0 -45
- package/dist-skill/docs/platform/architecture.md +0 -79
- package/dist-skill/docs/platform/auth.md +0 -110
- package/dist-skill/docs/platform/email.md +0 -67
- package/dist-skill/docs/platform/projects.md +0 -111
- package/dist-skill/docs/platform/sharing.md +0 -90
- package/dist-skill/docs/runbook.md +0 -345
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
skill-group: sketch
|
|
3
|
-
skill-order: 11
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Sketch Regions
|
|
7
|
-
|
|
8
|
-
Decompose complex sketches into their individual filled areas. This is essential when a sketch operation produces multiple disconnected regions and you need to work with them independently.
|
|
9
|
-
|
|
10
|
-
## `sketch.regions()`
|
|
11
|
-
|
|
12
|
-
Decompose a sketch into its distinct filled regions, returned largest-first by area.
|
|
13
|
-
|
|
14
|
-
A single sketch can contain several disconnected filled areas (e.g., two separate rectangles, a ring shape, or the result of a boolean that leaves islands). This method enumerates all top-level connected regions as independent `Sketch` objects.
|
|
15
|
-
|
|
16
|
-
**Returns:** `Sketch[]` — Array of region sketches, sorted by area (largest first)
|
|
17
|
-
|
|
18
|
-
```javascript
|
|
19
|
-
// Two disconnected rectangles — get each one separately
|
|
20
|
-
const pair = union2d(rect(40, 40), rect(40, 40).translate(60, 0));
|
|
21
|
-
const [larger, smaller] = pair.regions();
|
|
22
|
-
larger.extrude(10);
|
|
23
|
-
smaller.extrude(5);
|
|
24
|
-
|
|
25
|
-
// Ring shape — one region containing the ring
|
|
26
|
-
const ring = circle2d(50).subtract(circle2d(30));
|
|
27
|
-
const [ringRegion] = ring.regions();
|
|
28
|
-
ringRegion.extrude(8);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## `sketch.region(seed)`
|
|
32
|
-
|
|
33
|
-
Select the single filled region that contains a given 2D point. This lets you pick any enclosed area by pointing at it instead of sorting through all regions.
|
|
34
|
-
|
|
35
|
-
**Parameters:**
|
|
36
|
-
- `seed` (`[number, number]`) — A 2D point `[x, y]` strictly inside the desired region
|
|
37
|
-
|
|
38
|
-
**Returns:** `Sketch` — The region containing the seed point
|
|
39
|
-
|
|
40
|
-
**Throws:** If the seed is outside all regions, on a boundary edge, or inside a hole.
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
// Donut — select the ring area at radius 40
|
|
44
|
-
const donut = circle2d(50).subtract(circle2d(30));
|
|
45
|
-
const ring = donut.region([40, 0]);
|
|
46
|
-
ring.extrude(10);
|
|
47
|
-
|
|
48
|
-
// Complex boolean result — pick a specific island
|
|
49
|
-
const complex = union2d(rect(40, 40), rect(40, 40).translate(60, 0));
|
|
50
|
-
const rightBox = complex.region([80, 20]); // seed inside right box
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
> **Callout:** The seed point must be strictly inside the filled area — not on the boundary. If you're unsure where the regions are, use `.regions()` first to enumerate them. Each returned region has a `.bounds()` you can inspect.
|
|
54
|
-
|
|
55
|
-
## Constrained Sketch Regions
|
|
56
|
-
|
|
57
|
-
`ConstraintSketch` (from `constrainedSketch().solve()`) provides two additional methods for working with the line arrangement formed by its edges:
|
|
58
|
-
|
|
59
|
-
### `cs.detectArrangement()`
|
|
60
|
-
|
|
61
|
-
Enumerate all bounded regions formed by the non-construction line arrangement. Returns `Sketch[]` sorted largest-first.
|
|
62
|
-
|
|
63
|
-
```javascript
|
|
64
|
-
const sk = constrainedSketch();
|
|
65
|
-
// ... add geometry and constraints ...
|
|
66
|
-
const cs = sk.solve();
|
|
67
|
-
const regions = cs.detectArrangement();
|
|
68
|
-
regions[0].extrude(5); // extrude the largest region
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### `cs.detectArrangementRegion(seed)`
|
|
72
|
-
|
|
73
|
-
Select a single arrangement region by seed point. Same semantics as `sketch.region(seed)` but operates on the constraint sketch's line arrangement (DCEL face detection).
|
|
74
|
-
|
|
75
|
-
```javascript
|
|
76
|
-
const region = cs.detectArrangementRegion([10, 10]);
|
|
77
|
-
region.extrude(3);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
> **Callout:** `detectArrangement()` and `detectArrangementRegion()` use the raw line/arc geometry from the constraint solver, not the boolean profile. This means construction lines are excluded and the regions are formed by the geometric arrangement of edges — useful when you need to select specific enclosed areas from a complex constrained sketch.
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
skill-group: sketch
|
|
3
|
-
skill-order: 10
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 2D Text
|
|
7
|
-
|
|
8
|
-
Create filled text geometry from strings. Supports both the built-in **Forge Mono** geometric font and any **TTF/OTF font file** for professional typography. Text sketches can be extruded, engraved, or used anywhere a normal `Sketch` is accepted.
|
|
9
|
-
|
|
10
|
-
## `text2d(content, options?)`
|
|
11
|
-
|
|
12
|
-
Build a filled 2D `Sketch` from a text string.
|
|
13
|
-
|
|
14
|
-
**Parameters:**
|
|
15
|
-
- `content` (string) — The text to render
|
|
16
|
-
- `options` (TextOptions, optional):
|
|
17
|
-
- `size` (number) — Cap height in model units. Default: `10`. All proportions scale with this.
|
|
18
|
-
- `letterSpacing` (number) — Extra space between characters in model units. Negative tightens. Default: `0`
|
|
19
|
-
- `align` (`'left' | 'center' | 'right'`) — Horizontal alignment relative to x = 0. Default: `'left'`
|
|
20
|
-
- `baseline` (`'baseline' | 'center' | 'top'`) — Vertical alignment relative to y = 0. Default: `'baseline'`
|
|
21
|
-
- `font` (string | Font) — Path to a TTF/OTF font file, or a pre-loaded Font object from `loadFont()`. When omitted, uses the built-in Forge Mono font.
|
|
22
|
-
- `flattenTolerance` (number) — Bezier curve flattening tolerance in model units (font mode only). Smaller = smoother curves. Default: 0.5% of size.
|
|
23
|
-
|
|
24
|
-
**Returns:** `Sketch` — Filled 2D text geometry
|
|
25
|
-
|
|
26
|
-
```javascript
|
|
27
|
-
// Built-in geometric font (default)
|
|
28
|
-
text2d('FORGE CAD', { size: 8 }).extrude(1.2);
|
|
29
|
-
|
|
30
|
-
// Using a real font — professional typography with proper curves
|
|
31
|
-
text2d('Hello World', { size: 10, font: '/path/to/Arial.ttf' }).extrude(1);
|
|
32
|
-
|
|
33
|
-
// Pre-load font for reuse across multiple text calls
|
|
34
|
-
const font = loadFont('/path/to/Arial Bold.ttf');
|
|
35
|
-
text2d('Title', { size: 12, font }).extrude(1.5);
|
|
36
|
-
text2d('Subtitle', { size: 8, font, align: 'center' }).extrude(0.8);
|
|
37
|
-
|
|
38
|
-
// Centered label
|
|
39
|
-
text2d('V 2.0', { size: 6, align: 'center', baseline: 'center' });
|
|
40
|
-
|
|
41
|
-
// Engraved text on top face of a box
|
|
42
|
-
const label = text2d('REV A', { size: 5, align: 'center', baseline: 'center' });
|
|
43
|
-
const plate = box(60, 20, 5);
|
|
44
|
-
return plate.subtract(label.onFace(plate, 'top', { protrude: -0.5 }).extrude(1));
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Font Options
|
|
48
|
-
|
|
49
|
-
**Real fonts (TTF/OTF)** — Pass a file path or pre-loaded Font to the `font` option:
|
|
50
|
-
- Professional typography with proper bezier curves
|
|
51
|
-
- Full character set: uppercase, lowercase, accented characters, symbols
|
|
52
|
-
- Automatic kerning between character pairs
|
|
53
|
-
- Any TTF or OTF font file works
|
|
54
|
-
|
|
55
|
-
**Built-in: Forge Mono** (default when no `font` option) —
|
|
56
|
-
- **Style:** Geometric monoline sans-serif, squared-off and futuristic
|
|
57
|
-
- **Inspired by:** Eurostile, Chakra Petch
|
|
58
|
-
- **Characteristics:** Uniform stroke weight, flat open ends, no serifs
|
|
59
|
-
- **Character set:** Uppercase A–Z, digits 0–9, punctuation. Lowercase maps to uppercase
|
|
60
|
-
- No external font files needed — every character is constructed from geometric primitives
|
|
61
|
-
|
|
62
|
-
## `loadFont(source, cacheKey?)`
|
|
63
|
-
|
|
64
|
-
Pre-load and cache a font for reuse across multiple `text2d()` calls.
|
|
65
|
-
|
|
66
|
-
**Parameters:**
|
|
67
|
-
- `source` (string | ArrayBuffer) — File path to a TTF/OTF font, or raw font data as ArrayBuffer
|
|
68
|
-
- `cacheKey` (string, optional) — Cache key when passing ArrayBuffer
|
|
69
|
-
|
|
70
|
-
**Returns:** Font object (pass to `text2d`'s `font` option)
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
const font = loadFont('/System/Library/Fonts/Supplemental/Arial.ttf');
|
|
74
|
-
text2d('Line 1', { size: 8, font }).extrude(1);
|
|
75
|
-
text2d('Line 2', { size: 8, font }).extrude(1);
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## `textWidth(content, options?)`
|
|
79
|
-
|
|
80
|
-
Measure the rendered width of a string without creating geometry. Useful for layout calculations.
|
|
81
|
-
|
|
82
|
-
**Parameters:**
|
|
83
|
-
- `content` (string) — The text to measure
|
|
84
|
-
- `options` (object, optional):
|
|
85
|
-
- `size` (number) — Cap height in model units. Default: `10`
|
|
86
|
-
- `letterSpacing` (number) — Extra spacing. Default: `0`
|
|
87
|
-
|
|
88
|
-
**Returns:** `number` — Width of the rendered text in model units
|
|
89
|
-
|
|
90
|
-
```javascript
|
|
91
|
-
const label = 'SERIAL: 001';
|
|
92
|
-
const w = textWidth(label, { size: 6 });
|
|
93
|
-
|
|
94
|
-
// Create a plate that fits the text with padding
|
|
95
|
-
const plate = box(w + 10, 12, 2);
|
|
96
|
-
const text = text2d(label, { size: 6, align: 'center', baseline: 'center' })
|
|
97
|
-
.translate(w / 2 + 5, 6, 0);
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Alignment Quick Reference
|
|
101
|
-
|
|
102
|
-
| `align` | `baseline` | Origin position |
|
|
103
|
-
|---------|-----------|----------------|
|
|
104
|
-
| `'left'` | `'baseline'` | Bottom-left of first character (default) |
|
|
105
|
-
| `'center'` | `'center'` | Dead center of text block |
|
|
106
|
-
| `'right'` | `'top'` | Top-right corner |
|
|
107
|
-
|
|
108
|
-
The origin is at `(0, 0)` — alignment controls where the text sits relative to that point.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
skill-group: sketch
|
|
3
|
-
skill-order: 4
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Sketch Transforms
|
|
7
|
-
|
|
8
|
-
2D transformations for sketches. All transforms are **chainable** and **immutable** (return new sketches). Colors are preserved through all transforms.
|
|
9
|
-
|
|
10
|
-
## Methods
|
|
11
|
-
|
|
12
|
-
### `.clone()` / `.duplicate()`
|
|
13
|
-
Create an explicit copy handle of a sketch (same profile/color) so variants are easy to branch.
|
|
14
|
-
|
|
15
|
-
```javascript
|
|
16
|
-
const profile = rect(40, 20);
|
|
17
|
-
const left = profile.clone().translate(-30, 0);
|
|
18
|
-
const right = profile.duplicate().translate(30, 0);
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### `.translate(x, y?)`
|
|
22
|
-
Moves the sketch.
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
const moved = rect(50, 30).translate(100, 50);
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### `.rotate(degrees)`
|
|
29
|
-
Rotates around the sketch's bounding-box center.
|
|
30
|
-
|
|
31
|
-
```javascript
|
|
32
|
-
const rotated = rect(50, 30).rotate(45);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### `.rotateAround(degrees, pivot)`
|
|
36
|
-
Rotates around a specific point instead of the default center pivot.
|
|
37
|
-
|
|
38
|
-
**Parameters:**
|
|
39
|
-
- `degrees` (number) — Rotation angle
|
|
40
|
-
- `pivot` ([number, number]) — Point to rotate around
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
const hook = rect(4, 20).rotateAround(-35, [2, 0]);
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### `.scale(v)`
|
|
47
|
-
Scales the sketch from its bounding-box center.
|
|
48
|
-
|
|
49
|
-
**Parameters:**
|
|
50
|
-
- `v` (number | [number, number]) — Uniform scale or per-axis scale
|
|
51
|
-
|
|
52
|
-
```javascript
|
|
53
|
-
const bigger = circle2d(10).scale(2);
|
|
54
|
-
const stretched = rect(10, 10).scale([2, 0.5]);
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### `.mirror(normal)`
|
|
58
|
-
Mirrors across a line defined by its normal vector, passing through the sketch's bounding-box center.
|
|
59
|
-
|
|
60
|
-
**Parameters:**
|
|
61
|
-
- `normal` ([number, number]) — Line normal (doesn't need to be unit length)
|
|
62
|
-
|
|
63
|
-
```javascript
|
|
64
|
-
const mirrored = sketch.mirror([1, 0]); // Mirror across Y axis
|
|
65
|
-
```
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
skill-group: toolbox
|
|
3
|
-
skill-order: 1
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Toolbox — Fastener Library
|
|
7
|
-
|
|
8
|
-
Pre-built ISO metric fastener geometry available via `lib.*` in any ForgeCAD script.
|
|
9
|
-
|
|
10
|
-
## Supported catalog
|
|
11
|
-
|
|
12
|
-
This is the initial, intentionally small catalog. Coverage outside these items is not guaranteed.
|
|
13
|
-
|
|
14
|
-
| Family | Sizes | Standard |
|
|
15
|
-
|--------|-------|----------|
|
|
16
|
-
| Hex bolt (`lib.bolt`) | M4 – M10 (parametric) | ISO 4762 lookalike |
|
|
17
|
-
| Hex nut (`lib.nut`) | M4 – M10 (parametric) | ISO 4032 lookalike |
|
|
18
|
-
| Flat washer (`lib.washer`) | M2, M2.5, M3, M4, M5, M6, M8, M10 | DIN 125-A |
|
|
19
|
-
| Fastener hole (`lib.fastenerHole`) | M2, M2.5, M3, M4, M5, M6, M8, M10 | ISO metric fits |
|
|
20
|
-
| Fastener set (`lib.fastenerSet`) | M2 – M10 | Combines all of the above |
|
|
21
|
-
|
|
22
|
-
Sizes outside the table will throw. Extend `METRIC_HOLE_TABLE` / `WASHER_TABLE` in `library.ts` when adding new sizes.
|
|
23
|
-
|
|
24
|
-
## `lib.washer(size, options?)`
|
|
25
|
-
|
|
26
|
-
Returns a flat ring washer (DIN 125-A by default) centered at the origin, thickness along Z.
|
|
27
|
-
|
|
28
|
-
```javascript
|
|
29
|
-
const w = lib.washer("M5");
|
|
30
|
-
// outer dia 10 mm, inner dia 5.3 mm, thickness 1 mm
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Parameters**
|
|
34
|
-
|
|
35
|
-
| Name | Type | Default | Description |
|
|
36
|
-
|------|------|---------|-------------|
|
|
37
|
-
| `size` | `MetricSize` | required | ISO metric thread size string, e.g. `"M6"` |
|
|
38
|
-
| `options.standard` | `'din-125-a'` | `'din-125-a'` | Washer standard (only DIN 125-A for now) |
|
|
39
|
-
| `options.segments` | `number` | `48` | Circle segment count |
|
|
40
|
-
|
|
41
|
-
**DIN 125-A dimensions**
|
|
42
|
-
|
|
43
|
-
| Size | Inner dia (mm) | Outer dia (mm) | Thickness (mm) |
|
|
44
|
-
|------|---------------|----------------|----------------|
|
|
45
|
-
| M2 | 2.2 | 5.0 | 0.3 |
|
|
46
|
-
| M2.5 | 2.7 | 6.0 | 0.5 |
|
|
47
|
-
| M3 | 3.2 | 7.0 | 0.5 |
|
|
48
|
-
| M4 | 4.3 | 9.0 | 0.8 |
|
|
49
|
-
| M5 | 5.3 | 10.0 | 1.0 |
|
|
50
|
-
| M6 | 6.4 | 12.0 | 1.6 |
|
|
51
|
-
| M8 | 8.4 | 17.0 | 1.6 |
|
|
52
|
-
| M10 | 10.5 | 21.0 | 2.0 |
|
|
53
|
-
|
|
54
|
-
## `lib.fastenerSet(size, boltLength, options?)`
|
|
55
|
-
|
|
56
|
-
Returns all geometry needed for one complete bolted joint: bolt, nut, washers, and hole cutters — un-positioned so you can place them freely.
|
|
57
|
-
|
|
58
|
-
```javascript
|
|
59
|
-
const hw = lib.fastenerSet("M5", 20);
|
|
60
|
-
|
|
61
|
-
// Cut holes in two plates
|
|
62
|
-
const topPlate = box(60, 40, 8, true)
|
|
63
|
-
.subtract(hw.clearanceHole.translate(15, 10, 0));
|
|
64
|
-
const botPlate = box(60, 40, 8, true).translate(0, 0, -16)
|
|
65
|
-
.subtract(hw.tappedHole.translate(15, 10, -8));
|
|
66
|
-
|
|
67
|
-
// Place hardware
|
|
68
|
-
return [
|
|
69
|
-
{ name: "Top Plate", shape: topPlate, color: "#9ab4cc" },
|
|
70
|
-
{ name: "Bot Plate", shape: botPlate, color: "#b0b8c8" },
|
|
71
|
-
{ name: "Bolt", shape: hw.bolt.translate(15, 10, 4), color: "#aaaaaa" },
|
|
72
|
-
{ name: "Nut", shape: hw.nut.translate(15, 10, -19), color: "#888888" },
|
|
73
|
-
];
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Parameters**
|
|
77
|
-
|
|
78
|
-
| Name | Type | Default | Description |
|
|
79
|
-
|------|------|---------|-------------|
|
|
80
|
-
| `size` | `MetricSize` | required | ISO metric thread size |
|
|
81
|
-
| `boltLength` | `number` | required | Shaft length in mm (head excluded) |
|
|
82
|
-
| `options.washerUnderHead` | `boolean` | `true` | Include a washer shape for under the head |
|
|
83
|
-
| `options.washerUnderNut` | `boolean` | `true` | Include a washer shape for under the nut |
|
|
84
|
-
| `options.fit` | `FastenerFit` | `'normal'` | Clearance hole fit: `close`, `normal`, `loose`, or `tap` |
|
|
85
|
-
| `options.segments` | `number` | `36` | Thread/circle segment count |
|
|
86
|
-
|
|
87
|
-
**Result fields**
|
|
88
|
-
|
|
89
|
-
| Field | Type | Description |
|
|
90
|
-
|-------|------|-------------|
|
|
91
|
-
| `bolt` | `Shape` | Head top at z=0, shaft along −Z by `boltLength` |
|
|
92
|
-
| `nut` | `Shape` | Hex nut centered at z=0 |
|
|
93
|
-
| `washerUnderHead` | `Shape \| null` | Flat washer centered at z=0 |
|
|
94
|
-
| `washerUnderNut` | `Shape \| null` | Flat washer centered at z=0 |
|
|
95
|
-
| `clearanceHole` | `Shape` | Cutter cylinder for through-plate clearance, centered at z=0 |
|
|
96
|
-
| `tappedHole` | `Shape` | Cutter cylinder for tap-drill hole, centered at z=0 |
|
|
97
|
-
| `dims` | `FastenerSetDimensions` | Reference dimensions for placement and BOM |
|
|
98
|
-
|
|
99
|
-
**`FastenerSetDimensions` fields**
|
|
100
|
-
|
|
101
|
-
| Field | Description |
|
|
102
|
-
|-------|-------------|
|
|
103
|
-
| `size` | Thread size string |
|
|
104
|
-
| `nominalDiameter` | Numeric thread diameter (mm) |
|
|
105
|
-
| `boltLength` | As specified |
|
|
106
|
-
| `clearanceDia` | Clearance hole diameter for chosen fit (mm) |
|
|
107
|
-
| `tapDia` | Tap-drill diameter (mm) |
|
|
108
|
-
| `nutAcrossFlats` | Hex nut width across flats (mm) |
|
|
109
|
-
| `nutHeight` | Nut height (mm) |
|
|
110
|
-
| `washerOuterDia` / `washerInnerDia` / `washerThickness` | DIN 125-A washer dimensions (mm) |
|
|
111
|
-
|
|
112
|
-
## `lib.fastenerHole(opts)`
|
|
113
|
-
|
|
114
|
-
Lower-level helper that returns only a hole cutter (cylinder ± counterbore/countersink). Supports M2–M10 with four fit classes and optional counterbore/countersink geometry. See the full API reference for details.
|
|
115
|
-
|
|
116
|
-
## Pairing table
|
|
117
|
-
|
|
118
|
-
Use this to pick the right cutter fit for your workflow:
|
|
119
|
-
|
|
120
|
-
| Fit | Hole diameter | Use when |
|
|
121
|
-
|-----|--------------|----------|
|
|
122
|
-
| `close` | ≈ nominal + 0.2 mm | Press-location or close-tolerance slotting |
|
|
123
|
-
| `normal` | ≈ nominal + 0.5 mm | Standard through-bolt clearance (default) |
|
|
124
|
-
| `loose` | ≈ nominal + 1–2 mm | Adjustment slots or misaligned patterns |
|
|
125
|
-
| `tap` | ISO tap drill | Tapped hole in the mating part |
|
|
126
|
-
|
|
127
|
-
## Example
|
|
128
|
-
|
|
129
|
-
See [`examples/toolbox/bolted-joint.forge.js`](../../../../examples/toolbox/bolted-joint.forge.js) for a complete two-plate bolted assembly with BOM and exploded view.
|
package/dist-skill/docs/INDEX.md
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# ForgeCAD Documentation
|
|
2
|
-
|
|
3
|
-
Central entry point for all ForgeCAD documentation. Start here.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Operations & Runbook
|
|
8
|
-
|
|
9
|
-
The first place to look when debugging, deploying, or onboarding.
|
|
10
|
-
|
|
11
|
-
- **[Runbook](project/runbook.md)** — Dev server commands, local stack setup, health checks, production SSH, API endpoint reference, troubleshooting
|
|
12
|
-
- **[Deployment & Environment](project/deployment.md)** — Docker Compose architecture, environment variables, Coolify setup, database migrations
|
|
13
|
-
- **[Releasing](RELEASING.md)** — npm version, publish workflow, GitHub Releases
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Platform (Web App)
|
|
18
|
-
|
|
19
|
-
Documentation for the hosted service at forgecad.io.
|
|
20
|
-
|
|
21
|
-
- **[System Architecture](platform/architecture.md)** — Stack overview, URL routes, Docker topology, security
|
|
22
|
-
- **[Authentication](platform/auth.md)** — JWT tokens, OAuth (GitHub/Google), registration, password reset, session management
|
|
23
|
-
- **[Projects & Files](platform/projects.md)** — Project CRUD, member roles, file storage, storage quotas, SSE watching
|
|
24
|
-
- **[Model Sharing](platform/sharing.md)** — Publishing, public URLs, embeds, gist/URL/inline sharing
|
|
25
|
-
- **[Admin Dashboard](platform/admin.md)** — Admin panel, audit log, user management
|
|
26
|
-
- **[Email Delivery](platform/email.md)** — Resend setup, verification emails, password reset emails
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## CLI
|
|
31
|
-
|
|
32
|
-
- **[CLI Reference](CLI.md)** — Full command reference: dev/studio servers, export (STL/STEP/SVG/G-code/SDF), render, capture, notebooks, invariant checks
|
|
33
|
-
- **[Monetization & Licensing](project/cli-monetization.md)** — Free vs Pro tiers, license activation, feature gating strategy
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## API Reference (Model Authoring)
|
|
38
|
-
|
|
39
|
-
For users writing `.forge.js` scripts.
|
|
40
|
-
|
|
41
|
-
- **[API Overview](API/README.md)** — Reading plan and orientation
|
|
42
|
-
- **[Core API](API/API.md)** — Shapes, primitives, transforms, booleans, patterns
|
|
43
|
-
- **[Entities](API/entities.md)** — 2D/3D entity-based API
|
|
44
|
-
- **Sketches**: [Core](API/sketch/core.md) | [Primitives](API/sketch/primitives.md) | [Paths](API/sketch/path.md) | [Booleans](API/sketch/booleans.md) | [Operations](API/sketch/operations.md) | [Extrude/Revolve](API/sketch/extrude.md) | [Transforms](API/sketch/transforms.md) | [Regions](API/sketch/regions.md) | [Text](API/sketch/text.md) | [Anchoring](API/sketch/anchor.md) | [On-Face](API/sketch/on-face.md)
|
|
45
|
-
- **Assembly**: [Assembly & Kinematics](API/assembly/assembly.md)
|
|
46
|
-
- **Output**: [Export](API/output/export.md) | [BREP/STEP](API/output/brep-export.md) | [G-code](API/output/gcode.md) | [Dimensions](API/output/dimensions.md) | [BOM](API/output/bom.md)
|
|
47
|
-
- **Other**: [Sheet Metal](API/sheet-metal/sheet-metal.md) | [Fasteners](API/toolbox/fasteners.md) | [Viewport](API/runtime/viewport.md)
|
|
48
|
-
- **Core Concepts**: [Concepts](API/core/concepts.md) | [Parameters](API/core/parameters.md) | [Topology](API/core/topology.md) | [Edge Queries](API/core/edge-queries.md) | [Specs](API/core/specs.md) | [SDF](API/core/sdf.md)
|
|
49
|
-
- **AI Skill**: [Skill Guide](API/core/skill-guide.md) | [Skill CLI](API/core/skill-cli.md)
|
|
50
|
-
- **[Auto-Generated API Docs](generated/)** — Machine-generated from `forge-public-api.ts`
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Guides (Modeling)
|
|
55
|
-
|
|
56
|
-
Techniques and conventions for model authors.
|
|
57
|
-
|
|
58
|
-
- **[Coordinate System](guides/coordinate-system.md)** — Z-up convention, axis orientation
|
|
59
|
-
- **[Geometry Conventions](guides/geometry-conventions.md)** — Winding order, depth, normals
|
|
60
|
-
- **[Positioning](guides/positioning.md)** — Connectors, `matchTo()`, and placement strategies
|
|
61
|
-
- **[Modeling Recipes](guides/modeling-recipes.md)** — Common patterns, iteration, multi-file composition
|
|
62
|
-
- **[Skill Maintenance](guides/skill-maintenance.md)** — AI skill build process, `npm run refresh`
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Engine Internals
|
|
67
|
-
|
|
68
|
-
For contributors working on ForgeCAD's core engine.
|
|
69
|
-
|
|
70
|
-
- **[Compiler](internals/compiler.md)** — Multi-backend architecture (Manifold + OCCT), compile plans, lowering
|
|
71
|
-
- **[Constraint Solver](internals/constraint-solver.md)** — Solver pipeline, architecture, Levenberg-Marquardt
|
|
72
|
-
- **[Solver Quality](internals/constraint-solver-quality.md)** — Tunable vs architectural parameters
|
|
73
|
-
- **[2D Sketch Pipeline](internals/sketch-2d-pipeline.md)** — Two-track export, ProfileCompilePlan
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Development Standards
|
|
78
|
-
|
|
79
|
-
For contributors developing ForgeCAD itself.
|
|
80
|
-
|
|
81
|
-
- **[Coding Guidelines](project/coding.md)** — Project structure, workflow, adding new features
|
|
82
|
-
- **[Coding Best Practices](project/coding-best-practices.md)** — TypeScript, React, performance, self-review
|
|
83
|
-
- **[Blueprint-First Design](project/blueprint-first.md)** — No trigonometry tax, intent-driven API design
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## Processes
|
|
88
|
-
|
|
89
|
-
Operational procedures for multi-agent development and investigations.
|
|
90
|
-
|
|
91
|
-
- **[Multi-Agent Development](../processes/MULTI_AGENT_DEVELOPMENT.md)**
|
|
92
|
-
- **[Program Lead](../processes/PROGRAM-LEAD.md)**
|
|
93
|
-
- **[AI Investigation Projects](../processes/AI_INVESTIGATION_PROJECTS.md)**
|
|
94
|
-
- **[Benchmark SOP](../processes/README_BENCHMARK_SOP.md)**
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
skill-group: dev-conventions
|
|
3
|
-
skill-order: 4
|
|
4
|
-
skill-tiers: [dev]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Releasing ForgeCAD
|
|
8
|
-
|
|
9
|
-
## Quick Release
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm version patch # or minor / major
|
|
13
|
-
git push && git push --tags
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
That's it. GitHub Actions handles the rest:
|
|
17
|
-
- Builds everything (solver WASM + TypeScript + Vite + CLI + skills)
|
|
18
|
-
- Runs the full test suite
|
|
19
|
-
- Publishes to npm
|
|
20
|
-
- Creates a GitHub Release with auto-generated notes
|
|
21
|
-
- Production (forgecad.io) deploys automatically via Coolify on push to mainline
|
|
22
|
-
|
|
23
|
-
## Version Levels
|
|
24
|
-
|
|
25
|
-
| Command | When | Example |
|
|
26
|
-
|---------|------|---------|
|
|
27
|
-
| `npm version patch` | Bug fixes, small changes | 0.1.5 → 0.1.6 |
|
|
28
|
-
| `npm version minor` | New features | 0.1.5 → 0.2.0 |
|
|
29
|
-
| `npm version major` | Breaking changes | 0.1.5 → 1.0.0 |
|
|
30
|
-
|
|
31
|
-
`npm version` automatically:
|
|
32
|
-
1. Updates `version` in `package.json`
|
|
33
|
-
2. Creates a git commit (`v0.1.6`)
|
|
34
|
-
3. Creates a git tag (`v0.1.6`)
|
|
35
|
-
|
|
36
|
-
## Dry Run
|
|
37
|
-
|
|
38
|
-
To test the publish workflow without actually releasing:
|
|
39
|
-
|
|
40
|
-
1. Go to **Actions → Publish to npm & GitHub Release → Run workflow**
|
|
41
|
-
2. Check "Dry run" and run
|
|
42
|
-
|
|
43
|
-
## Prerequisites
|
|
44
|
-
|
|
45
|
-
- `NPM_TOKEN` must be set as a GitHub repo secret (Settings → Secrets → Actions)
|
|
46
|
-
- Create a **Granular Access Token** at npmjs.com → Account → Access Tokens
|
|
47
|
-
- Scope it to read+write on the `forgecad` package only
|
|
48
|
-
|
|
49
|
-
## What Gets Published
|
|
50
|
-
|
|
51
|
-
- `dist-cli/forgecad.js` — CLI binary
|
|
52
|
-
- `dist/` — web app bundles
|
|
53
|
-
- `dist-skill/` — AI skill documentation and context
|
|
54
|
-
- `examples/` — sample models
|
|
55
|
-
- `README.md`, `LICENSE`
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# CLI Monetization Strategy
|
|
2
|
-
|
|
3
|
-
## The Model: Sublime Text Now, Cursor Later
|
|
4
|
-
|
|
5
|
-
ForgeCAD follows a phased monetization strategy informed by how real software companies make money — not by how they try to prevent piracy.
|
|
6
|
-
|
|
7
|
-
### Phase 1: Honor System (Now)
|
|
8
|
-
|
|
9
|
-
Ship a compiled binary with a local license gate. Pro commands show a clear upgrade message. No enforcement beyond that.
|
|
10
|
-
|
|
11
|
-
**Why this works:**
|
|
12
|
-
- Sublime Text makes $5-25M/year with zero enforcement (nag popup only)
|
|
13
|
-
- WinRAR makes $20-40M/year with zero enforcement (40-day trial that never expires)
|
|
14
|
-
- JetBrains makes $593M/year despite being cracked constantly
|
|
15
|
-
- The pattern: individuals who crack it weren't going to pay. Enterprises must pay (legal compliance, audit risk, IT procurement). Pirates who learn ForgeCAD become advocates inside companies that buy licenses.
|
|
16
|
-
|
|
17
|
-
**What we ship:**
|
|
18
|
-
- Compiled native binary via `bun build --compile --minify` (source not trivially readable)
|
|
19
|
-
- Local JWT license validation at `~/.forgecad/license.json`
|
|
20
|
-
- Pro commands blocked with helpful message + free alternatives
|
|
21
|
-
- `forgecad license activate/deactivate/status` commands
|
|
22
|
-
|
|
23
|
-
**What we accept:**
|
|
24
|
-
- A developer can bypass the local check in 30 minutes
|
|
25
|
-
- String literals (error messages, API names) are visible via `strings`
|
|
26
|
-
- This is fine. The gate converts honest users; it doesn't stop determined pirates.
|
|
27
|
-
|
|
28
|
-
### Phase 2: Enterprise Features (Soon)
|
|
29
|
-
|
|
30
|
-
Add features that enterprises need and individuals don't care about:
|
|
31
|
-
- License server (floating seats, team management, usage reporting)
|
|
32
|
-
- Audit log (who exported what, when)
|
|
33
|
-
- SSO/SAML integration
|
|
34
|
-
- Priority support channel
|
|
35
|
-
|
|
36
|
-
These features don't need anti-piracy because they're inherently organizational. A solo developer doesn't need a license server.
|
|
37
|
-
|
|
38
|
-
### Phase 3: Server-Side Pro Features (Later)
|
|
39
|
-
|
|
40
|
-
Move high-value exports to run on the ForgeCAD server. The CLI uploads the model, the server processes it, the CLI downloads the result.
|
|
41
|
-
|
|
42
|
-
**Why this is piracy-proof:** The code for STEP export, Blender rendering, and gcode computation never ships to the user. You can't crack what you don't have.
|
|
43
|
-
|
|
44
|
-
**Proven by:**
|
|
45
|
-
- Cursor: $2B ARR — the editor is free, AI calls are server-side
|
|
46
|
-
- Figma: $1B revenue — all rendering is server-side
|
|
47
|
-
- Onshape: acquired for $470M — 100% browser-based, nothing local to crack
|
|
48
|
-
|
|
49
|
-
## Feature Tiers
|
|
50
|
-
|
|
51
|
-
| Tier | Price | Features |
|
|
52
|
-
|------|-------|----------|
|
|
53
|
-
| **Free** | $0 | Editor, dev server, run scripts, render PNG, export STL/3MF/SVG, all checks, debug tools |
|
|
54
|
-
| **Pro** | $15-25/mo | STEP/BREP export, render-hq (Blender), capture GIF/MP4, gcode, report PDF, cutting layout, SDF/URDF, sketch PDF |
|
|
55
|
-
| **Team** | $40-60/seat/mo | Everything in Pro + license server, floating seats, audit log, SSO, priority support |
|
|
56
|
-
|
|
57
|
-
### Why this split?
|
|
58
|
-
|
|
59
|
-
**Free tier** includes everything needed to learn ForgeCAD, build models, and 3D print. This is the funnel — hobbyists, students, and evaluators use this. It's genuinely useful, not a crippled demo.
|
|
60
|
-
|
|
61
|
-
**Pro tier** gates the features professionals need: exact CAD interchange (STEP), manufacturing outputs (gcode, cutting layouts), and presentation (render-hq, animations). These are the commands that save hours of work and justify a subscription.
|
|
62
|
-
|
|
63
|
-
**Team tier** gates organizational features that individuals don't need.
|
|
64
|
-
|
|
65
|
-
## What NOT to Do
|
|
66
|
-
|
|
67
|
-
### Don't rewrite in a compiled language for code protection
|
|
68
|
-
SolidWorks is C++ and it's cracked (SolidSquad). AutoCAD is C++ and it's cracked. The language doesn't matter — Ghidra/IDA Pro can reverse-engineer any native binary. The cost (rewriting years of work, losing the JS API that makes ForgeCAD special) far outweighs the marginal protection gain.
|
|
69
|
-
|
|
70
|
-
### Don't add aggressive DRM
|
|
71
|
-
Dassault embeds forensic signatures in SolidWorks files and sues pirates — this generates "many millions" in settlements but also generates resentment. For a small product trying to build a community, aggressive enforcement is counterproductive.
|
|
72
|
-
|
|
73
|
-
### Don't make the free tier useless
|
|
74
|
-
Ondsel (commercial FreeCAD) died in 2 years. Open-source CAD has near-zero commercial traction. But the opposite extreme — locking everything behind a paywall — kills adoption. The free tier must be genuinely useful.
|
|
75
|
-
|
|
76
|
-
### Don't ship source maps
|
|
77
|
-
Claude Code accidentally shipped `.map` files in npm v2.1.88. Within hours, the entire 1,900-file TypeScript codebase was extracted, mirrored to GitHub (1,100+ stars), and reverse-engineered. `.npmignore` must exclude `*.map`, `*.ts` source, and `tsconfig.json`.
|
|
78
|
-
|
|
79
|
-
## The Gabe Newell Principle
|
|
80
|
-
|
|
81
|
-
> "Piracy is almost always a service problem, not a pricing problem."
|
|
82
|
-
|
|
83
|
-
Steam proved this — Russia went from "don't bother, too much piracy" to Valve's largest European market once they localized and shipped same-day.
|
|
84
|
-
|
|
85
|
-
**Applied to ForgeCAD:** Make the paid version more convenient than the cracked one:
|
|
86
|
-
- Automatic updates (the binary self-updates, cracked copies don't)
|
|
87
|
-
- Cloud project sync (your models available everywhere)
|
|
88
|
-
- Share links (one-click sharing from the editor)
|
|
89
|
-
- Support (access to help when stuck)
|
|
90
|
-
- Team features (collaboration, permissions)
|
|
91
|
-
|
|
92
|
-
People pay for convenience and reliability, not because they can't find a crack.
|
|
93
|
-
|
|
94
|
-
## Distribution
|
|
95
|
-
|
|
96
|
-
| Channel | Format | Audience |
|
|
97
|
-
|---------|--------|----------|
|
|
98
|
-
| **npm** (`npm install -g forgecad`) | Minified `cli.js` (no source maps) | Primary channel |
|
|
99
|
-
| **forgecad.io** | Web editor (no install) | Evaluators, casual users |
|
|
100
|
-
|
|
101
|
-
ForgeCAD users write `.forge.js` files — they already have Node.js. npm is the only CLI distribution channel we need to maintain.
|
|
102
|
-
|
|
103
|
-
A compiled native binary build script exists (`npm run build:binary`) for potential future Homebrew distribution, but compiled binaries offer no additional source protection over minified JS (the source is stored as plain text in the binary's `__BUN` section). The binary is not worth maintaining as a separate channel until user volume justifies it.
|
|
104
|
-
|
|
105
|
-
### Build
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
TypeScript source → tsup (ESM bundle, 2.5MB) → dist-cli/forgecad.js
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Never ship source maps.** `.npmignore` must exclude `*.map`, `*.ts` source, and `tsconfig.json`.
|