Ripple Surface
A field of soft concentric rings shaded by a directional light — WebGL sin-ridge height field with four travel modes (outward, inward, breathe, drift), tanh-smoothed ridges, a faded core that kills the seam at the origin, and eight palettes from pearl to obsidian. Pauses when off-screen.
ripple-surface
Lazy-ui
Ripple
Build quietly.
Concentric rings carved by a single directional light — tanh-smoothed ridges and a faded core keep the surface clean from edge to edge.
0px
Customize
Edit props; preview updates instantly.
Customize
Palette
Effect
Rings
4
Sharpness
0.30
Depth
1.25
Speed
1.15
Light
130°
Center glow
0.62
Vignette
0.30
Origin X
0.50
Origin Y
0.50
Props
Props accepted by RippleSurface.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | Content rendered above the canvas. Wrapped in `relative z-10 h-full w-full` so centered layouts resolve. |
| palette | "pearl" | "bone" | "linen" | "silver" | "mist" | "ocean" | "graphite" | "obsidian" | "pearl" | Color preset. Each preset is three stops (surface, highlight, shadow). `pearl` matches the soft near-white reference; `bone`/`linen` warm it; `mist`/`ocean` cool it; `graphite`/`obsidian` flip the surface to dark. |
| colors | [string, string, string] | — | Custom palette as `[surface, highlight, shadow]`. Accepts hex or `rgb()`/`rgba()`. Overrides `palette`. |
| effect | "outward" | "inward" | "breathe" | "drift" | "outward" | Animation pattern. `outward` and `inward` travel rings across the surface. `breathe` freezes the rings and pulses the shading intensity. `drift` keeps the rings still and rotates the light direction slowly. |
| speed | number | 1 | Animation speed multiplier. `0` freezes the surface on its starting pose. Reduced-motion users see a static radial gradient fallback regardless. |
| rings | number | 9 | Number of visible ring crests across the radius. More rings pack the surface tighter; fewer give big, lazy arcs. |
| sharpness | number | 1 | Ridge sharpness (0.2–4). Higher values pinch each ridge into a thinner, more defined band; lower values blur the ridges into a smooth gradient. |
| depth | number | 1 | Shading contrast (0–3). Drives how strongly each ridge picks up the directional highlight and shadow. `0` leaves a flat surface with only the center sheen and vignette. |
| lightAngle | number | 315 | Light direction in degrees. `0` = light from the right, `90` = below, `315` = top-right (the default — matches the canonical light-from-above-left look). |
| centerGlow | number | 0.18 | Center brightness lift (0–1). Subtle radial highlight pulled toward the origin — simulates an overhead key light catching the inner rings. |
| vignette | number | 0.2 | Vignette intensity at the corners (0–1). Fades toward the palette's shadow color in the far edges. |
| originX | number | 0.5 | Horizontal center of the rings, normalized 0–1. `0.5` is the middle, `0` pins the origin to the left edge. |
| originY | number | 0.5 | Vertical center of the rings, normalized 0–1. `0.5` is the middle, `0` pins the origin to the top edge. |
| className | string | — | Extra class names merged onto the outermost wrapper. Width and height are governed here — the canvas fills the container. |
Installation
Choose CLI for the one-line shadcn install, or copy the file manually.
npx shadcn@latest add https://2lazyui.com/r/ripple-surface.json
Usage
Import the component and drop it into a render.
demo.tsx27 lines
import { RippleSurface } from "@/components/lazy-ui/ripple-surface"; export function Demo() { return ( <RippleSurface palette="graphite" effect="drift" rings={4} sharpness={0.3} depth={1.25} speed={1.15} lightAngle={130} centerGlow={0.62} vignette={0.3} className="min-h-[520px] rounded-2xl" > <main className="relative z-10 flex h-full items-center justify-center px-6"> <h1 className="text-5xl tracking-tight text-white" style={{ fontFamily: "'Instrument Serif', serif" }} > Build <span className="italic">quietly.</span> </h1> </main> </RippleSurface> ); }