forgecad 0.9.4 → 0.9.6
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-Da6hhpJx.js} +1 -1
- package/dist/assets/{BlogPage-Ck7g3ue2.js → BlogPage-Bl_sKeWb.js} +1 -1
- package/dist/assets/{DocsPage-9WaRC14b.js → DocsPage-Blz3Tp4j.js} +1 -6
- package/dist/assets/EditorApp-CuiPbtn5.js +12754 -0
- package/dist/assets/{EmbedViewer-37_PfMwv.js → EmbedViewer-BFG6-Ufm.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-CO8WL0CY.js → LandingPageProofDriven-DB9fQd5P.js} +1 -1
- package/dist/assets/{PricingPage-DADKGuOa.js → PricingPage-BMxYT_F0.js} +1 -1
- package/dist/assets/{SettingsPage-DKKI4W49.js → SettingsPage-VVQNrCAg.js} +1 -1
- package/dist/assets/{app-CwI02pTA.js → app-Dl9ymBWC.js} +355 -36
- package/dist/assets/cli/{render-Kw5hLEcL.js → render-CFtwKCCY.js} +203 -862
- package/dist/assets/{sectionPlaneMath-C8N0w8o3.js → distance-BEC2RjJi.js} +4150 -801
- package/dist/assets/{evalWorker-D6ub3kfS.js → evalWorker-CRvbzTXm.js} +2611 -528
- package/dist/assets/{manifold-CwDdMKyc.js → manifold-B9QSr-qP.js} +1 -1
- package/dist/assets/{manifold-DTvmxSDf.js → manifold-DpBXFS2K.js} +1 -1
- package/dist/assets/{manifold-lru0jwVw.js → manifold-DzZ4VRPs.js} +2 -2
- package/dist/assets/{renderSceneState-tvtNKNRi.js → renderSceneState-BuAXF2jh.js} +1 -1
- package/dist/assets/{reportWorker-DeqktDGt.js → reportWorker-BNWEnRg1.js} +2606 -525
- 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/beta-operations.md +4 -0
- package/dist/docs-raw/deployment.md +38 -23
- package/dist/docs-raw/generated/assembly.md +8 -3
- package/dist/docs-raw/generated/concepts.md +126 -46
- package/dist/docs-raw/generated/core.md +97 -47
- package/dist/docs-raw/generated/curves.md +113 -595
- 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/sketch.md +9 -1
- package/dist/docs-raw/generated/viewport.md +1 -9
- package/dist/docs-raw/guides/inspection-bundles.md +40 -9
- package/dist/docs-raw/runbook.md +3 -3
- 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 +5729 -2015
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-skill/CONTEXT.md +372 -667
- 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 +113 -595
- 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/sketch.md +9 -1
- package/dist-skill/docs/generated/viewport.md +1 -9
- package/dist-skill/docs/guides/inspection-bundles.md +40 -9
- 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 +113 -595
- 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/sketch.md +9 -1
- package/dist-skill/docs-dev/generated/viewport.md +1 -9
- package/dist-skill/docs-dev/guides/inspection-bundles.md +40 -9
- 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/guided-loft-olive-oil-bottle.forge.js +135 -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 +20 -2
- package/dist/assets/EditorApp-Dja2jMmW.js +0 -12509
- package/dist/docs-raw/skills/forgecad-api-dogfood.md +0 -130
- package/dist-skill/library/forgecad-api-dogfood/SKILL.md +0 -125
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guided loft vs ProductSkin: olive oil bottle.
|
|
3
|
+
*
|
|
4
|
+
* Left: the new namespaced Loft.withGuideRails(...) primitive. Right: the
|
|
5
|
+
* equivalent Product.skin(...) authoring style for comparison.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
Product.scenePreset('product');
|
|
9
|
+
|
|
10
|
+
viewConfig({
|
|
11
|
+
camera: { position: [190, -250, 150], target: [8, 0, 88], fov: 34 },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const darkOlive = {
|
|
15
|
+
color: '#34462f',
|
|
16
|
+
material: {
|
|
17
|
+
opacity: 0.58,
|
|
18
|
+
roughness: 0.14,
|
|
19
|
+
metalness: 0,
|
|
20
|
+
clearcoat: 1,
|
|
21
|
+
clearcoatRoughness: 0.04,
|
|
22
|
+
transmission: 0.28,
|
|
23
|
+
thickness: 4,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const labelStock = Product.materials.mattePlastic('#eee8d8');
|
|
27
|
+
const blackCap = Product.materials.softRubber({ color: '#171a15' });
|
|
28
|
+
|
|
29
|
+
const guidedStations = [
|
|
30
|
+
Loft.station(roundedRect(52, 34, 8), 0),
|
|
31
|
+
Loft.station(roundedRect(60, 38, 11), 78),
|
|
32
|
+
Loft.station(roundedRect(42, 27, 10), 128),
|
|
33
|
+
Loft.station(circle2d(12, 64), 166),
|
|
34
|
+
Loft.station(circle2d(14, 64), 184),
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const leftSilhouette = path()
|
|
38
|
+
.moveTo(-26, 0)
|
|
39
|
+
.bezierTo(-31, 30, -33, 55, -31, 72)
|
|
40
|
+
.bezierTo(-30, 90, -27, 107, -25, 118)
|
|
41
|
+
.bezierTo(-20, 142, -12, 152, -12, 166)
|
|
42
|
+
.lineTo(-14, 184);
|
|
43
|
+
|
|
44
|
+
const rightSilhouette = path()
|
|
45
|
+
.moveTo(26, 0)
|
|
46
|
+
.bezierTo(31, 30, 33, 55, 31, 72)
|
|
47
|
+
.bezierTo(30, 90, 27, 107, 25, 118)
|
|
48
|
+
.bezierTo(20, 142, 12, 152, 12, 166)
|
|
49
|
+
.lineTo(14, 184);
|
|
50
|
+
|
|
51
|
+
const backCrown = path()
|
|
52
|
+
.moveTo(-17, 0)
|
|
53
|
+
.bezierTo(-21, 30, -22, 56, -20, 72)
|
|
54
|
+
.bezierTo(-19, 92, -17, 108, -16, 118)
|
|
55
|
+
.bezierTo(-13, 142, -10, 154, -10, 166)
|
|
56
|
+
.lineTo(-12, 184);
|
|
57
|
+
|
|
58
|
+
const frontCrown = path()
|
|
59
|
+
.moveTo(17, 0)
|
|
60
|
+
.bezierTo(22, 30, 24, 56, 22, 72)
|
|
61
|
+
.bezierTo(21, 92, 19, 108, 18, 118)
|
|
62
|
+
.bezierTo(14, 142, 10, 154, 10, 166)
|
|
63
|
+
.lineTo(12, 184);
|
|
64
|
+
|
|
65
|
+
const leftRail = Loft.pathOnXz(leftSilhouette);
|
|
66
|
+
const rightRail = Loft.pathOnXz(rightSilhouette);
|
|
67
|
+
const backRail = Loft.pathOnYz(backCrown);
|
|
68
|
+
const frontRail = Loft.pathOnYz(frontCrown);
|
|
69
|
+
|
|
70
|
+
const guidedBottle = Loft.withGuideRails(
|
|
71
|
+
guidedStations,
|
|
72
|
+
[
|
|
73
|
+
Loft.leftRail(leftRail),
|
|
74
|
+
Loft.rightRail(rightRail),
|
|
75
|
+
Loft.backRail(backRail),
|
|
76
|
+
Loft.frontRail(frontRail),
|
|
77
|
+
],
|
|
78
|
+
{ samples: 19, edgeLength: 1.3 },
|
|
79
|
+
)
|
|
80
|
+
.as('guided-loft-olive-glass')
|
|
81
|
+
.material(darkOlive.material)
|
|
82
|
+
.color(darkOlive.color);
|
|
83
|
+
|
|
84
|
+
const guidedLabel = Product.applyMaterial(
|
|
85
|
+
roundedRect(34, 58, 4)
|
|
86
|
+
.extrude(0.8)
|
|
87
|
+
.rotateX(90)
|
|
88
|
+
.translate(0, 22.5, 76)
|
|
89
|
+
.as('guided-loft-cream-label'),
|
|
90
|
+
labelStock,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const guidedCap = Product.applyMaterial(cylinder(18, 12, 12, 64).translate(0, 0, 184).as('guided-loft-black-cap'), blackCap);
|
|
94
|
+
|
|
95
|
+
const guided = group(
|
|
96
|
+
{ name: 'body', shape: guidedBottle },
|
|
97
|
+
{ name: 'label', shape: guidedLabel },
|
|
98
|
+
{ name: 'cap', shape: guidedCap },
|
|
99
|
+
).translate(-52, 0, 0);
|
|
100
|
+
|
|
101
|
+
const productBottle = Product.skin('product-skin-olive-glass')
|
|
102
|
+
.axis('Z')
|
|
103
|
+
.stations([
|
|
104
|
+
Product.station('base').z(0).roundedRect(52, 34, 8),
|
|
105
|
+
Product.station('body').z(78).roundedRect(60, 38, 11),
|
|
106
|
+
Product.station('shoulder').z(128).roundedRect(42, 27, 10),
|
|
107
|
+
Product.station('neck').z(166).circle(24),
|
|
108
|
+
Product.station('lip').z(184).circle(28),
|
|
109
|
+
])
|
|
110
|
+
.rails({
|
|
111
|
+
leftSilhouette: Product.rail.polyline(leftRail),
|
|
112
|
+
frontCrown: Product.rail.polyline(frontRail),
|
|
113
|
+
})
|
|
114
|
+
.material(darkOlive)
|
|
115
|
+
.edgeLength(1.3)
|
|
116
|
+
.build();
|
|
117
|
+
|
|
118
|
+
const productLabel = Product.applyMaterial(
|
|
119
|
+
roundedRect(34, 58, 4)
|
|
120
|
+
.extrude(0.8)
|
|
121
|
+
.rotateX(90)
|
|
122
|
+
.translate(0, 22.5, 76)
|
|
123
|
+
.as('product-skin-cream-label'),
|
|
124
|
+
labelStock,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const productCap = Product.applyMaterial(cylinder(18, 12, 12, 64).translate(0, 0, 184).as('product-skin-black-cap'), blackCap);
|
|
128
|
+
|
|
129
|
+
const productSkinComparison = group(
|
|
130
|
+
{ name: 'body', shape: productBottle.toShape() },
|
|
131
|
+
{ name: 'label', shape: productLabel },
|
|
132
|
+
{ name: 'cap', shape: productCap },
|
|
133
|
+
).translate(52, 0, 0);
|
|
134
|
+
|
|
135
|
+
return [guided, productSkinComparison];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SDF circular array — fogleman-style folded-domain knurling.
|
|
2
|
+
// circularArray evaluates the source groove twice no matter how many copies it creates.
|
|
3
|
+
|
|
4
|
+
const body = sdf.cylinder(42, 11);
|
|
5
|
+
|
|
6
|
+
const rightHandGroove = sdf.box(2.4, 1.2, 48)
|
|
7
|
+
.rotateZ(45)
|
|
8
|
+
.circularArray(32, 11.6)
|
|
9
|
+
.twist(2.2);
|
|
10
|
+
|
|
11
|
+
const leftHandGroove = sdf.box(2.4, 1.2, 48)
|
|
12
|
+
.rotateZ(-45)
|
|
13
|
+
.circularArray(32, 11.6)
|
|
14
|
+
.twist(-2.2);
|
|
15
|
+
|
|
16
|
+
return body
|
|
17
|
+
.subtract(rightHandGroove, leftHandGroove)
|
|
18
|
+
.color('#8da2ad')
|
|
19
|
+
.material({ roughness: 0.38, metalness: 0.18 });
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Native Pattern2D relief on ceramic forms: flutes, bands, and woven bowl texture.
|
|
2
|
+
|
|
3
|
+
scene({
|
|
4
|
+
background: { top: '#fff8f1', bottom: '#d8e4ea' },
|
|
5
|
+
camera: { position: [90, -126, 66], target: [0, 0, 8], fov: 34 },
|
|
6
|
+
environment: { preset: 'studio', intensity: 1.28 },
|
|
7
|
+
lights: [
|
|
8
|
+
{ type: 'ambient', color: '#ffffff', intensity: 0.28 },
|
|
9
|
+
{ type: 'point', position: [54, -72, 90], color: '#fff1d0', intensity: 2.2, distance: 280, decay: 1.12 },
|
|
10
|
+
{ type: 'point', position: [-76, 48, 62], color: '#84d8ff', intensity: 1.15, distance: 240, decay: 1.18 },
|
|
11
|
+
{ type: 'directional', position: [30, -56, 150], color: '#ffffff', intensity: 0.58 },
|
|
12
|
+
],
|
|
13
|
+
postProcessing: {
|
|
14
|
+
toneMappingExposure: 1.12,
|
|
15
|
+
bloom: { intensity: 0.08, threshold: 0.84, radius: 0.38 },
|
|
16
|
+
vignette: { darkness: 0.12, offset: 0.62 },
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const ceramic = (shape, color) =>
|
|
21
|
+
shape.color(color).material({
|
|
22
|
+
roughness: 0.46,
|
|
23
|
+
metalness: 0,
|
|
24
|
+
clearcoat: 0.72,
|
|
25
|
+
clearcoatRoughness: 0.18,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const p = sdf.pattern2d();
|
|
29
|
+
|
|
30
|
+
const flutedPorcelain = p
|
|
31
|
+
.sineWave({ direction: [1, 0], wavelength: 4.6, amplitude: 0.28 })
|
|
32
|
+
.add(p.sineWave({ direction: [0, 1], wavelength: 18, amplitude: 0.08 }))
|
|
33
|
+
.clamp(-0.34, 0.34);
|
|
34
|
+
|
|
35
|
+
const carvedBands = p
|
|
36
|
+
.stripes({ direction: [0, 1], spacing: 7.5, width: 0.9, depth: 0.2 })
|
|
37
|
+
.add(p.sineWave({ direction: [1, 1], wavelength: 9, amplitude: 0.08 }))
|
|
38
|
+
.clamp(-0.27, 0.07);
|
|
39
|
+
|
|
40
|
+
const wovenGlaze = p
|
|
41
|
+
.overUnderWeave({ spacing: 2.45, threadWidth: 1.08, depth: 0.34 })
|
|
42
|
+
.add(p.sineWave({ direction: [1, -1], wavelength: 13, amplitude: 0.055 }))
|
|
43
|
+
.clamp(-0.42, 0.06);
|
|
44
|
+
|
|
45
|
+
const tallVase = ceramic(
|
|
46
|
+
sdf.cylinder(58, 11)
|
|
47
|
+
.shell(1.35)
|
|
48
|
+
.surfaceDisplace(flutedPorcelain, { uv: 'cylinder' })
|
|
49
|
+
.subtract(sdf.cylinder(66, 8.2))
|
|
50
|
+
.translate(-35, 0, 3),
|
|
51
|
+
'#f2efe2',
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const bandedCup = ceramic(
|
|
55
|
+
sdf.cylinder(38, 14)
|
|
56
|
+
.shell(1.25)
|
|
57
|
+
.surfaceDisplace(carvedBands, { uv: 'cylinder' })
|
|
58
|
+
.subtract(sdf.cylinder(46, 10.6))
|
|
59
|
+
.translate(0, 0, -7),
|
|
60
|
+
'#8fb7c7',
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const lowBowl = ceramic(
|
|
64
|
+
sdf.sphere(22)
|
|
65
|
+
.shell(1.4)
|
|
66
|
+
.surfaceDisplace(wovenGlaze)
|
|
67
|
+
.subtract(sdf.box(68, 68, 40).translate(0, 0, 17))
|
|
68
|
+
.translate(37, 0, -8),
|
|
69
|
+
'#c97462',
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const footRings = ceramic(
|
|
73
|
+
sdf
|
|
74
|
+
.torus(10.5, 0.75)
|
|
75
|
+
.translate(-35, 0, -27)
|
|
76
|
+
.union(
|
|
77
|
+
sdf.torus(12.5, 0.72).translate(0, 0, -26),
|
|
78
|
+
sdf.torus(14.5, 0.72).translate(37, 0, -25),
|
|
79
|
+
),
|
|
80
|
+
'#d8c59f',
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return { tallVase, bandedCup, lowBowl, footRings };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Native Pattern2D relief for a tactile grip: diamond tread, metal collars, no JS callbacks.
|
|
2
|
+
|
|
3
|
+
scene({
|
|
4
|
+
background: { top: '#eef4f7', bottom: '#ccd8df' },
|
|
5
|
+
camera: { position: [82, -118, 54], target: [0, 0, 0], fov: 32 },
|
|
6
|
+
environment: { preset: 'studio', intensity: 1.35 },
|
|
7
|
+
lights: [
|
|
8
|
+
{ type: 'ambient', color: '#ffffff', intensity: 0.24 },
|
|
9
|
+
{ type: 'point', position: [56, -78, 78], color: '#ffffff', intensity: 2.1, distance: 260, decay: 1.12 },
|
|
10
|
+
{ type: 'point', position: [-62, 48, 46], color: '#73d8ff', intensity: 1.25, distance: 230, decay: 1.2 },
|
|
11
|
+
{ type: 'directional', position: [36, -52, 130], color: '#fff0cf', intensity: 0.62 },
|
|
12
|
+
],
|
|
13
|
+
postProcessing: {
|
|
14
|
+
toneMappingExposure: 1.08,
|
|
15
|
+
bloom: { intensity: 0.1, threshold: 0.82, radius: 0.36 },
|
|
16
|
+
vignette: { darkness: 0.13, offset: 0.58 },
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const p = sdf.pattern2d();
|
|
21
|
+
|
|
22
|
+
const diamondTread = p
|
|
23
|
+
.stripes({ direction: [1, 1], spacing: 5.2, width: 1.05, depth: 0.42 })
|
|
24
|
+
.max(p.stripes({ direction: [1, -1], spacing: 5.2, width: 1.05, depth: 0.42 }))
|
|
25
|
+
.add(p.sineWave({ direction: [0, 1], wavelength: 19, amplitude: 0.06 }))
|
|
26
|
+
.clamp(-0.54, 0.04);
|
|
27
|
+
|
|
28
|
+
const collarGrooves = p
|
|
29
|
+
.stripes({ direction: [0, 1], spacing: 2.4, width: 0.45, depth: 0.09 })
|
|
30
|
+
.add(p.sineWave({ direction: [1, 0], wavelength: 8, amplitude: 0.018 }))
|
|
31
|
+
.clamp(-0.12, 0.02);
|
|
32
|
+
|
|
33
|
+
const rubber = (shape) =>
|
|
34
|
+
shape.color('#1f2227').material({
|
|
35
|
+
roughness: 0.86,
|
|
36
|
+
metalness: 0.02,
|
|
37
|
+
clearcoat: 0.08,
|
|
38
|
+
clearcoatRoughness: 0.72,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const satinMetal = (shape) =>
|
|
42
|
+
shape.color('#c3cbd4').material({
|
|
43
|
+
roughness: 0.34,
|
|
44
|
+
metalness: 0.78,
|
|
45
|
+
clearcoat: 0.42,
|
|
46
|
+
clearcoatRoughness: 0.18,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const grip = rubber(
|
|
50
|
+
sdf.cylinder(78, 13)
|
|
51
|
+
.shell(1.7)
|
|
52
|
+
.surfaceDisplace(diamondTread, { uv: 'cylinder' })
|
|
53
|
+
.subtract(sdf.cylinder(88, 9.0)),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const core = satinMetal(sdf.cylinder(86, 6.8));
|
|
57
|
+
const leftCollar = satinMetal(
|
|
58
|
+
sdf.torus(13.2, 1.45).surfaceDisplace(collarGrooves, { uv: 'torus' }).translate(0, 0, -39),
|
|
59
|
+
);
|
|
60
|
+
const rightCollar = satinMetal(
|
|
61
|
+
sdf.torus(13.2, 1.45).surfaceDisplace(collarGrooves, { uv: 'torus' }).translate(0, 0, 39),
|
|
62
|
+
);
|
|
63
|
+
const endLips = satinMetal(sdf.box(1.1, 1.1, 5.0).circularArray(44, 15.2));
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
core,
|
|
67
|
+
grip,
|
|
68
|
+
leftCollar,
|
|
69
|
+
rightCollar,
|
|
70
|
+
leftEndKnurl: endLips.translate(0, 0, -41.5),
|
|
71
|
+
rightEndKnurl: endLips.translate(0, 0, 41.5),
|
|
72
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Native Pattern2D relief plus folded circular array accents for an ornamental SDF piece.
|
|
2
|
+
|
|
3
|
+
scene({
|
|
4
|
+
background: { top: '#101420', bottom: '#223242' },
|
|
5
|
+
camera: { position: [74, -104, 58], target: [0, 0, 4], fov: 31 },
|
|
6
|
+
environment: { preset: 'night', intensity: 1.18 },
|
|
7
|
+
lights: [
|
|
8
|
+
{ type: 'ambient', color: '#172030', intensity: 0.18 },
|
|
9
|
+
{ type: 'point', position: [48, -66, 72], color: '#ffd36f', intensity: 2.35, distance: 250, decay: 1.08 },
|
|
10
|
+
{ type: 'point', position: [-52, 48, 58], color: '#58e5ff', intensity: 1.85, distance: 230, decay: 1.14 },
|
|
11
|
+
{ type: 'point', position: [0, 36, 76], color: '#ff7ab8', intensity: 1.15, distance: 220, decay: 1.2 },
|
|
12
|
+
{ type: 'directional', position: [28, -48, 138], color: '#ffffff', intensity: 0.58 },
|
|
13
|
+
],
|
|
14
|
+
fog: { color: '#101420', near: 130, far: 330 },
|
|
15
|
+
postProcessing: {
|
|
16
|
+
toneMappingExposure: 1.32,
|
|
17
|
+
bloom: { intensity: 0.44, threshold: 0.56, radius: 0.56 },
|
|
18
|
+
vignette: { darkness: 0.42, offset: 0.44 },
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const p = sdf.pattern2d();
|
|
23
|
+
|
|
24
|
+
const braidedGold = p
|
|
25
|
+
.overUnderWeave({ spacing: 1.6, threadWidth: 0.72, depth: 0.18 })
|
|
26
|
+
.add(p.sineWave({ direction: [1, 0], wavelength: 7.2, amplitude: 0.035 }))
|
|
27
|
+
.clamp(-0.23, 0.04);
|
|
28
|
+
|
|
29
|
+
const opalSkin = p
|
|
30
|
+
.sineWave({ direction: [1, 0], wavelength: 6, amplitude: 0.18 })
|
|
31
|
+
.add(p.sineWave({ direction: [0, 1], wavelength: 4.2, amplitude: 0.12 }))
|
|
32
|
+
.add(p.stripes({ direction: [1, 1], spacing: 5.5, width: 0.7, depth: 0.08 }))
|
|
33
|
+
.clamp(-0.2, 0.22);
|
|
34
|
+
|
|
35
|
+
const gold = (shape) =>
|
|
36
|
+
shape.color('#e8b95f').material({
|
|
37
|
+
roughness: 0.25,
|
|
38
|
+
metalness: 0.92,
|
|
39
|
+
clearcoat: 0.45,
|
|
40
|
+
clearcoatRoughness: 0.08,
|
|
41
|
+
reflectivity: 0.72,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const opal = (shape) =>
|
|
45
|
+
shape.color('#9be9dd').material({
|
|
46
|
+
roughness: 0.12,
|
|
47
|
+
metalness: 0,
|
|
48
|
+
clearcoat: 1,
|
|
49
|
+
clearcoatRoughness: 0.03,
|
|
50
|
+
opacity: 0.86,
|
|
51
|
+
transmission: 0.22,
|
|
52
|
+
reflectivity: 0.84,
|
|
53
|
+
ior: 1.42,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const braidedBand = gold(sdf.torus(24, 2.9).surfaceDisplace(braidedGold, { uv: 'torus' }));
|
|
57
|
+
const centerStone = opal(sdf.sphere(8.8).surfaceDisplace(opalSkin).translate(0, 0, 0.8));
|
|
58
|
+
const beadHalo = gold(sdf.sphere(1.8).circularArray(32, 31).translate(0, 0, 0.8));
|
|
59
|
+
const northStar = opal(sdf.sphere(3.3).surfaceDisplace(opalSkin).translate(0, 31, 1.1));
|
|
60
|
+
const southStar = opal(sdf.sphere(3.3).surfaceDisplace(opalSkin).translate(0, -31, 1.1));
|
|
61
|
+
|
|
62
|
+
return { braidedBand, centerStone, beadHalo, northStar, southStar };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Native SDF surface relief — user-composed Pattern2D IR lowers to shader + CPU.
|
|
2
|
+
// These raw SDF leaves raymarch directly; call .toShape() only for export.
|
|
3
|
+
|
|
4
|
+
scene({
|
|
5
|
+
background: { top: '#f6fbff', bottom: '#dfe9f3' },
|
|
6
|
+
camera: { position: [92, -128, 72], target: [0, 0, 3], fov: 34 },
|
|
7
|
+
environment: { preset: 'studio', intensity: 1.2 },
|
|
8
|
+
lights: [
|
|
9
|
+
{ type: 'ambient', color: '#ffffff', intensity: 0.22 },
|
|
10
|
+
{ type: 'point', position: [56, -72, 86], color: '#fff0cf', intensity: 2.0, distance: 260, decay: 1.15 },
|
|
11
|
+
{ type: 'point', position: [-70, 52, 64], color: '#79d9ff', intensity: 1.45, distance: 240, decay: 1.2 },
|
|
12
|
+
{ type: 'directional', position: [36, -68, 150], color: '#ffffff', intensity: 0.7 },
|
|
13
|
+
],
|
|
14
|
+
postProcessing: {
|
|
15
|
+
toneMappingExposure: 1.12,
|
|
16
|
+
bloom: { intensity: 0.18, threshold: 0.74, radius: 0.42 },
|
|
17
|
+
vignette: { darkness: 0.18, offset: 0.58 },
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const textile = (shape, color) =>
|
|
22
|
+
shape.color(color).material({
|
|
23
|
+
roughness: 0.72,
|
|
24
|
+
metalness: 0,
|
|
25
|
+
clearcoat: 0.22,
|
|
26
|
+
clearcoatRoughness: 0.58,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const p = sdf.pattern2d();
|
|
30
|
+
const weave = p.overUnderWeave({ spacing: 2.8, threadWidth: 1.2, depth: 0.55 });
|
|
31
|
+
const diagonalRipple = p.sineWave({ direction: [1, 1], wavelength: 11, amplitude: 0.08 });
|
|
32
|
+
const bowlPattern = weave.add(diagonalRipple).clamp(-0.68, 0.08);
|
|
33
|
+
|
|
34
|
+
const bowl = textile(
|
|
35
|
+
sdf.sphere(24)
|
|
36
|
+
.shell(1.8)
|
|
37
|
+
.surfaceDisplace(bowlPattern)
|
|
38
|
+
.subtract(sdf.box(70, 70, 36).translate(0, 0, 20))
|
|
39
|
+
.translate(-46, 0, 0),
|
|
40
|
+
'#d9826b',
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const sleevePattern = p
|
|
44
|
+
.overUnderWeave({ spacing: 2.15, threadWidth: 0.95, depth: 0.45 })
|
|
45
|
+
.add(p.stripes({ direction: [1, 0], spacing: 7, width: 0.7, depth: 0.18 }));
|
|
46
|
+
|
|
47
|
+
const sleeve = textile(
|
|
48
|
+
sdf.cylinder(38, 13)
|
|
49
|
+
.shell(1.4)
|
|
50
|
+
.surfaceDisplace(sleevePattern, { uv: 'cylinder' })
|
|
51
|
+
.subtract(sdf.cylinder(46, 9.8))
|
|
52
|
+
.translate(0, 0, 0),
|
|
53
|
+
'#6fa6a3',
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const ringPattern = p
|
|
57
|
+
.overUnderWeave({ spacing: 1.75, threadWidth: 0.78, depth: 0.28 })
|
|
58
|
+
.add(p.sineWave({ direction: [0, 1], wavelength: 5.4, amplitude: 0.05 }));
|
|
59
|
+
|
|
60
|
+
const ring = textile(
|
|
61
|
+
sdf.torus(18, 3.4)
|
|
62
|
+
.surfaceDisplace(ringPattern, { uv: 'torus' })
|
|
63
|
+
.translate(46, 0, 0),
|
|
64
|
+
'#c6a15b',
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return { bowl, sleeve, ring };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Sector gear demo: partial tooth window composed with a visual/structural body.
|
|
2
|
+
|
|
3
|
+
const moduleSize = Param.number("Module", 1.2, { min: 0.8, max: 2.5, step: 0.05, unit: "mm" });
|
|
4
|
+
const teethOnFullCircle = Param.number("Pitch Teeth", 36, { min: 24, max: 72, integer: true });
|
|
5
|
+
const toothCount = Param.number("Active Teeth", 11, { min: 2, max: 24, integer: true });
|
|
6
|
+
const firstTooth = Param.number("First Tooth", 2, { min: 0, max: 35, integer: true });
|
|
7
|
+
const faceWidth = Param.number("Face Width", 8, { min: 4, max: 16, unit: "mm" });
|
|
8
|
+
|
|
9
|
+
const pitchRadius = (moduleSize * teethOnFullCircle) / 2;
|
|
10
|
+
const rootRadius = pitchRadius - moduleSize * 1.25;
|
|
11
|
+
const rimWidth = Math.max(2.4, moduleSize * 2);
|
|
12
|
+
const hubDiameter = Math.max(8, moduleSize * 8);
|
|
13
|
+
|
|
14
|
+
const body = lib.gearBodies.spoked({
|
|
15
|
+
outerRadius: rootRadius,
|
|
16
|
+
rimWidth,
|
|
17
|
+
hubDiameter,
|
|
18
|
+
boreDiameter: 5,
|
|
19
|
+
spokeCount: 5,
|
|
20
|
+
spokeWidth: Math.max(2, moduleSize * 1.8),
|
|
21
|
+
faceWidth,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const sector = lib.sectorGear({
|
|
25
|
+
module: moduleSize,
|
|
26
|
+
teethOnFullCircle,
|
|
27
|
+
firstTooth: Math.min(firstTooth, teethOnFullCircle - 1),
|
|
28
|
+
toothCount: Math.min(toothCount, teethOnFullCircle),
|
|
29
|
+
pressureAngleDeg: 20,
|
|
30
|
+
faceWidth,
|
|
31
|
+
body,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return [{ name: "Sector Gear", shape: sector.color("#d5a15f") }];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgecad",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "Code-first parametric CAD for JavaScript/TypeScript, in the browser and CLI.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"type": "module",
|
|
@@ -101,7 +101,25 @@
|
|
|
101
101
|
"beta:shell": "bash scripts/beta.sh shell",
|
|
102
102
|
"beta:db": "bash scripts/beta.sh db",
|
|
103
103
|
"beta:refresh": "bash scripts/beta.sh refresh",
|
|
104
|
-
"beta:local": "bash scripts/beta
|
|
104
|
+
"beta:local": "bash scripts/beta.sh local",
|
|
105
|
+
"beta:help": "bash scripts/beta.sh help",
|
|
106
|
+
"prod:setup": "bash scripts/prod.sh setup",
|
|
107
|
+
"prod:deploy": "bash scripts/prod.sh deploy",
|
|
108
|
+
"prod:smoke": "bash scripts/prod.sh smoke",
|
|
109
|
+
"prod:deploy:backend": "bash scripts/prod.sh deploy-backend",
|
|
110
|
+
"prod:deploy:all": "bash scripts/prod.sh deploy-all",
|
|
111
|
+
"prod:rollback": "bash scripts/prod.sh rollback",
|
|
112
|
+
"prod:rollback:backend": "bash scripts/prod.sh rollback-backend",
|
|
113
|
+
"prod:logs": "bash scripts/prod.sh logs",
|
|
114
|
+
"prod:logs:backend": "bash scripts/prod.sh logs-backend",
|
|
115
|
+
"prod:open": "bash scripts/prod.sh open",
|
|
116
|
+
"prod:shell": "bash scripts/prod.sh shell",
|
|
117
|
+
"prod:shell:backend": "bash scripts/prod.sh shell-backend",
|
|
118
|
+
"prod:db": "bash scripts/prod.sh db",
|
|
119
|
+
"prod:health": "bash scripts/prod/health.sh",
|
|
120
|
+
"prod:errors": "bash scripts/prod/errors.sh",
|
|
121
|
+
"prod:promote-beta": "fish scripts/promote-beta-to-prod.fish",
|
|
122
|
+
"prod:help": "bash scripts/prod.sh help",
|
|
105
123
|
"gen:types": "node scripts/gen-forge-types.mjs",
|
|
106
124
|
"gen:docs": "node scripts/gen-api-docs.mjs",
|
|
107
125
|
"gen:cli-docs": "node scripts/gen-cli-docs.mjs",
|