A customizable, top-down topographic visualization of Gerstner waves, rendered on the
GPU. Feed it a <canvas> and some parameters and it draws an animated contour map of the
sea surface.
This is a monorepo containing three layers:
| Package | What it is |
|---|---|
@sargasso/core |
The core rendering engine. Takes a canvas + params, renders with WebGL2. No framework, no DOM assumptions. |
@sargasso/elements |
Two custom elements: <sargasso-canvas> (drop-in embed of the engine) and <sargasso-controls> (a Preact UI that reads/writes another canvas's params). |
sargasso-block |
The WordPress plugin with Gutenberg blocks built on the elements: a wave-map container block (the animated waves are the background and you drop other blocks inside it, with optional glass blur, drop shadow, and corner radius) and a wave-controls block rendering an interactive wave map with the live <sargasso-controls> panel on the page. |
The surface is a sum of individual Gerstner waves, each with a direction,
wavelength, amplitude, and speed. Realistic water needs many of them (the shader
supports up to MAX_WAVES, currently 64), so the core ships:
WAVE_PRESETS— ready-made looks keyed by name (WAVE_PRESET_NAMES):"Glassy dawn","Calm swell","Lagoon","Open ocean","Crossed swells","Windy chop","Storm swell","Wind swell","Ripples". Each is aWavePreset({ waves, steepness? });DEFAULT_WAVESis the"Open ocean"preset's waves.generateWaveSpectrum(options)— build your own realistic set from a few knobs (count, wavelength band, dominant direction + spread, amplitude falloff, seed). It uses deep-water dispersion (longer waves travel faster) and irrational wavelength ratios so the pattern doesn't visibly tile.steepness(0–1) — adds a Stokes-style 2nd harmonic that sharpens crests and flattens/widens troughs along each wave's direction (how wind-driven waves form ridges; 0 = smooth swell)."Wind swell"pairs it with a few coherent trains for sharp ridges; both UIs expose it as a slider.
Every layer exposes wave editing: the <sargasso-controls> element and the WordPress
block both offer a preset picker plus a repeater to add, remove, and tune
individual waves.
Only contour lines are drawn (no color fill). Like a topographic map, they come in two
weights: light intermediate lines every contour.interval, and bolder index
lines every contour.emphasisEveryth line. Each weight has its own color, opacity, and
width — color / width for intermediate lines and emphasisColor / emphasisWidth
for index lines (color is RGBA, so the 4th channel is opacity). Set emphasisEvery: 0 for
a single uniform line weight. Both the <sargasso-controls> element and the WordPress
block expose all of these (interval, per-weight color/opacity/width, index frequency).
Requires Node ≥ 20.19 and pnpm (via corepack).
corepack enable
pnpm install
pnpm dev # run the web-components demo (canvas + controls) via Vite
pnpm test # run all unit tests (Vitest)
pnpm typecheck # tsc project references
pnpm lint # Biome check
pnpm build # build the publishable libraries
pnpm wp:build # build the WordPress plugin- pnpm workspaces for the monorepo.
- Vite (library mode) for library builds,
@wordpress/scriptsfor the plugin. - Vitest (+ happy-dom) for tests.
- Biome for lint + format.
- Forgejo Actions for CI (primary) — see
.forgejo/workflows/ci.yml. The GitHub repository is a mirror with its own workflow in.github/workflows/ci.yml.
MIT — see LICENSE.