KQ-1532 · SEA/LEVEL

Sea Level

An ocean drawn in points and seen from a camera floating just above the surface, with a content plate riding the near water. Three seeded swells with peaked crests and two trains of chop move a world grid of points; the points are drawn near to far against a silhouette buffer, so a passing swell rises past the horizon and hides the water behind it, while the camera floats over the water ahead and rolls and pitches with it, so the whole view rocks. The pointer is the wind: its side turns the wind's direction on springs.drift and builds chop from that side on springs.drift, and the plate keeps riding the same swell. One slider under the plate turns the wind from the keyboard.

KQ-1532 · SEA/LEVEL

Left and right arrows turn the wind; while this has focus the wind builds chop on the water.

Coldbrook Harbour

Dawn swim, Saturday

calm · swell 0.50, breeze 0.35 off the sea

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/sea-level

Props

children
React.ReactNode
default —
The content plate that floats on the near water and rides the swell: a headline, a card.
waveHeight
number
default 0.5
How high the swell runs, 0 (glass) to 1 (a heavy sea that hides the horizon).
pointSize
number
default 1.4
The size of a near point, px; far points are finer. 0.6 to 3.
wind
number
default 0.35
The standing breeze, 0 (still air) to 1: how much chop rides the swell and how briskly it all moves.
color
string
default "var(--accent-bright)"
The water's points.
foamColor
string
default —
The crests' points, where the swell breaks into foam; by default the foreground mixed with a little of color.
horizon
number
default 0.36
Where the horizon sits, as a share of the height from the top, 0.15 to 0.6.
density
number
default 1
How closely the points are set, 0.5 (open) to 1.5 (dense).
speed
number
default 1
How fast the sea moves, 0 (held) to 2.
rock
number
default 0.6
How much the camera rolls and pitches with the water, 0 (level) to 1; it always floats at the surface.
floatAt
readonly [number, number]
default [0.5, 0.82]
Where the plate floats, as shares of the box: the point on the water under the plate's bottom edge.
heading / defaultHeading
number
default 0
The wind's direction in degrees, -80 (from the left) to 80 (from the right); 0 blows straight in. Controlled or initial.
onHeadingChange
(degrees: number) => void
default —
Fires when the pointer (on leaving) or the keys set a new wind direction, in whole degrees.
interactive
boolean
default true
The pointer and keys turn the wind and build chop.
pointerStrength
number
default 0.7
How much chop the hand builds from its side, 0 to 1.
paused
boolean
default false
Hold the sea still; the wind can still build chop.
seed
number
default 1
Seeds the swell, so two seas never match.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
label
string
default "Wind direction"
The accessible name of the wind control.
onActiveChange
(active: boolean) => void
default —
Fires when the pointer or the keyboard starts (true) or stops (false) building chop.
className
string
default —
Sizes and shapes the box; it fills its parent by default (h-full w-full).