threejs-sky-atmosphere-and-haze ยท diff
git:20260713.f0e8d5c to git:20260716.2ce13bc
170 added, 1 removed. Audit C to A.
- ../../threejs-sky-atmosphere-and-haze/SKILL.md
+ ---
+ name: threejs-sky-atmosphere-and-haze
+ description: Build sky, atmosphere, and haze in Three.js WebGPU/TSL. Use for authored sky/fog, planetary scattering, depth-aware aerial perspective, or atmosphere-derived sun/sky lighting.
+ ---
+
+ # Sky, Atmosphere, and Haze
+
+ Build every branch around one atmosphere model, one scene-linear HDR path, and
+ one final-output owner.
+
+ ## Process
+
+ ### 1. Select the transport claim
+
+ Choose the least expensive branch that supports the requested observable:
+
+ | Need | Branch | Valid claim |
+ | --- | --- | --- |
+ | Regional authored sky, distance haze, or height haze | `SkyMesh` plus TSL fog/haze | Authored appearance in a bounded local frame |
+ | Real-time planetary sky and aerial perspective | Compact Hillaire-style LUTs | Approximate higher-order transport within measured error |
+ | Fixed atmosphere with stricter spectral/angular accuracy | Bruneton-style scattering orders or an offline solve | Accuracy demonstrated against the chosen reference |
+
+ Use the compact branch for changing cameras and suns. Use the higher-order
+ branch when its regeneration cost and higher-dimensional products fit the
+ actual workload. Keep an offline integrator as reference evidence rather than
+ visible-pixel runtime work.
+
+ **Complete when:** the implementation names one branch, its supported spatial
+ domain, its physical-versus-authored claim, and the error or visual criterion
+ that admits it.
+
+ ### 2. Establish one model
+
+ Declare one length unit for radii, positions, and integration steps; store
+ extinction/scattering coefficients in its reciprocal unit so
+ `beta * ds` is dimensionless. Define the body or local frame, origin policy,
+ altitude model, sun direction convention, spectral/working basis, and whether
+ the solar source is normal irradiance or finite-disc radiance.
+
+ Initialize `WebGPURenderer`, await `renderer.init()`, and confirm the native
+ WebGPU backend before allocating compute/storage products. Use
+ `NoColorSpace` for transport data and keep radiance scene-linear until the
+ host output stage.
+
+ For physically dimensioned extinction, LUT radiometry, mapping equations, phase
+ conventions, product dependencies, or the single unit-equivalence fixture, read
+ [references/atmosphere-transport.md](references/atmosphere-transport.md).
+
+ **Complete when:** every producer and consumer uses the same frame, length
+ conversion, sun convention, and radiometric basis; physically dimensioned
+ extinction also gives the same fixture optical depth on CPU and GPU.
+
+ ### 3. Build products in dependency order
+
+ The authored local branch samples its sky and distance/height haze directly
+ from the shared model and host depth. The compact LUT branch generates:
+
+ ```text
+ transmittance
+ -> multiscatter and optional irradiance
+ -> camera/sun sky-view
+ -> aerial RGB inscattering plus RGB optical depth
+ -> scene composition
+ ```
+
+ Give each product its own dependency key and last-update reason. Atmosphere
+ profile and body changes dirty base products. Camera body-relative pose,
+ projection, viewport, and depth mapping dirty aerial products. Camera yaw,
+ projection jitter, and a pure floating-origin translation leave unchanged
+ body-frame LUTs valid.
+
+ Write 2D products with `StorageTexture` and `textureStore()`; write 3D
+ products with `Storage3DTexture` and `storageTexture3D()`. Set formats,
+ filters, wrapping, and mip ownership explicitly. Treat
+ `renderer.computeAsync()` as submission, not GPU completion; synchronize
+ readback, reuse, and retirement with an actual completion mechanism.
+
+ **Complete when:** every sampled product names all of its physical and view
+ dependencies, no consumer can observe a newer dependency with an older
+ dependent product, and unchanged base LUTs survive camera-only changes.
+
+ ### 4. Compose sky and aerial perspective
+
+ Reuse the host scene color and depth. Reconstruct the active perspective,
+ reversed, logarithmic, or orthographic depth convention into a metric segment,
+ then intersect that segment with the atmosphere. Classify sky through explicit
+ coverage or the declared clear-depth encoding.
+
+ For a visible surface, apply exactly:
+
+ ```text
+ C_out = C_scene * T_segment + S_segment
+ ```
+
+ For a sky pixel, sample sky radiance and the calibrated sun/moon disc. Keep
+ direct lighting, diffuse sky lighting, cloud shadows, opaque visibility, and
+ camera-segment transport as separate factors. Let either `renderOutput()` or
+ `RenderPipeline.outputColorTransform` own presentation.
+
+ For planetary bodies, exterior cameras, ellipsoids, non-perspective depth, or a
+ shell/post handoff, read
+ [references/body-depth-and-composition.md](references/body-depth-and-composition.md).
+
+ **Complete when:** standard and enabled alternate depth modes reconstruct known
+ positions within the declared tolerance, sky/surface coverage is stable, the
+ zero-atmosphere control returns `C_scene`, and tone mapping/output conversion
+ runs once.
+
+ ### 5. Expose the lighting handoff
+
+ Expose only the quantities another system needs:
+
+ - sample time, model revision, physics frame/origin, support, filter, age, and
+ error;
+ - sample-to-sun unit direction and disc angular radius;
+ - calibrated solar quantity, unit, and basis;
+ - either direct sun already attenuated by the atmosphere, or the unattenuated
+ source plus atmosphere transmittance;
+ - directional sky radiance, normal-dependent sky irradiance, and whether each
+ includes the direct disc;
+ - camera-segment RGB transmittance and RGB inscattering.
+
+ Clouds add cloud-only optical depth; geometry adds visibility; water adds its
+ own path extinction. A consumer chooses one atmosphere direct-light form and
+ applies each factor once.
+
+ **Complete when:** every lighting consumer can identify quantity, unit, frame,
+ sample age, and included attenuation, and a factor trace proves that atmosphere,
+ cloud, geometry, water, and aerial transport each appear at most once.
+
+ ### 6. Verify the selected branch
+
+ Verify the mechanisms that branch actually uses:
+
+ - LUT forward/inverse maps at texel centers, boundaries, horizon split, and
+ azimuth seam;
+ - phase normalization and forward-lobe sign;
+ - optical-depth, radiance, and energy convergence against a higher-accuracy
+ reference;
+ - body intersections and every enabled depth encoding;
+ - product invalidation under parameter, camera, jitter, viewport, and origin
+ changes;
+ - fixed-view linear-HDR sky, horizon, night, surface-haze, and exterior-camera
+ diagnostics;
+ - create, resize/tier-switch, completion, and disposal ownership.
+
+ **Complete when:** every enabled branch passes its numeric and visual gates,
+ every diagnostic names the product revision it displays, and repeated
+ resize/tier-switch cycles leave one live generation per retained product.
+
+ ## Failure signatures
+
+ | Symptom | Inspect |
+ | --- | --- |
+ | Halo appears opposite the sun | phase direction sign |
+ | Haze changes with world scale | length/coefficient conversion |
+ | Horizon seam or limb pop | LUT seam, body interval, or owner transition |
+ | Terrain is darkened twice | direct-light or aerial factor ownership |
+ | Camera jitter regenerates base LUTs | dependency keys are too broad |
+ | Off-axis haze is too short | normalized depth was mistaken for ray distance |
+
+ ## Routing boundary
+
+ This skill owns molecular/aerosol sky transport, atmosphere-derived sun/sky
+ lighting, and camera-segment aerial perspective. Use
+ `$threejs-volumetric-clouds` for weather-shaped cloud density and cloud-only
+ shadows, `$threejs-image-pipeline` for shared scene signals and final-output
+ ownership, `$threejs-exposure-color-grading` for metering/tone mapping, and
+ `$threejs-procedural-planets` for terrain/body detail.
+