@genex-ai/cli-demo 0.6.1 → 0.7.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 (45) hide show
  1. package/dist/index.js +54 -15
  2. package/package.json +1 -1
  3. package/templates/skills/genex-threejs-atmosphere-aerial-perspective/SKILL.md +30 -18
  4. package/templates/skills/genex-threejs-atmosphere-aerial-perspective/references/atmosphere.md +204 -20
  5. package/templates/skills/genex-threejs-bloom/SKILL.md +29 -18
  6. package/templates/skills/genex-threejs-bloom/references/bloom.md +176 -20
  7. package/templates/skills/genex-threejs-camera-direction/SKILL.md +38 -26
  8. package/templates/skills/genex-threejs-camera-direction/references/camera-rigs.md +359 -27
  9. package/templates/skills/genex-threejs-exposure-color-grading/SKILL.md +27 -18
  10. package/templates/skills/genex-threejs-exposure-color-grading/references/exposure-grading.md +196 -21
  11. package/templates/skills/genex-threejs-image-pipeline/SKILL.md +38 -17
  12. package/templates/skills/genex-threejs-image-pipeline/references/image-pipeline.md +185 -29
  13. package/templates/skills/genex-threejs-procedural-animation/SKILL.md +34 -21
  14. package/templates/skills/genex-threejs-procedural-animation/references/procedural-motion.md +353 -24
  15. package/templates/skills/genex-threejs-procedural-architecture/SKILL.md +36 -17
  16. package/templates/skills/genex-threejs-procedural-architecture/references/architecture-systems.md +500 -22
  17. package/templates/skills/genex-threejs-procedural-fields/SKILL.md +59 -24
  18. package/templates/skills/genex-threejs-procedural-fields/references/field-systems.md +222 -25
  19. package/templates/skills/genex-threejs-procedural-geometry/SKILL.md +34 -20
  20. package/templates/skills/genex-threejs-procedural-geometry/references/mesh-systems.md +192 -26
  21. package/templates/skills/genex-threejs-procedural-materials/SKILL.md +55 -18
  22. package/templates/skills/genex-threejs-procedural-materials/references/material-systems.md +189 -22
  23. package/templates/skills/genex-threejs-procedural-planets/SKILL.md +36 -18
  24. package/templates/skills/genex-threejs-procedural-planets/references/planet-systems.md +489 -21
  25. package/templates/skills/genex-threejs-procedural-vegetation/SKILL.md +35 -25
  26. package/templates/skills/genex-threejs-procedural-vegetation/references/vegetation-systems.md +304 -27
  27. package/templates/skills/genex-threejs-procedural-vfx/SKILL.md +26 -18
  28. package/templates/skills/genex-threejs-procedural-vfx/references/vfx-systems.md +208 -20
  29. package/templates/skills/genex-threejs-raymarched-space-effects/SKILL.md +25 -18
  30. package/templates/skills/genex-threejs-raymarched-space-effects/references/space-effects.md +185 -21
  31. package/templates/skills/genex-threejs-screen-space-ambient-occlusion/SKILL.md +23 -17
  32. package/templates/skills/genex-threejs-screen-space-ambient-occlusion/references/ambient-occlusion.md +430 -20
  33. package/templates/skills/genex-threejs-shadow-systems/SKILL.md +29 -18
  34. package/templates/skills/genex-threejs-shadow-systems/references/shadow-systems.md +420 -21
  35. package/templates/skills/genex-threejs-skill-router/SKILL.md +21 -21
  36. package/templates/skills/genex-threejs-spectral-ocean/SKILL.md +30 -20
  37. package/templates/skills/genex-threejs-spectral-ocean/references/spectral-ocean.md +462 -22
  38. package/templates/skills/genex-threejs-temporal-surfaces/SKILL.md +26 -17
  39. package/templates/skills/genex-threejs-temporal-surfaces/references/temporal-surfaces.md +198 -20
  40. package/templates/skills/genex-threejs-visual-validation/SKILL.md +34 -18
  41. package/templates/skills/genex-threejs-visual-validation/references/visual-validation.md +396 -32
  42. package/templates/skills/genex-threejs-volumetric-clouds/SKILL.md +33 -17
  43. package/templates/skills/genex-threejs-volumetric-clouds/references/volumetric-clouds.md +570 -21
  44. package/templates/skills/genex-threejs-water-optics/SKILL.md +33 -18
  45. package/templates/skills/genex-threejs-water-optics/references/water-optics.md +184 -20
