More
Under the hood
What the water does each frame, and what changed from the single-file index.html page it grew out of. Drag each slider to compare the original with NatureGL Water.
#The frame
#Waves
On FFT tiers, one spectrum pass builds a JONSWAP directional spectrum from a static noise atlas, 2·log2(N) Stockham butterfly passes run over every cascade in one Float32 atlas, and a resolve pass writes mip-mapped HalfFloat displacement and slope textures. The swell cascade is read back asynchronously for the CPU. On Gerstner tiers the same spectrum is sampled into 24–56 Gerstner waves whose phases advance by ω·dt.
#Foam field
A ping-pong texture centred on the camera and snapped to its texels. Folding crests, breakers and hulls stamp foam into it; it decays with foamPersistence and drifts with the wind.
#World pass
Your scene, without the ocean and the overlay layer, into a HalfFloat target with a depth texture.
#Water pass
The ocean is a polar grid centred on the camera. The vertex shader sums the long waves at a mip level matched to the local grid spacing. The fragment shader adds the short band, reads the world depth for the water's thickness, and shades it: Beer–Lambert absorption, in-scatter, refraction with a depth blur, screen-space reflections over the sky reflection, GGX glitter, crest subsurface scattering and foam.
#Bloom and composite
A mip-chain bloom, then exposure, tone mapping and dither, plus the waterline split and meniscus when the camera straddles the surface.
#Against index.html
Each pair is the original page (before) and the NatureGL Water demo (after) from the same camera.
#Shore break
The original shoaled waves with a radial function built for one island and drew concentric surf rings. NatureGL Water bakes any terrain into a distance field, so breakers roll up the real coastline and swash runs up the sand.

#Storm sea
The high tier's FFT ocean with the persistent foam field. Whitecaps linger and break up into lace after the crest passes, instead of per-frame noise.

#Glitter and bloom
A GGX sun path with a clamped peak and an HDR bloom chain. Far water gets rougher instead of sparkling, because waves smaller than a pixel become roughness.

#What's new over the original
- A library.
WaterSystemrenders into your scene with your camera. The island, ships and reef are demo code. - Generic shorelines. A baked bathymetry (height, exact Euclidean distance to shore, shore direction) replaces the island-specific shoaling. Breakers break by the H/d index, swash foam runs up beaches, and contact foam ignores shallow objects, so a wreck's deck no longer turns into a beach.
- Persistent foam in a ping-pong field with a mip-mapped lace texture, instead of per-frame noise. Ships leave trails.
- Reflections. Screen-space reflections of ships, island and rocks on top of the sky.
- Antialiased normals. A mip-mapped micro-normal texture with Toksvig and LEAN roughness, and GGX glitter with a clamped peak.
- Forward-scattering blur of the refracted seabed with depth.
- Bloom (13-tap downsample, tent upsample) and a proper HDR composite.
- Seamless underwater. The reef was a separate scene; now the dive goes under the same ocean, with Snell's window, total internal reflection, light shafts and a waterline with a meniscus. Caustics became a reusable material patch.
- Composition.
setSky()for external skies, the overlay layer andbindLights(). - GPU FFT ocean as the high and ultra wave source: rotated, non-harmonic patches (512, 67.3 and 10.7 m) against tiling, and an asynchronous read-back so buoyancy follows the drawn swell.
- Speed. Long Gerstner waves per vertex and the short band per pixel took the 40-wave high tier from 87 to 120 fps (vsync), before the FFT became its default.
- Modern three. three r160 from a CDN became three ^0.186 from npm, with
THREE.TimerandPCFShadowMap, and no deprecation warnings.
#Limits
- WebGL2 and GLSL only, perspective cameras only, no logarithmic depth buffer.
- Sea level is fixed at
y = 0. - No true wave breaking or overturning: steep FFT crests are clamped, not curled.
- On FFT tiers the swell cascade repeats every 512 m, softened by the rotated detail cascades and fog. CPU sampling uses the swell cascade only, 1–3 frames late, so floating objects don't feel the small chop.
- Screen-space reflections only see what's on screen. Off-screen objects fall back to the sky.
- The waterline split assumes the surface is locally flat across the near plane, which holds for waves longer than about 1 m.
- In extreme storms
sampleHeightcan be a few centimetres off near sharp crests. - Up to 8 wakes are drawn.