Noniv / web-ocean
git clone https://github.com/Noniv/web-ocean.git
Real-time WebGPU ocean renderer written from scratch, no engine. FFT waves, whitecaps, sun glitter, physically based sunset sky with clouds, free camera. Built with Claude Code (Opus 5.5). Opens from a single 61 KB HTML file in Chrome.
—
stars, 24h
+805
stars, 7 days · #89
+805
stars, 30 days · #376
805
★ total · +805% this week
124
forks · 5 open issues
Star history starts 2026-10-20; the chart appears after the second daily snapshot.
LanguageHTML
LicenseMIT
Created2026-10-16 (3d ago)
Last push3d ago
Watchers3
OwnerUser
Links
- GitHub: github.com/Noniv/web-ocean
- Homepage: https://ocean-noniv.vercel.app/
- Releases · Issues · Hacker News mentions
README excerpt
# web-ocean A real-time ocean renderer written from scratch on WebGPU, with no engine or rendering library. It draws a sunset sea with simulated waves, whitecaps, sun glitter, and a physically based sky with clouds. You fly around it with a free camera. | 75 degrees off the sun, 2.4 m up | Looking toward the sun from 30 m up | |---|---| | | | ## Run it You need a recent Chrome with WebGPU and a reasonably capable GPU. On a laptop, force Chrome onto the dedicated GPU in the Windows graphics settings, or it will fall back to the integrated one. Open `ocean.html` directly in the browser. `ocean.min.html` is the same page minified (61 KB instead of 102 KB). Both are self-contained and work from `file://`. To run from source: [code] After editing anything under `js/`, run `npm run build` to regenerate both bundles. The minified build strips WGSL comments and whitespace and minifies the JavaScript with esbuild. ## Controls | Input | Action | |---|---| | Click the canvas | Capture the mouse (Esc releases it). Holding the right mouse button also works. | | Mouse | Look around | | W A S D | Move | | Space or E / Q or C | Up / down | | Shift | 5x speed | | Mouse wheel | Change base speed | | H | Settings panel: wind, swell, choppiness, turbidity, foam, sun, haze, clouds, exposure, bloom | The camera keeps itself above the displaced water surface, so waves never pass through it. URL parameters are handy for testing. `?w=2560&h=1440` forces the render resolution, `cam=x,y,z,yawDeg,pitchDeg` sets the camera, `fov=deg` sets the field of view, `ui=0` hides the HUD, and any settings key works too, for example `windSpeed=12&swellHs=2&sunElev=8`. ## How it works ### Waves The sea is a Tessendorf FFT simulation with six cascades of 256 by 256 samples. The patches range from 1103 m down to 0.26 m, so wavelengths run from about a kilometre to a few millimetres. The smallest cascade produces the sharp sun sparkles near the camera. The spectrum is a fetch-limited JONSWAP wind sea with Donelan-Banner directional spreading, plus a narrow long-crested swell. Dispersion includes the capillary term, and choppy horizontal displacement sharpens the crests. The inverse FFTs are radix-2 compute shaders working in workgroup memory. The surface mesh is a CDLOD quadtree with 17 levels. Vertices are 6.25 cm apart near the camera and the mesh reaches 160 km, with continuous vertex morphing between levels. ### Shading - Mip-mapped first and second moments of the wave slopes (LEAN mapping) give the right anisotropic roughness at every distance. The sun glitter widens with distance and the far sea settles into a sheen without aliasing. Screen-space slope derivatives add specular anti-aliasing. - Sun glitter uses an anisotropic Gaussian slope distribution with Smith masking and the size of the solar disc. - The sky reflection comes from an environment cube map rebuilt every frame, with roughness-filtered mips. At grazing angles the reflection direction is tilted to account for which w