KQ-1389 · DROP/RIPPLE

Drop Ripple

Water over an image or generated pool tiles, simulated on the GPU: a height field on a ping-pong pair of framebuffers (half-float where possible, byte-encoded where not) takes the neighbours' average less the previous height each fixed step and damps it, and its reads clamp at the edges, so a ring meets the sides and comes back crossed with its own reflection before it smooths to glass. A press drops a cosine dimple, a drag leaves a wake, a passing mouse a faint trail and seeded rain can fall; the picture is refracted through the surface normals with a soft highlight on the crests. The surface is a button: Enter or Space drops at a marker the arrow keys move, which glides there on springs.snap.

KQ-1389 · DROP/RIPPLE
Calm water over a lap pool's tiles. Press Enter or Space to drop into the water at the marker; the arrow keys move the marker.

Basinworks · lap pools

Swim the long water

still water · touch it, or tab to it and press Enter

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/drop-ripple

Props

src
string
default —
An image to put under the water; without one, the water lies over generated pool tiles.
alt
string
default "Water over pool tiles"
What the picture under the water shows, for assistive technology.
children
ReactNode
default —
Content laid over the water, such as a headline; it takes no pointer events, so drops land through it (give a control pointer-events-auto).
damping
number
default 0.4
How quickly the rings die away, from long-lived with many reflections at 0 to a quick settle at 1.
size
number
default 16
A drop's radius, in CSS pixels.
rain
number
default 0
Seeded rain on the surface, from none at 0 to about eight drops a second on a wide card at 1.
strength
number
default 0.6
How deep a drop dents the surface, 0 to 1.
refraction
number
default 0.5
How far the water bends the picture under it, 0 to 1.
specular
number
default 0.5
The soft highlight on the crests, 0 to 1.
wake
number
default 0.25
The faint wake a mouse leaves as it moves over the water, 0 to 1.
colors
[string, string, string]
default pigments mixed from --accent and --signal with the background
The generated tiles' deep water, shallow water and grout-and-lane colours, resolved on the element.
tile
number
default 28
The generated tiles' size, in CSS pixels.
resolution
number
default 0.5
The simulation's resolution as a share of the box, 0.25 to 1.
interactive
boolean
default true
Presses, drags, the mouse and the keyboard disturb the water; off, it is an image.
label
string
default "Water surface"
The surface's accessible name.
seed
number
default 9
Seed for the tiles' tones and the rain.
dpr
number
default 2
The highest device pixel ratio the canvas draws at (never above 2).
paused
boolean
default false
Freeze the water where it is.
sound
boolean
default false
Play a plip for each drop the visitor makes (never for rain).
onDrop
(x: number, y: number) => void
default —
Fires when the visitor drops into the water, with the point as fractions of the box.
className
string
default —
Classes for the box; set its height here (default h-56).