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