The detail drift was `(0.011, 0.0043) * t`, so the field jumped to a new
pattern when the sky clock wrapped at 86400 s. `value_noise_plane` now takes
a lattice period and hashes cell indices modulo it; the detail plane tiles
every CLOUD_TILE = 64 cells (octave o every 64 << o, the half-rate domain
warp every 32), and the drift is whole tiles per wrap, CLOUD_DRIFT_TILES =
(15, 6), i.e. 0.01111 and 0.00444 cells/s (+1% and +3% over WarcraftXL's
rates). The shader takes the drift as `fract(tiles * t / SKY_WRAP) * tile`,
so the field at the wrap equals the field at 0, and the drift term stays
below 64 instead of growing to ~950 in f32. One tile spans 1.78 of the
sheet's UV, wider than the dome shows, so no spatial repeat is visible.
A test reads `sky_fx.wgsl` and pins SKY_WRAP to SKY_CLOCK_WRAP_S, an even
tile, whole tiles of drift and the rates within 5% of the originals.
Verified: cargo test -p benilla-world --lib (644 passed, 8 ignored);
cloud.wgsl (SKY_FX_CLOUDS) and sky.wgsl (SKY_FX) compose and validate under
naga_oil 0.20 / naga 27 offline. No GPU or WoW data here; built on Linux only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6yUWgPosSakvL23gtgvpH