package/dist/index.js CHANGED
@@ -788,32 +788,71 @@ async function deployGame(sshUrl, opts, log) {
788
788
  return false;
789
789
  }
790
790
  const gitDir = await fs6.mkdtemp(path7.join(os2.tmpdir(), "genex-deploy-"));
791
- const gitEnv = { GIT_DIR: gitDir, GIT_WORK_TREE: siteDir };
791
+ const base = { GIT_DIR: gitDir };
792
+ const ident = {
793
+ GIT_AUTHOR_NAME: "genex",
794
+ GIT_AUTHOR_EMAIL: "agent@genex.local",
795
+ GIT_COMMITTER_NAME: "genex",
796
+ GIT_COMMITTER_EMAIL: "agent@genex.local"
797
+ };
798
+ const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
792
799
  try {
793
- if ((await run("git", ["init", "-q"], gitEnv)).code !== 0) {
800
+ if ((await run("git", ["init", "-q"], base)).code !== 0) {
794
801
  log.warn("git init failed \u2014 the game was not pushed.");
795
802
  return false;
796
803
  }
797
- await run("git", ["add", "-A"], gitEnv);
798
- const tracked = await run("git", ["ls-files"], gitEnv);
799
- if (/(^|\/)genex_key(\.pub)?$/m.test(tracked.out)) {
804
+ await fs6.writeFile(
805
+ path7.join(gitDir, "info", "exclude"),
806
+ ["node_modules/", "dist/", ".git/", KEY_NAME, `${KEY_NAME}.pub`, ".genex/", ""].join("\n")
807
+ );
808
+ const stage = async (workTree, indexName) => {
809
+ const env = { ...base, GIT_WORK_TREE: workTree, GIT_INDEX_FILE: path7.join(gitDir, indexName) };
810
+ await run("git", ["add", "-A"], env);
811
+ const tracked = await run("git", ["ls-files"], env);
812
+ if (/(^|\/)genex_key(\.pub)?$/m.test(tracked.out)) throw new Error("KEY_STAGED");
813
+ if (!tracked.out.trim()) return null;
814
+ const tree = (await run("git", ["write-tree"], env)).out.trim();
815
+ return tree || null;
816
+ };
817
+ const commitTree = async (tree, message) => (await run("git", ["commit-tree", tree, "-m", message], { ...base, ...ident })).out.trim();
818
+ let mainTree;
819
+ try {
820
+ mainTree = await stage(siteDir, "index-main");
821
+ } catch {
800
822
  log.error(`Refusing to deploy: ${KEY_NAME} is staged. Add it to .gitignore and retry.`);
801
823
  return false;
802
824
  }
803
- const commit = await run(
804
- "git",
805
- ["-c", "user.email=agent@genex.local", "-c", "user.name=genex", "commit", "-q", "-m", "build"],
806
- gitEnv
807
- );
808
- if (commit.code !== 0 && !/nothing to commit/i.test(commit.out + commit.err)) {
825
+ if (!mainTree || mainTree === EMPTY_TREE) {
809
826
  log.warn("Nothing to commit \u2014 the build produced no files.");
810
827
  return false;
811
828
  }
829
+ await run("git", ["update-ref", "refs/heads/main", await commitTree(mainTree, "build")], base);
830
+ let pushSource = false;
831
+ if (siteDir !== cwd) {
832
+ try {
833
+ const srcTree = await stage(cwd, "index-source");
834
+ if (srcTree && srcTree !== EMPTY_TREE) {
835
+ await run("git", ["update-ref", "refs/heads/source", await commitTree(srcTree, "source")], base);
836
+ pushSource = true;
837
+ }
838
+ } catch {
839
+ log.dim(" (Couldn't publish source for remixing \u2014 the deploy key was in the way.)");
840
+ }
841
+ }
812
842
  log.step("Pushing your game over SSH\u2026");
813
- const push = await run("git", ["push", "-q", sshUrl, "+HEAD:main"], {
814
- ...gitEnv,
815
- GIT_SSH_COMMAND: `ssh -i ${keyPath} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new`
816
- });
843
+ const refspecs = ["+refs/heads/main:main"];
844
+ if (pushSource) refspecs.push("+refs/heads/source:source");
845
+ const push = await run(
846
+ "git",
847
+ ["push", "-q", ...pushSource ? ["--atomic"] : [], sshUrl, ...refspecs],
848
+ {
849
+ ...base,
850
+ // Quote the key path: git splits GIT_SSH_COMMAND with shell-like rules, so a
851
+ // project folder with a space (e.g. "fly drone") otherwise breaks the `-i`
852
+ // argument and ssh fails with "Could not resolve hostname …".
853
+ GIT_SSH_COMMAND: `ssh -i "${keyPath}" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new`
854
+ }
855
+ );
817
856
  if (push.code === 0) {
818
857
  log.success("Pushed.");
819
858
  if (opts.playUrl) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Set up your ~/.claude workspace, authorize, create a game project, generate AI assets, and publish (genex CLI).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,26 +5,38 @@ description: Implement sky and aerial perspective for Genex Three.js games. Use
5
5
 
6
6
  # Genex Three.js Atmosphere And Aerial Perspective
7
7
 
8
- Atmosphere should explain scale and lighting without hiding gameplay. Add it
9
- after the base scene reads.
8
+ Treat sky rendering and aerial perspective as two views of the same scattering model. They must share radii, density profiles, coefficients, sun direction, exposure scale, and coordinate transforms.
10
9
 
11
- Read [references/atmosphere.md](references/atmosphere.md) for sky, haze,
12
- lighting handoff, and transition checks.
10
+ ## Choose the implementation tier
13
11
 
14
- ## Build order
12
+ - Small scene with no orbital camera: analytic height/distance approximation.
13
+ - Planetary ground-to-space camera: ray integration or precomputed LUTs.
14
+ - Large geospatial world: LUTs plus world-to-planet transform, altitude correction, and depth-aware aerial perspective.
15
15
 
16
- 1. Define world scale, camera altitude range, sun direction, horizon behavior,
17
- and target devices.
18
- 2. Build the sky model or sky gradient first.
19
- 3. Add depth-based aerial perspective for terrain, buildings, and distant props.
20
- 4. Connect sun color, ambient color, fog, and material response coherently.
21
- 5. Add planetary shell or LUT paths only when the scale needs them.
22
- 6. Expose debug views for transmittance, inscattering, depth, and no-atmosphere.
16
+ Read [references/atmosphere.md](references/atmosphere.md)
17
+ before implementation. It separates the LUT/ellipsoid architecture from
18
+ dynamic integration and the shell/post handoff.
23
19
 
24
- ## Rules
20
+ ## Required outputs
25
21
 
26
- - Keep gameplay silhouettes readable through haze.
27
- - Use one owner for sky color and sun direction.
28
- - Avoid stacking multiple fog systems with different assumptions.
29
- - Keep atmosphere quality adjustable for lower-end browsers.
30
- - Validate ground, mid-altitude, and high-altitude views.
22
+ - sky radiance;
23
+ - sun transmittance/color;
24
+ - segment transmittance from camera to visible surface;
25
+ - segment inscattering;
26
+ - optional sky irradiance for materials;
27
+ - explicit scale conversion between world units and atmosphere units.
28
+
29
+ ## Failure conditions
30
+
31
+ - sky and terrain haze use different sun directions or coefficients;
32
+ - the atmosphere is a uniformly transparent sphere;
33
+ - camera altitude is measured in a local flat frame during orbital motion;
34
+ - scene depth is treated as linear when it is not;
35
+ - exposure is used to hide incorrect radiance scale;
36
+ - atmosphere fades abruptly at shell entry.
37
+
38
+ ## Routing boundary
39
+
40
+ This skill owns molecular/aerosol sky scattering and surface-segment aerial
41
+ perspective. Use `$genex-threejs-volumetric-clouds` for weather-shaped cloud density,
42
+ temporal cloud reconstruction, and cloud shadows.
@@ -1,29 +1,213 @@
1
- # Atmosphere And Aerial Perspective
1
+ # Atmosphere system contract
2
2
 
3
- Use this reference for outdoor scale and sky rendering.
3
+ Use this contract to choose between a precomputed LUT/ellipsoid atmosphere and bounded dynamic integration while keeping sky, aerial perspective, surface lighting, and coordinate transforms coherent.
4
4
 
5
- ## Sky
5
+ ## Contents
6
6
 
7
- - Keep sun direction explicit and shared with lighting.
8
- - Match sky color, ambient color, and direct light temperature.
9
- - Include sun or moon discs only when they help composition.
10
- - Keep stars or space backgrounds separated from atmospheric haze.
7
+ - Shared parameter model
8
+ - LUT atmosphere implementation LUT contract
9
+ - Ellipsoid and depth ownership
10
+ - planet-space implementation body profiles
11
+ - planet-space implementation integration
12
+ - Shell/post handoff
13
+ - Implementation limits
14
+ - Diagnostics
11
15
 
12
- ## Aerial perspective
13
16
 
14
- - Apply haze by depth or world distance.
15
- - Preserve contrast for interactable objects and traversal edges.
16
- - Let distant terrain shift color before it loses all form.
17
- - Provide a debug toggle to remove atmosphere.
17
+ ## Shared parameter model
18
18
 
19
- ## Planetary scale
19
+ `LUT atmosphere implementation` keeps one atmosphere object for sky and aerial perspective.
20
+ Earth-like defaults:
20
21
 
21
- - Use altitude-aware behavior for ground-to-space transitions.
22
- - Keep horizon curvature and shell radius consistent with planet radius.
23
- - Validate camera positions near ground, high altitude, and orbit.
22
+ ```text
23
+ solar irradiance = (1.474, 1.8504, 1.91198)
24
+ sun angular radius = 0.004675 rad
25
+ bottom radius = 6,360,000 m
26
+ top radius = 6,420,000 m
27
+ Rayleigh scattering = (0.005802, 0.013558, 0.0331)
28
+ Mie scattering = (0.003996, 0.003996, 0.003996)
29
+ Mie extinction = (0.00444, 0.00444, 0.00444)
30
+ Mie phase g = 0.8
31
+ absorption extinction = (0.00065, 0.001881, 0.000085)
32
+ ground albedo = 0.1
33
+ ```
24
34
 
25
- ## Performance
35
+ Density profiles are two-layer functions:
26
36
 
27
- - Prefer simple depth haze for small scenes.
28
- - Use precomputed or lower-resolution paths for expensive scattering.
29
- - Expose quality tiers and render-target costs.
37
+ ```text
38
+ density(h) =
39
+ clamp(
40
+ expTerm * exp(expScale * h)
41
+ + linearTerm * h
42
+ + constantTerm,
43
+ 0,
44
+ 1
45
+ )
46
+ ```
47
+
48
+ The default Rayleigh exponential scale is `-0.125`, Mie `-0.833333`.
49
+ Absorption uses two linear layers centered around the ozone region rather than
50
+ another ground-heavy exponential.
51
+
52
+ One explicit meter-to-render-unit conversion is applied when parameters become
53
+ uniforms. Preserve this single conversion boundary.
54
+
55
+ ## LUT atmosphere implementation LUT contract
56
+
57
+ The sky material and aerial-perspective effect consume the same:
58
+
59
+ ```text
60
+ transmittance texture
61
+ scattering 3D texture
62
+ irradiance texture
63
+ optional single-Mie and higher-order scattering textures
64
+ atmosphere parameters
65
+ sun direction
66
+ ```
67
+
68
+ The sky material reconstructs rays from inverse projection and inverse view
69
+ matrices. It can render sun, moon, ground, and shadow-length integration.
70
+
71
+ The aerial-perspective effect owns:
72
+
73
+ ```text
74
+ camera projection/view and inverses
75
+ camera world position
76
+ depth
77
+ optional normal buffer
78
+ ellipsoid radii
79
+ world-to-ECEF transform
80
+ altitude correction
81
+ geometric-error correction
82
+ overlay/cloud shadow/light-mask inputs
83
+ ```
84
+
85
+ Default composition enables segment transmittance and inscatter. Direct sun
86
+ light and sky-light relighting are separate switches. Do not collapse these
87
+ signals into one fog color.
88
+
89
+ ## Ellipsoid and depth ownership
90
+
91
+ The geospatial path defaults to `Ellipsoid.WGS84` and can correct both
92
+ camera altitude and geometry error. Atmosphere altitude is therefore not
93
+ `worldPosition.y`.
94
+
95
+ Required coordinate contract:
96
+
97
+ ```text
98
+ world position
99
+ -> world-to-ECEF
100
+ -> ellipsoid-relative position
101
+ -> corrected altitude
102
+ -> LUT coordinates / segment scattering
103
+ ```
104
+
105
+ The aerial effect declares depth ownership through its post-processing effect
106
+ attribute. It also supports octahedral normals or normal reconstruction when
107
+ lighting terms require orientation.
108
+
109
+ ## planet-space implementation body profiles
110
+
111
+ planet-space implementation derives profiles by body kind and density. Terrestrial baseline:
112
+
113
+ ```text
114
+ Rayleigh = (0.0058, 0.0135, 0.0331)
115
+ Mie scattering = (0.0022, 0.0022, 0.0022)
116
+ Mie extinction = (0.0032, 0.0032, 0.0032)
117
+ Rayleigh scale height = lerp(7.2, 10.8, normalized density) km
118
+ Mie scale height = lerp(0.9, 1.7, normalized density) km
119
+ Mie g = 0.76
120
+ ozone extinction = (0.00065, 0.001881, 0.000085)
121
+ solar intensity = 13.8
122
+ ```
123
+
124
+ Rocky bodies reduce scattering and remove ozone. Gas/ice giants use much
125
+ larger scale heights and `g` around `0.80–0.82`.
126
+
127
+ The implementation enforces:
128
+
129
+ ```text
130
+ mieExtinction[channel] >= mieScattering[channel] + 0.0001
131
+ g <= 0.92
132
+ ```
133
+
134
+ This prevents negative absorption and unstable phase behavior.
135
+
136
+ ## planet-space implementation integration
137
+
138
+ For each camera ray, planet-space implementation:
139
+
140
+ 1. intersects the top atmosphere sphere;
141
+ 2. clamps the segment against the surface sphere;
142
+ 3. marches `ATMOSPHERE_VIEW_SAMPLES`;
143
+ 4. accumulates Rayleigh, Mie, and triangular ozone depth;
144
+ 5. at every view sample, marches a sun segment with
145
+ `ATMOSPHERE_LIGHT_SAMPLES`;
146
+ 6. tests planet occlusion of the sun;
147
+ 7. evaluates Rayleigh and anisotropic Mie phase;
148
+ 8. returns in-scattered radiance and view transmittance.
149
+
150
+ It adds an upper-Rayleigh exponential term and fades density over the final
151
+ `24%` of atmosphere thickness to soften the shell edge.
152
+
153
+ The compact path includes a small multiple-scattering approximation derived
154
+ from `1 - transmittance`; it is not equivalent to the precomputed higher-order
155
+ scattering available in `LUT atmosphere implementation`.
156
+
157
+ ## Shell/post handoff
158
+
159
+ planet-space implementation renders a double-sided shell and a depth-aware post path from one
160
+ profile. Runtime face-opacity weights avoid a hard front/back cull switch.
161
+
162
+ The post blend is based on altitude above the atmosphere top:
163
+
164
+ ```text
165
+ entry blend near = 140 km
166
+ entry blend far = max(448 km, visual atmosphere height * 0.58)
167
+ post blend = 1 - smoothstep(near, far, altitudeFromTop)
168
+ ```
169
+
170
+ The post path applies only where scene depth represents a surface. The shell
171
+ continues to own sky pixels and limb appearance.
172
+
173
+ Preserve:
174
+
175
+ ```text
176
+ one body center and radius
177
+ one atmosphere profile
178
+ one sun direction
179
+ one unit conversion
180
+ surface-depth classification
181
+ continuous shell/post blend
182
+ ```
183
+
184
+ ## Implementation limits
185
+
186
+ - planet-space implementation performs nested dynamic integration and is expensive compared with
187
+ LUT lookup.
188
+ - Its atmosphere uses spheres, while `LUT atmosphere implementation` supports an ellipsoid
189
+ and ECEF correction.
190
+ - planet-space implementation’s multiple-scattering term is an artistic approximation.
191
+ - `LUT atmosphere implementation` is version-sensitive and built around its own
192
+ post-processing/coordinate utilities; adapt the architecture, not imports
193
+ blindly.
194
+ - Do not combine LUT radiance and dynamic integrated radiance at full weight.
195
+ Choose ownership or a validated transition.
196
+
197
+ ## Diagnostics
198
+
199
+ Expose:
200
+
201
+ ```text
202
+ planet/ECEF coordinates and corrected altitude
203
+ top and bottom intersections
204
+ Rayleigh, Mie, and absorption density
205
+ view and sun optical depth
206
+ sun visibility
207
+ segment transmittance
208
+ single and multiple scattering
209
+ sky versus surface depth classification
210
+ shell front/back opacity
211
+ post blend
212
+ LUT coordinates and texture slices
213
+ ```
@@ -5,26 +5,37 @@ description: Implement controlled HDR bloom for Genex Three.js games. Use for se
5
5
 
6
6
  # Genex Three.js Bloom
7
7
 
8
- Bloom should reveal strong light and energy. It should not be the only reason an
9
- object reads.
8
+ Bloom is a camera/display response to bright HDR signal. Establish scene exposure and emissive luminance before tuning blur.
10
9
 
11
- Read [references/bloom.md](references/bloom.md) for HDR signal setup,
12
- selective contribution, blur hierarchy, and diagnostics.
10
+ ## Workflow
13
11
 
14
- ## Build order
12
+ 1. Inspect pre-tone-map luminance.
13
+ 2. Choose which scene values should bloom.
14
+ 3. Choose a single-node or dual selective-render ownership model.
15
+ 4. Calibrate threshold, radius, smooth width, and strength in HDR.
16
+ 5. Restore all substituted materials transactionally for selective passes.
17
+ 6. Composite before exposure/tone mapping.
18
+ 7. Validate base, contribution, and final views.
15
19
 
16
- 1. Confirm the scene uses a consistent HDR signal and tone-mapping path.
17
- 2. Define what is allowed to bloom and why.
18
- 3. Extract bright or selected contribution.
19
- 4. Blur at multiple scales.
20
- 5. Composite with exposure-aware strength.
21
- 6. Expose debug views for source, threshold mask, blur levels, final bloom, and
22
- no-bloom baseline.
20
+ Read [references/bloom.md](references/bloom.md) for the
21
+ HDR ordering, dual selective-bloom transaction, compact emissive hierarchy,
22
+ and the costs and limits of each ownership model.
23
23
 
24
- ## Rules
24
+ Apply the material substitution/restoration ownership pattern in the
25
+ reference before adding selective bloom to a composed scene.
25
26
 
26
- - Keep emissive intensities scene-relative.
27
- - Avoid global bloom that washes out gameplay silhouettes.
28
- - Restore materials if using selective render passes.
29
- - Tune bloom with exposure and grading visible.
30
- - Validate readability with bloom disabled.
27
+ ## Failure conditions
28
+
29
+ - bloom creates the only visible form of an effect;
30
+ - all bright materials share one arbitrary emission multiplier;
31
+ - threshold is tuned after tone mapping;
32
+ - selective bloom requires mutating scene materials every frame without restoration guarantees;
33
+ - transparent particles disappear from extraction because pass ownership is unclear;
34
+ - bloom radius changes wildly with resolution;
35
+ - highlights become gray because energy is clamped too early.
36
+
37
+ ## Routing boundary
38
+
39
+ Use `$genex-threejs-exposure-color-grading` for metering, adaptation, tone mapping,
40
+ and LUTs. Load `$genex-threejs-image-pipeline` only when bloom must be composed with
41
+ several shared image-space systems.
@@ -1,29 +1,185 @@
1
- # Bloom
1
+ # HDR bloom systems
2
2
 
3
- Use this reference for controlled glow in Genex games.
3
+ Use this reference to choose bloom ownership, signal order, selective contribution, and scene-relative emissive ranges without making bloom responsible for the underlying form.
4
4
 
5
- ## Signal ownership
5
+ ## Contents
6
6
 
7
- - Establish whether bloom comes from HDR thresholding, selection layers, or both.
8
- - Keep tone mapping after bloom composition.
9
- - Keep exposure changes from unpredictably destroying bloom intent.
7
+ - production WebGPU pipeline signal order
8
+ - production WebGPU pipeline bloom controls
9
+ - selective gallery pipeline selective ownership
10
+ - Material substitution invariant
11
+ - atlas-based renderer baseline
12
+ - pooled VFX system HDR hierarchy
13
+ - Implementation limits
14
+ - Diagnostics
10
15
 
11
- ## Selective bloom
12
16
 
13
- - Use layers, masks, or a separate render pass.
14
- - Restore material state after rendering a selected pass.
15
- - Avoid duplicate contribution from the same object.
16
- - Keep selected objects documented.
17
+ ## production WebGPU pipeline signal order
17
18
 
18
- ## Blur levels
19
+ The WebGPU pipeline owns bloom before exposure and render output:
19
20
 
20
- - Small radius: sharp energy and UI-like highlights.
21
- - Medium radius: glow around light sources.
22
- - Large radius: atmosphere or spectacle.
23
- - Keep each level inspectable.
21
+ ```text
22
+ scene pass
23
+ -> optional GTAO composite
24
+ -> optional atmosphere
25
+ -> bloom node
26
+ -> sampled scene + bloom
27
+ -> eye-adaptation exposure
28
+ -> renderOutput / tone map
29
+ -> optional 3D LUT
30
+ -> optional FXAA
31
+ ```
24
32
 
25
- ## Failure checks
33
+ The render pipeline disables its automatic output color transform and assigns
34
+ one final output node. Preserve this one-owner rule when adapting to current
35
+ Three.js `RenderPipeline`.
26
36
 
27
- - Bloom cannot carry the silhouette alone.
28
- - White UI or text should not bloom unless intentionally emissive.
29
- - Dark scenes should not become foggy because bloom strength is too high.
37
+ ## production WebGPU pipeline bloom controls
38
+
39
+ Bloom defaults:
40
+
41
+ ```text
42
+ enabled = false
43
+ strength = 0
44
+ radius = 0.35
45
+ threshold = 0.72
46
+ smooth width = 0.08
47
+ ```
48
+
49
+ The Three.js bloom node reads the HDR texture produced after atmosphere. Its
50
+ strength becomes zero when disabled; radius, threshold, and smooth width remain
51
+ independently updateable.
52
+
53
+ This path does not implement a custom pyramid. Its contract is signal placement
54
+ and parameter ownership around the renderer’s bloom node.
55
+ Verify the installed Three.js node API before using the exact constructor or
56
+ property names.
57
+
58
+ ## selective gallery pipeline selective ownership
59
+
60
+ The gallery uses two separate selective bloom pipelines:
61
+
62
+ ```text
63
+ neon layer -> neon UnrealBloomPass
64
+ chandelier layer -> chandelier UnrealBloomPass
65
+ base scene -> final composer
66
+
67
+ final = base + neon bloom + chandelier bloom
68
+ ```
69
+
70
+ Each bloom composer renders off-screen. A final shader adds both bloom textures
71
+ to the base render, then an `OutputPass` performs display output.
72
+
73
+ Separate ownership lets neon animation change strength/radius without forcing
74
+ the chandelier glow to share the same threshold or spread.
75
+
76
+ Chandelier bulbs, filaments, and glow meshes use unlit materials; bulb and
77
+ filament materials set `toneMapped = false`. The pipeline therefore combines
78
+ explicit layer membership with material-level HDR/display behavior.
79
+
80
+ ## Material substitution invariant
81
+
82
+ For each selective pass, selective gallery pipeline traverses visible meshes and replaces every
83
+ non-member material with one shared black material.
84
+
85
+ Required transaction:
86
+
87
+ ```text
88
+ set active bloom layer
89
+ traverse visible meshes
90
+ record { mesh, original material }
91
+ replace non-members with shared black material
92
+ try:
93
+ render bloom composer
94
+ finally:
95
+ restore every recorded material
96
+ clear restoration list
97
+ ```
98
+
99
+ Support material arrays by storing the complete original `mesh.material`
100
+ value. Also toggle the high-detail and simplified
101
+ chandelier representations so only the intended version contributes.
102
+
103
+ The `finally` block is non-negotiable. Without it, a render error permanently
104
+ blackens scene meshes.
105
+
106
+ ## atlas-based renderer baseline
107
+
108
+ atlas-based renderer wraps `UnrealBloomPass` with:
109
+
110
+ ```text
111
+ strength = 0.30
112
+ radius = 0.50
113
+ threshold = 0.05
114
+ ```
115
+
116
+ Composer order:
117
+
118
+ ```text
119
+ scene -> SSAO -> volumetrics -> bloom -> lens flare -> fog/color
120
+ ```
121
+
122
+ This is a useful comparison, not the quality target. The threshold is very low
123
+ and can bloom ordinary bright surfaces. The wrapper exposes only enabled,
124
+ strength, and threshold, while radius stays at its constructor value.
125
+
126
+ ## pooled VFX system HDR hierarchy
127
+
128
+ pooled VFX system assigns compact effect luminance before bloom:
129
+
130
+ ```text
131
+ spark initial RGB multiplier = 80
132
+ homing projectile = 30
133
+ laser = 10
134
+ ```
135
+
136
+ These values establish a material-level contribution hierarchy, but they do
137
+ not define the bloom pass. Validate them against actual renderer exposure
138
+ before reuse.
139
+
140
+ Use the relationship, not the raw numbers:
141
+
142
+ ```text
143
+ short spark flash
144
+ > projectile core
145
+ > persistent laser
146
+ > ordinary lit surface
147
+ ```
148
+
149
+ ## Implementation limits
150
+
151
+ - selective gallery pipeline renders the scene multiple times for selective bloom. This is
152
+ acceptable for its bounded gallery but expensive for large scenes.
153
+ - Temporary material substitution can trigger shader/program changes and must
154
+ account for newly added meshes.
155
+ - The final selective gallery pipeline composite adds bloom textures directly; energy is
156
+ artistic, not physically conserved.
157
+ - atlas-based renderer’s low threshold is not evidence for a general HDR calibration.
158
+ - production WebGPU pipeline depends on version-sensitive Three.js bloom-node behavior.
159
+ - pooled VFX system material multipliers are scene-relative and cannot be treated as
160
+ exposure-independent units.
161
+
162
+ Prefer a dedicated contribution target when MRT/backend architecture supports
163
+ it and the scene cannot afford multiple full renders. Validate that decision
164
+ against the target scene’s measured cost and contribution masks.
165
+
166
+ ## Diagnostics
167
+
168
+ Expose:
169
+
170
+ ```text
171
+ HDR scene before bloom
172
+ false-color luminance
173
+ neon contribution
174
+ chandelier contribution
175
+ each bloom result
176
+ base without bloom
177
+ final composite
178
+ active layer membership
179
+ material restoration count and leak assertion
180
+ transparent-emitter contribution
181
+ bloom GPU time per render
182
+ ```
183
+
184
+ Acceptance requires the base frame to retain form and material hierarchy with
185
+ both bloom textures disabled.