---
name: snow-terrain
description: >
  Build a snow heightfield in one Three.js file: domain-warped CPU
  displacement, a traced sun and horizon light map, and a TSL surface for
  polish, melt and sparkle. Use when changing the grid, the trace, or the
  snow material on WebGPU. The reference file is snow.html beside this
  skill. If they disagree, the HTML wins.
---

# Snow heightfield

One HTML file. No bundler, no npm, no photo tiles. Three.js 0.186.1 from a CDN via an import map (`three` and `three/webgpu` both point at `three.webgpu.js`, `three/tsl` at `three.tsl.js`). `WebGPURenderer` only. Set `renderer._getFallback = null`. If `navigator.gpu` is missing, or the backend is not WebGPU after `init()`, stop. No WebGL fallback.

Open it through a server. `file://` will not load the ES modules. `php -S localhost:8000` or `npx serve` in the folder is enough.

## Height

`SIZE` 420, `SEG` 256, `GN` 257. `buildHeights` writes one float per grid point.

1. Domain warp from two low fBm octaves. Every later feature uses the warped coordinates.
2. Broad fBm for the mass, ridged noise for the spines, a tighter ridge for drifts, a last fBm for grain.
3. Pull the rim down so the horizon stays flat.
4. Hash with `ihash` (integer mix). Do not switch it to `sin` noise. On this grid that bands.

`applyHeights` writes the floats into the plane's local z, then `rotation.x = -PI/2`. `heightAt(x, z)` bilinear-samples the same grid. The camera uses it as a floor.

## Light map

`lightData` is `GN` by `GN`, RGBA, `NoColorSpace`.

- R: sun visibility. Walk toward the sun, keep the max slope, soft step against the sun's rise.
- G: horizon AO. 8 directions, jittered, squared steps, one blur.
- Texture row is `SEG - iy`. The plane's v is flipped relative to grid y. Drop the flip and the shadow slides off the ridge.

Sun sliders call `queueTrace`: a coarse pass, then a fine one. New terrain rebuilds height, AO and the fine shadow. Polish, melt, relief and sparkle are uniforms only.

## Material

`MeshStandardNodeMaterial`. `colorNode` mixes snow and rock from `normalWorld.y`, then multiplies by sun visibility and AO from `texture(lightTex)`. `roughnessNode` is the wind polish, the melt, and a little of the relief noise. `emissiveNode` is the sparkle, multiplied by sun visibility so shade does not glitter.

The study this came from lit the snow in GLSL and bloomed the glints. Do not put that shader back on `WebGPURenderer`. It will not run. Extend the node material.

## Orbit

Phi is elevation off the horizon.

```
x = sin(theta) * cos(phi) * dist
z = cos(theta) * cos(phi) * dist
```

Pointer move right decreases theta. Swapping sin and cos reverses left and right.
