Ripple
BackgroundsRings expand from a point and fade, one after another, like a pulse.
Draws a water surface in halftone. It runs the wave equation on the GPU (a height field and its previous step), so a drop spreads into rings that cross, interfere and settle, and the edges absorb them. The cursor drops ripples along its path, a wake of rings behind it; while it rests, a light rain falls around the focus. The steepness of the surface sizes a dot per cell, in two tones on the page's ground; `dots` 0 draws a smooth surface. Every constant is a custom property re-read when the element's style changes. Without WebGL2 or a colour-renderable float texture, or without JavaScript, still rings stand in. Fills its positioned parent.
Ripples.
move your cursor
Live, from the library itself: scroll, hover, navigate away and back. The demo is never gated.
Adjust · props are custom properties, set inline, so you edit the running instance
JavaScript with its libs
10.8 kB raw
2.3 kB raw of its own, 1.3 kB gzip. The rest is the runtime, the canvas helper and the GL core, loaded once for every effect on the page.
CSS 5.3 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Chrome 56 · Firefox 51 · Safari 15; needs webgl2. Elsewhere: without WebGL2 or a colour-renderable float texture (EXT_color_buffer_float), still rings around the focus.
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
npx shadcn@latest add @moonarc-pro/wave-field<section class="relative min-h-[70vh]">
<WaveField color="var(--primary)" />
<h1 class="relative">Ripples on a halftone surface</h1>
</section>Without a key the registry answers 401 with an upgrade message. Related free primitives: ripple.
| Prop | Type | Default | Description |
|---|---|---|---|
color | string | 'oklch(0.62 0.19 262)' | Dot colour; any CSS colour, theme tokens included. Re-read when the theme changes. |
core | string | color lifted 50 % toward white | The second tone: the colour on the steepest wave fronts. |
dots | number | 6 | Halftone cell in CSS px; 0 draws a smooth surface. |
speed | number | 1 | Wave speed: 60 simulation steps a second at 1. Fixed steps, so the rings travel at the same pace at any frame rate. |
settle | number | 0.65 | How fast ripples die out, per second. 0.3 lets them cross the box; 1.5 keeps them local. |
drop | number | 1 | How deep the pointer drops into the surface; 0 turns the pointer off. |
rain | number | 1.1 | Ambient drops per second while the pointer has rested for 1.5 s; 0 is a still pool. |
focus | string | '0.7 0.55' | Where the rain falls and the fallback rings sit, as fractions of the box (x y, from the top-left). |
No loop and no rain: three drops settle for a second of simulation and are drawn once, as a still. The pointer does not stir it.
ClientRouterBound through the shared runtime: the frame loop, observers and the pointer listener are released before the swap and the WebGL context is lost on purpose after it, so the GPU memory goes with the page; five round trips leave one context. Under transition:persist the canvas keeps its context and starts again on the next page.
Replaces: Water ripple effect (jQuery ripples) · Ripple shader backgrounds. See the migration table.
Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown