threejs-awesome-graphics-agent-skills 0.1.2 → 0.2.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.
Files changed (30) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +4 -39
  3. package/package.json +6 -2
  4. package/skills/threejs-procedural-materials/SKILL.md +8 -1
  5. package/skills/threejs-procedural-materials/agents/openai.yaml +2 -2
  6. package/skills/threejs-procedural-materials/examples/lava-flow-surface/lava-surface.js +305 -0
  7. package/skills/threejs-procedural-vegetation/SKILL.md +9 -2
  8. package/skills/threejs-procedural-vegetation/agents/openai.yaml +2 -2
  9. package/skills/threejs-procedural-vegetation/assets/stylized-meadow-grass/grass-blades-up.glb +0 -0
  10. package/skills/threejs-procedural-vegetation/assets/stylized-meadow-grass/path.webp +0 -0
  11. package/skills/threejs-procedural-vegetation/assets/stylized-meadow-grass/perlin.webp +0 -0
  12. package/skills/threejs-procedural-vegetation/examples/stylized-meadow-grass/grass-system.js +449 -0
  13. package/skills/threejs-skill-router/SKILL.md +4 -4
  14. package/skills/threejs-spectral-ocean/SKILL.md +16 -2
  15. package/skills/threejs-spectral-ocean/agents/openai.yaml +2 -2
  16. package/skills/threejs-spectral-ocean/assets/stylized-above-below-ocean/foam.webp +0 -0
  17. package/skills/threejs-spectral-ocean/assets/stylized-above-below-ocean/sand.webp +0 -0
  18. package/skills/threejs-spectral-ocean/examples/hybrid-clear-water-ocean/hybrid-ocean-material.js +666 -0
  19. package/skills/threejs-spectral-ocean/examples/stylized-above-below-ocean/stylized-ocean-material.js +593 -0
  20. package/skills/threejs-water-optics/SKILL.md +12 -3
  21. package/skills/threejs-water-optics/agents/openai.yaml +2 -2
  22. package/skills/threejs-water-optics/assets/interactive-pool-volume/tiles.jpg +0 -0
  23. package/skills/threejs-water-optics/assets/interactive-pool-volume/xneg.jpg +0 -0
  24. package/skills/threejs-water-optics/assets/interactive-pool-volume/xpos.jpg +0 -0
  25. package/skills/threejs-water-optics/assets/interactive-pool-volume/ypos.jpg +0 -0
  26. package/skills/threejs-water-optics/assets/interactive-pool-volume/zneg.jpg +0 -0
  27. package/skills/threejs-water-optics/assets/interactive-pool-volume/zpos.jpg +0 -0
  28. package/skills/threejs-water-optics/examples/interactive-pool-volume/water-volume-system.js +859 -0
  29. package/source_materials/THIRD_PARTY_NOTICES.md +34 -0
  30. package/source_materials/trace-manifest.json +404 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threejs-awesome-graphics-agent-skills",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Expert agent skills for creating exceptional Three.js graphics.",
