Threejs sky atmosphere and haze
Skill linegel/threejs-complete-set-of-skill/skills/threejs-sky-atmosphere-and-haze
25 expert agent skills for ambitious Three.js WebGPU/TSL scenes — procedural oceans, clouds, planets, water optics, image pipelines, and screenshot-backed visual validation. For Claude Code, Codex, Cursor, and any skill-aware agent.
npx -y skills add linegel/threejs-complete-set-of-skill --skill threejs-sky-atmosphere-and-hazeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
8.4 KB, as published. Nobody here has run it
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, imported LUT/product compatibility, or the single unit-equivalence fixture, read 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. It needs host depth only when haze is a separate depth-aware post. For the compact LUT branch, allocate no product merely because the branch was selected. Admit products by consumer:
| Product | Allocate only when |
|---|---|
| Transmittance | an admitted sky, aerial, or lighting path requires it directly or through a dependent product |
| Multiscatter | an admitted sky, aerial, or lighting closure includes higher-order response |
| Irradiance | an admitted diffuse-lighting consumer samples it |
| Sky-view | an admitted visible-sky consumer samples it |
| Aerial RGB inscattering and RGB optical depth | an admitted depth-aware composition consumer samples the paired payload |
A sky-only or lighting-only branch has no aerial allocation or aerial view dependencies.
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, every unadmitted product has zero allocation and no dependency state, and unchanged base LUTs survive camera-only changes.
4. Compose the selected branch
For an in-scene authored branch, attach the SkyMesh and TSL fog/haze to the
host scene and keep their output scene-linear.
For a separate depth-aware haze or LUT aerial branch, 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 in that branch, apply exactly:
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.
Complete when: each admitted in-scene branch reaches the host output path
once; each enabled depth-aware branch reconstructs known positions within the
declared tolerance, keeps sky/surface coverage stable, and returns C_scene
under the zero-atmosphere control; tone mapping/output conversion runs once.
5. Expose an admitted lighting handoff
When another system consumes atmosphere-derived lighting, expose only the quantities it 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: a visual-only branch has no unused lighting interface; every admitted lighting consumer can identify quantity, unit, frame, sample age, and included attenuation, and its 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.