web-ocean README

The project's README from github.com/Noniv/web-ocean. As one markdown file: README.md.

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.

Looking toward the sun from 2.4 m above the water

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:

npm install
npm start        # serves http://localhost:8080/

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

Sky

The atmosphere follows Hillaire's approach, with transmittance, multiple-scattering, and sky-view lookup tables plus aerosol haze. There are two cloud layers, a broken low cumulus and a fibrous altostratus deck. Each is shaded with self-shadowing toward the sun, lit rims, silver linings when backlit, and direction-dependent multiple scattering.

Cloud noise octaves are filtered by pixel footprint, and silhouettes are anti-aliased analytically: the screen-space derivative of each layer's edge function sets the width of its opacity edge. Cloud transmittance along the sun direction dims the sunlight that reaches the water, and aerial perspective is applied over the sea.

Post-processing

The scene renders in HDR with 4x MSAA. Post-processing adds an 8-level bloom, AgX tone mapping, a slight white balance shift, and dithering.

Performance

At 2560 by 1440 on an RTX 5070 Ti, the GPU takes about 6 to 8 ms per frame, measured while other programs were also using the GPU. The HUD shows FPS and GPU time when the browser supports timestamp-query.

The per-frame code reuses preallocated typed arrays and descriptors, so the garbage collector has almost nothing to do. The only recurring allocations are the objects WebGPU itself requires, such as the swap-chain view and command buffers.

Known limitations

How it was made

I built this with Claude Code (Opus 5.5). I asked for the most realistic water it could produce, in WebGPU, with a floating camera, and left the architecture and implementation to it. It checked its own work by rendering screenshots in headless Chrome and having separate critic subagents review them, so it was not grading its own output. I gave feedback along the way, mainly on the clouds, which led to replacing the volumetric clouds with the flat layers and later fixing their edge aliasing.

Repository layout

Path Contents
index.html Page shell, HUD, and settings panel styles
js/main.js Device setup, resources, camera, per-frame loop
js/wgsl/ Shaders as JavaScript modules: sim.js (waves and foam), sky.js (atmosphere and clouds), ocean.js (surface and sky pass), post.js (bloom and tone mapping), common.js (shared structs)
server.mjs Tiny static server for development
build.mjs Builds ocean.html and ocean.min.html
docs/ README images

License

MIT. See LICENSE.

web-ocean (Noniv/web-ocean)

Searching Database…

Real-time WebGPU ocean renderer written from scratch, no engine. FFT waves, whitecaps, sun glitter, physically based sunset sky with clouds, free camera. 5).

Creator
Noniv
Size
0.7 MB
Stars
483
Updated
CommitOct 17
Age
1d
Commits · 90 Days