5
5
  "author": {
6
6
  "name": "Scott"
package/README.md CHANGED
@@ -32,13 +32,13 @@ Every graphics system is expected to expose:
32
32
  | `threejs-camera-direction` | Authored lenses and shots, chase/side/orbit rigs, body-relative frames, handoffs, pointer look, floating origins. |
33
33
  | `threejs-procedural-animation` | Analytic timelines, gravity turns, staging, rotating-frame docking, springs, quaternion alignment, debris motion. |
34
34
  | `threejs-procedural-fields` | Shared scalar/vector fields, frequency bands, domain warping, causal masks, procedural normals. |
35
- | `threejs-procedural-materials` | Atlas filtering, specular AA, planetary materials, terrain wetness, frame PBR, per-instance dissolve. |
35
+ | `threejs-procedural-materials` | Atlas filtering, specular AA, planetary materials, terrain wetness, lava/emissive surfaces, frame PBR, per-instance dissolve. |
36
36
  | `threejs-procedural-geometry` | Sculpted frame rails, branch rings, semantic mesh writers, UV density, material groups. |
37
- | `threejs-procedural-vegetation` | Growth hierarchies, branch-ring geometry, stratified children, foliage normals, wind. |
37
+ | `threejs-procedural-vegetation` | Growth hierarchies, stylized grass, branch-ring geometry, stratified children, foliage normals, rooted wind. |
38
38
  | `threejs-procedural-architecture` | Massing and façade grammars, exposed-edge analysis, modules, material-slot compilation. |
39
39
  | `threejs-procedural-planets` | Spherical terrain, ridges, craters, biomes, procedural normals, altitude filtering. |
40
- | `threejs-spectral-ocean` | Validated FFT synthesis, spectral cascades, choppy derivatives, Jacobian foam, ocean shading. |
41
- | `threejs-water-optics` | Shared analytic waves/normals, heuristic refraction, fallback absorption, reflection, crest foam. |
40
+ | `threejs-spectral-ocean` | Validated FFT synthesis, hybrid FFT/Gerstner water, stylized above/below ocean optics, spectral cascades, choppy derivatives, Jacobian foam, ocean shading. |
41
+ | `threejs-water-optics` | Shared analytic waves/normals, bounded pool heightfields, object ripples, caustics, refraction, absorption, reflection. |
42
42
  | `threejs-atmosphere-aerial-perspective` | Shared Rayleigh/Mie atmosphere, sky, shell/post handoff, depth-based scattering. |
43
43
  | `threejs-volumetric-clouds` | Weather-shaped density, bounded raymarching, cloud lighting, history, cloud shadows. |
44
44
  | `threejs-raymarched-space-effects` | Curved-ray integration, black holes, accretion disks, wormholes, bounded quality. |
@@ -135,41 +135,6 @@ controls, pause/time controls, debug-mode routing, standalone launch, runtime
135
135
  metrics, and canvas capture. It is repository tooling and is not installed as
136
136
  an agent skill.
137
137
 
138
- Current accepted inspection surfaces:
139
-
140
- - [Atmosphere and aerial perspective](http://127.0.0.1:4173/?example=threejs-atmosphere-aerial-perspective%2Flut-aerial-perspective)
141
- — precomputed sky radiance, sun transmittance, and depth-aware segment
142
- scattering;
143
- - [Sculpted gallery frame](http://127.0.0.1:4173/?example=threejs-procedural-geometry%2Fsculpted-gallery-frame)
144
- — profile-swept mesh, authored frame PBR, grazing lights, shadows, and
145
- selective bloom;
146
- - [Ash growth system](http://127.0.0.1:4173/?example=threejs-procedural-vegetation%2Fstructured-ash-growth)
147
- — species-specific hierarchy, branch geometry, foliage, wind, and meadow;
148
- - [Curved-ray accretion volume](http://127.0.0.1:4173/?example=threejs-raymarched-space-effects%2Fcurved-ray-accretion-volume)
149
- — bounded ray steering, accretion density, transmittance, and bent
150
- environment lookup;
151
- - [Spectral cascade ocean](http://127.0.0.1:4173/?example=threejs-spectral-ocean%2Fspectral-cascade-ocean)
152
- — directional spectra, staged inverse FFT, choppy displacement, and
153
- persistent Jacobian foam;
154
- - [Procedural planet surface](http://127.0.0.1:4173/?example=threejs-procedural-planets%2Fprocedural-planet-surface)
155
- — coupled displacement, geological fields, biome masks, water, and
156
- altitude-filtered material detail;
157
- - [Authored financial tower](http://127.0.0.1:4173/?example=threejs-procedural-architecture%2Fauthored-financial-tower)
158
- — semantic massing, façade grammar, grouped mesh emission, and cached
159
- clipmap shadows;
160
- - [Analytic wave optics](http://127.0.0.1:4173/?example=threejs-water-optics%2Fanalytic-wave-optics)
161
- — shared displaced waves and normals, filtered microstructure, Fresnel,
162
- refraction, absorption, and crest response;
163
- - [Weather volume clouds](http://127.0.0.1:4173/?example=threejs-volumetric-clouds%2Fweather-volume-clouds)
164
- — packed weather channels, profile-shaped density, bounded integration,
165
- directional lighting, and temporal reconstruction;
166
- - [Reentry plasma](http://127.0.0.1:4173/?example=threejs-procedural-vfx%2Freentry-plasma)
167
- — closed layered wake shells, flow deformation, advected filaments, and
168
- additive thermal emission;
169
- - [Touch-history frost](http://127.0.0.1:4173/?example=threejs-temporal-surfaces%2Ftouch-history-frost)
170
- — persistent interaction history, static crystalline fields, reduced blur,
171
- and two-scale refraction.
172
-
173
138
  Generate deterministic captures and a contact sheet:
174
139
 
175
140
  ```sh
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threejs-awesome-graphics-agent-skills",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Expert agent skills for creating exceptional Three.js graphics.",
5
5
  "license": "MIT",
6
6
  "author": "Scott",
@@ -31,6 +31,9 @@
31
31
  "bin/",
32
32
  "skills/",
33
33
  "LICENSE",
34
+ "source_materials/THIRD_PARTY_NOTICES.md",
35
+ "source_materials/trace-manifest.json",
36
+ "!source_materials/README.md",
34
37
  "README.md"
35
38
  ],
36
39
  "engines": {
@@ -41,7 +44,7 @@
41
44
  },
42
45
  "scripts": {
43
46
  "validate": "node scripts/validate-pack.mjs",
44
- "test": "npm run validate && npm run test:routing && npm run test:references && npm run test:installer && npm run test:gallery",
47
+ "test": "npm run validate && npm run test:routing && npm run test:references && npm run test:installer && npm run test:assets && npm run test:gallery",
45
48
  "dev:examples": "node dev/example-gallery/server.mjs --open",
46
49
  "dev:examples:no-open": "node dev/example-gallery/server.mjs",
47
50
  "dev:examples:fixture": "node dev/example-gallery/server.mjs --open --include-fixtures",
@@ -49,6 +52,7 @@
49
52
  "test:references": "node scripts/test-reference-examples.mjs",
50
53
  "test:routing": "node scripts/test-agent-routing.mjs",
51
54
  "test:installer": "node scripts/test-installer.mjs",
55
+ "test:assets": "node scripts/test-example-asset-origins.mjs",
52
56
  "test:gallery": "node scripts/test-example-gallery.mjs",
53
57
  "check:freshness": "node scripts/check-three-freshness.mjs",
54
58
  "test:all": "npm test && npm run check:freshness",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: threejs-procedural-materials
3
- description: Author production procedural materials in Three.js. Use for atlas filtering and specular AA, planet-space material fields, terrain wetness, per-instance dissolve, authored PBR identities, derivative normals, and custom direct-light shadow modulation.
3
+ description: Author production procedural materials in Three.js. Use for atlas filtering and specular AA, planet-space material fields, terrain wetness, lava and hot emissive procedural surfaces, raymarched material fields, per-instance dissolve, authored PBR identities, derivative normals, and custom direct-light shadow modulation.
4
4
  ---
5
5
 
6
6
  # Procedural Materials
@@ -38,6 +38,11 @@ Read the
38
38
  for coupled reflection, refraction, absorption, filtered microstructure,
39
39
  resolved crest response, and their diagnostic channels.
40
40
 
41
+ Read the
42
+ [lava flow surface material](examples/lava-flow-surface/lava-surface.js)
43
+ for raymarched procedural height fields whose normals, rock/lava identity,
44
+ emission, glow, embers, fog, and grain are coupled to one material cause stack.
45
+
41
46
  ## Required controls
42
47
 
43
48
  - real or perceptual texture scale;
@@ -47,6 +52,8 @@ resolved crest response, and their diagnostic channels.
47
52
  - distance/derivative filtering;
48
53
  - specular antialiasing;
49
54
  - channel and mask debug modes.
55
+ - emissive-material debug modes when the material owns glow or volumetric
56
+ accumulation.
50
57
 
51
58
  ## Failure conditions
52
59
 
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "Three.js Procedural Materials"
3
- short_description: "Author coherent filtered procedural PBR surfaces"
4
- default_prompt: "Use $threejs-procedural-materials to build a causal, multi-channel PBR surface with shared fields, derivative filtering, stable normals, and explicit channel diagnostics."
3
+ short_description: "Author coherent procedural PBR and emissive surfaces"
4
+ default_prompt: "Use $threejs-procedural-materials to build a causal procedural surface, including PBR or lava-like emissive materials, with shared fields, derivative normals, filtering, and explicit diagnostics."
@@ -0,0 +1,305 @@
1
+ import * as THREE from "three";
2
+
3
+ export const lavaFlowDebugModes = new Map([
4
+ ["final", 0],
5
+ ["height", 1],
6
+ ["normals", 2],
7
+ ["emission", 3],
8
+ ]);
9
+
10
+ export function createLavaFlowMaterial({
11
+ cameraSpeed = 0.1,
12
+ flowSpeed = 0.1,
13
+ ridgeFrequency = 0.0,
14
+ pulseSpeed = 0.05,
15
+ amplitude = 0.4,
16
+ octaves = 7,
17
+ emberCount = 80,
18
+ filmNoise = 0.015,
19
+ } = {}) {
20
+ return new THREE.ShaderMaterial({
21
+ uniforms: {
22
+ uTime: { value: 0 },
23
+ uResolution: { value: new THREE.Vector2(1, 1) },
24
+ uCameraPosition: { value: new THREE.Vector3(0, 0.2, 0) },
25
+ uCameraRight: { value: new THREE.Vector3(1, 0, 0) },
26
+ uCameraUp: { value: new THREE.Vector3(0, 1, 0) },
27
+ uCameraForward: { value: new THREE.Vector3(0, -0.35, 1).normalize() },
28
+ uVerticalTan: { value: Math.tan(THREE.MathUtils.degToRad(54) * 0.5) },
29
+ uDebugMode: { value: 0 },
30
+ uCameraSpeed: { value: cameraSpeed },
31
+ uFlowSpeed: { value: flowSpeed },
32
+ uRidgeFrequency: { value: ridgeFrequency },
33
+ uPulseSpeed: { value: pulseSpeed },
34
+ uAmplitude: { value: amplitude },
35
+ uOctaves: { value: octaves },
36
+ uEmberCount: { value: emberCount },
37
+ uFilmNoise: { value: filmNoise },
38
+ uLavaHot: { value: new THREE.Color(0xff1402) },
39
+ uLavaCool: { value: new THREE.Color(0xb20000) },
40
+ uEmberColor: { value: new THREE.Color(0xff5511) },
41
+ },
42
+ depthTest: false,
43
+ depthWrite: false,
44
+ vertexShader: `
45
+ varying vec2 vUv;
46
+
47
+ void main() {
48
+ vUv = uv;
49
+ gl_Position = vec4(position.xy, 0.0, 1.0);
50
+ }
51
+ `,
52
+ fragmentShader: `
53
+ precision highp float;
54
+
55
+ uniform float uTime;
56
+ uniform vec2 uResolution;
57
+ uniform vec3 uCameraPosition;
58
+ uniform vec3 uCameraRight;
59
+ uniform vec3 uCameraUp;
60
+ uniform vec3 uCameraForward;
61
+ uniform float uVerticalTan;
62
+ uniform int uDebugMode;
63
+ uniform float uCameraSpeed;
64
+ uniform float uFlowSpeed;
65
+ uniform float uRidgeFrequency;
66
+ uniform float uPulseSpeed;
67
+ uniform float uAmplitude;
68
+ uniform float uOctaves;
69
+ uniform float uEmberCount;
70
+ uniform float uFilmNoise;
71
+ uniform vec3 uLavaHot;
72
+ uniform vec3 uLavaCool;
73
+ uniform vec3 uEmberColor;
74
+ varying vec2 vUv;
75
+
76
+ float hash21(vec2 p) {
77
+ vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
78
+ p3 += dot(p3, p3.yzx + 33.33);
79
+ return fract((p3.x + p3.y) * p3.z);
80
+ }
81
+
82
+ vec3 hash31(float p) {
83
+ vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973));
84
+ p3 += dot(p3, p3.yzx + 33.33);
85
+ return fract((p3.xxy + p3.yzz) * p3.zyx);
86
+ }
87
+
88
+ float valueNoise(vec2 p) {
89
+ vec2 i = floor(p);
90
+ vec2 f = fract(p);
91
+ vec2 u = f * f * (3.0 - 2.0 * f);
92
+ return mix(
93
+ mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x),
94
+ mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0)), u.x),
95
+ u.y
96
+ );
97
+ }
98
+
99
+ float ridgeNoise(vec2 p, float octaveLimit) {
100
+ float h = 0.0;
101
+ float amp = 0.58;
102
+ mat2 rotation = mat2(0.8, -0.6, 0.6, 0.8);
103
+ for (int i = 0; i < 10; i++) {
104
+ if (float(i) >= octaveLimit) break;
105
+ float n = valueNoise(p);
106
+ h += amp * (1.0 - abs(n * 2.0 - 1.0));
107
+ p = rotation * p * 2.03;
108
+ amp *= 0.52;
109
+ }
110
+ return h;
111
+ }
112
+
113
+ float fbmHeight(vec2 p, float octaveLimit) {
114
+ float h = 0.0;
115
+ float amp = 0.8;
116
+ mat2 rotation = mat2(0.8, -0.6, 0.6, 0.8);
117
+ for (int i = 0; i < 10; i++) {
118
+ if (float(i) >= octaveLimit) break;
119
+ h += amp * valueNoise(p);
120
+ p = rotation * p * 2.1;
121
+ amp *= 0.5;
122
+ }
123
+ return h;
124
+ }
125
+
126
+ vec2 advectedDomain(vec2 p) {
127
+ p += vec2(1.0, 1.5) * uTime * uFlowSpeed;
128
+ vec2 curl = vec2(
129
+ sin(p.y * uRidgeFrequency + uTime * 0.42),
130
+ cos(p.x * uRidgeFrequency + uTime * 0.31)
131
+ ) * 0.2;
132
+ return p + curl;
133
+ }
134
+
135
+ float terrainHeight(vec2 p) {
136
+ float pulse = uAmplitude + sin(uTime * uPulseSpeed) * 0.06;
137
+ vec2 domain = advectedDomain(p);
138
+ float h = fbmHeight(domain, uOctaves);
139
+ return -0.9 + h * pulse;
140
+ }
141
+
142
+ float mapSurface(vec3 p) {
143
+ return (p.y - terrainHeight(p.xz)) * 0.52;
144
+ }
145
+
146
+ vec3 surfaceNormal(vec3 p) {
147
+ vec2 e = vec2(0.012, 0.0);
148
+ return normalize(vec3(
149
+ mapSurface(p + e.xyy) - mapSurface(p - e.xyy),
150
+ mapSurface(p + e.yxy) - mapSurface(p - e.yxy),
151
+ mapSurface(p + e.yyx) - mapSurface(p - e.yyx)
152
+ ));
153
+ }
154
+
155
+ float lavaMask(vec3 p) {
156
+ return clamp(1.0 - smoothstep(-0.7, -0.3, p.y), 0.0, 1.0);
157
+ }
158
+
159
+ float emberField(vec3 ro, vec3 rd, float surfaceT) {
160
+ float accum = 0.0;
161
+ for (float i = 0.0; i < 150.0; i++) {
162
+ if (i >= uEmberCount) break;
163
+ vec3 seed = hash31(i + 17.13);
164
+ float speed = 0.08 + seed.x * 0.13;
165
+ float life = fract(uTime * speed + seed.y);
166
+ vec3 ember = vec3(
167
+ (seed.x - 0.5) * 6.2,
168
+ mix(-0.86 + seed.z * 0.24, 0.85 + seed.x, pow(life, 1.35)),
169
+ ro.z + (seed.y - 0.5) * 5.2 + 3.2
170
+ );
171
+ float drift = uTime * (0.8 + seed.x * 0.45);
172
+ ember.x += (sin(drift * 2.1 + seed.z * 10.0) * 0.34 +
173
+ cos(drift * 4.7 + seed.y * 5.0) * 0.11) * life;
174
+ ember.z += (cos(drift * 2.4 + seed.x * 8.0) * 0.32 +
175
+ sin(drift * 5.2 + seed.z * 6.0) * 0.1) * life;
176
+
177
+ vec3 toEmber = ember - ro;
178
+ float projected = dot(toEmber, rd);
179
+ if (projected <= 0.0 || projected >= surfaceT) continue;
180
+ float distanceToRay = length(ro + rd * projected - ember);
181
+ float core = smoothstep(0.017, 0.001, distanceToRay);
182
+ float halo = 0.0000025 / (distanceToRay * distanceToRay + 0.0000015);
183
+ float fade =
184
+ smoothstep(0.0, 0.12, life) *
185
+ smoothstep(1.0, 0.68, life);
186
+ accum += (core * 1.1 + halo) * fade * (0.45 + seed.z * 0.7);
187
+ }
188
+ return accum;
189
+ }
190
+
191
+ void main() {
192
+ vec2 uv = (gl_FragCoord.xy - 0.5 * uResolution.xy) / uResolution.y;
193
+ vec3 ro = uCameraPosition + uCameraForward * uTime * uCameraSpeed;
194
+ vec3 rd = normalize(
195
+ uCameraForward +
196
+ uCameraRight * uv.x * 2.0 * uVerticalTan +
197
+ uCameraUp * uv.y * 2.0 * uVerticalTan
198
+ );
199
+
200
+ float t = 0.0;
201
+ float maxDistance = 15.0;
202
+ float glow = 0.0;
203
+ vec3 p = ro;
204
+ for (int i = 0; i < 84; i++) {
205
+ p = ro + rd * t;
206
+ float d = mapSurface(p);
207
+ if (d < 0.004 || t > maxDistance) break;
208
+ t += d;
209
+ float heat = smoothstep(-0.18, -0.86, p.y);
210
+ glow += exp(-d * 6.2) * heat * 0.055;
211
+ }
212
+
213
+ float horizonBand = exp(-abs(uv.y - 0.02) * 7.0);
214
+ vec3 background = mix(
215
+ vec3(0.00005, 0.00002, 0.00008),
216
+ vec3(0.16, 0.028, 0.015),
217
+ horizonBand
218
+ );
219
+ vec3 color = background;
220
+ float emissionMask = 0.0;
221
+ vec3 normal = vec3(0.0, 1.0, 0.0);
222
+ if (t < maxDistance) {
223
+ normal = surfaceNormal(p);
224
+ vec3 lightDirection = normalize(vec3(0.42, 0.92, -0.18));
225
+ float diffuse = max(dot(normal, lightDirection), 0.0);
226
+ float specular = pow(max(dot(reflect(-lightDirection, normal), -rd), 0.0), 12.0);
227
+ float ash = ridgeNoise(p.xz * 0.9 + vec2(3.0, -8.0), 4.0);
228
+ vec3 rock = mix(vec3(0.028, 0.018, 0.018), vec3(0.12, 0.09, 0.10), ash) *
229
+ (0.24 + diffuse * 0.62) +
230
+ vec3(0.12, 0.10, 0.12) * specular;
231
+ emissionMask = lavaMask(p);
232
+ float rockMask = smoothstep(-0.7, -0.3, p.y);
233
+ vec3 lava = mix(uLavaHot * 1.7, uLavaCool, smoothstep(-0.9, -0.6, p.y));
234
+ color = mix(lava, rock, rockMask);
235
+ }
236
+
237
+ float embers = emberField(ro, rd, min(t, maxDistance));
238
+ color += vec3(1.05, 0.11, 0.025) * glow;
239
+ color += uEmberColor * embers * 1.85;
240
+
241
+ float distanceFog = 1.0 - exp(-0.04 * min(t, maxDistance) * min(t, maxDistance));
242
+ float lowMist = t < maxDistance ? smoothstep(-0.25, -1.05, p.y) * 0.22 : 0.0;
243
+ vec3 fogColor = mix(
244
+ vec3(0.005, 0.002, 0.01),
245
+ vec3(0.44, 0.055, 0.02),
246
+ horizonBand
247
+ );
248
+ color = mix(color, fogColor, clamp(distanceFog + lowMist, 0.0, 0.82));
249
+
250
+ if (uDebugMode == 1) {
251
+ float heightValue = t < maxDistance ? clamp((p.y + 1.0) * 0.72, 0.0, 1.0) : 0.0;
252
+ color = mix(vec3(0.02, 0.0, 0.04), vec3(1.0, 0.18, 0.02), heightValue);
253
+ } else if (uDebugMode == 2) {
254
+ color = normal * 0.5 + 0.5;
255
+ } else if (uDebugMode == 3) {
256
+ color = vec3(glow * 1.7, emissionMask, embers * 0.08);
257
+ }
258
+
259
+ color *= 1.0 - 0.42 * length(uv);
260
+ color = pow(max(color, 0.0), vec3(0.4545));
261
+ float grain = hash21(gl_FragCoord.xy + vec2(fract(uTime * 0.123), fract(uTime * 0.321)) * 997.0);
262
+ color += (grain - 0.5) * uFilmNoise;
263
+ gl_FragColor = vec4(color, 1.0);
264
+ }
265
+ `,
266
+ });
267
+ }
268
+
269
+ export function createLavaFlowSurface(options = {}) {
270
+ const surface = new THREE.Mesh(
271
+ new THREE.PlaneGeometry(2, 2),
272
+ createLavaFlowMaterial(options),
273
+ );
274
+ surface.frustumCulled = false;
275
+ return surface;
276
+ }
277
+
278
+ const cameraForward = new THREE.Vector3();
279
+ const cameraRight = new THREE.Vector3();
280
+ const cameraUp = new THREE.Vector3();
281
+
282
+ export function updateLavaFlowMaterial(material, {
283
+ elapsed,
284
+ width,
285
+ height,
286
+ camera,
287
+ debugMode = "final",
288
+ }) {
289
+ material.uniforms.uTime.value = elapsed;
290
+ material.uniforms.uResolution.value.set(width, height);
291
+ material.uniforms.uDebugMode.value =
292
+ lavaFlowDebugModes.get(debugMode) ?? 0;
293
+ if (camera) {
294
+ camera.getWorldDirection(cameraForward);
295
+ const elements = camera.matrixWorld.elements;
296
+ cameraRight.set(elements[0], elements[1], elements[2]).normalize();
297
+ cameraUp.set(elements[4], elements[5], elements[6]).normalize();
298
+ material.uniforms.uCameraPosition.value.copy(camera.position);
299
+ material.uniforms.uCameraRight.value.copy(cameraRight);
300
+ material.uniforms.uCameraUp.value.copy(cameraUp);
301
+ material.uniforms.uCameraForward.value.copy(cameraForward);
302
+ material.uniforms.uVerticalTan.value =
303
+ Math.tan(THREE.MathUtils.degToRad(camera.fov ?? 54) * 0.5);
304
+ }
305
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: threejs-procedural-vegetation
3
- description: Generate authored procedural trees and vegetation in Three.js. Use for trunks, recursive branches, roots, canopies, leaf cards, species presets, growth forces, trellises, deterministic variation, and wind deformation.
3
+ description: Generate authored procedural trees, grass, and vegetation in Three.js. Use for stylized meadow grass, trunks, recursive branches, roots, canopies, leaf cards, species presets, growth forces, trellises, deterministic variation, rooted blade/leaf wind, and wind deformation.
4
4
  ---
5
5
 
6
6
  # Procedural Vegetation
@@ -28,6 +28,13 @@ Read the [Ash Growth System implementation](examples/structured-ash-growth/tree-
28
28
  with its [authored preset](examples/structured-ash-growth/ash-preset.js) for a
29
29
  contract-accurate implementation and its diagnostic attributes.
30
30
 
31
+ Read the
32
+ [stylized meadow grass implementation](examples/stylized-meadow-grass/grass-system.js)
33
+ for authored blade-cluster geometry with a procedural fallback, image-driven
34
+ path masking, per-instance origin/facing attributes, circular-arc rooted wind,
35
+ gust fronts, tip flutter, color clumps, macro variation, translucency, and rim
36
+ diagnostics.
37
+
31
38
  ## Visual failure conditions
32
39
 
33
40
  - branches form visible helices;
@@ -43,4 +50,4 @@ contract-accurate implementation and its diagnostic attributes.
43
50
 
44
51
  Use `$threejs-procedural-geometry` for generic branch-ring emission without a
45
52
  growth model. This skill owns species tables, topology, child placement,
46
- foliage, roots, and hierarchical wind.
53
+ foliage, grass fields, roots, and hierarchical/rooted wind.
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "Three.js Procedural Vegetation"
3
- short_description: "Generate trees, foliage, and organic growth"
4
- default_prompt: "Use $threejs-procedural-vegetation to build this plant as a deterministic growth hierarchy."
3
+ short_description: "Generate trees, grass, foliage, and organic growth"
4
+ default_prompt: "Use $threejs-procedural-vegetation to build deterministic plant growth, authored foliage, or rooted stylized grass with coherent wind and diagnostics."