Surface study no. 04
A studio for identities that move. We cast brands in liquid metal, then let them settle into something you can hold.
A live WebGL ripple gradient: concentric rings spread from a few slowly wandering points like drops on still water, each ring carrying the next color of the palette outward, blended in Oklab over a calm base color. Where rings from different sources meet they reinforce and cancel, and they fade with distance. Colors, base, source count, ring density, speed, softness, decay, interference, intensity, saturation and film grain are all props and a new palette fades through over a set time. On load the rings spread out of the flat base; it adapts its resolution to the device, pauses offscreen, holds a still frame for reduced motion and falls back to CSS rings without WebGL.
The import and the props worth knowing about, in one place.
import { RippleGradient } from "@/components/beste/component/ripple-gradient";
// As a layer behind content
<section className="relative min-h-[40rem]">
<RippleGradient className="absolute inset-0" />
<div className="relative">...</div>
</section>
// Fine, crisp rings on a dark pool
<RippleGradient
className="min-h-[32rem]"
colors={["#7ee0d1", "#4c8dff", "#c7b8ff"]}
baseColor="#0a1420"
sources={4}
frequency={0.8} // tighter rings
softness={0.2} // thin, crisp lines
interference={0.8}
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
colors | string[] | — | Colors the rings cycle through as they spread, 1 to 6. Any CSS color, tokens included. |
baseColor | string | — | The calm water the rings spread over. |
sources | number | — | Points the rings spread from, 1 to 6. |
frequency | number | — | Ring density, 0 (wide swells) to 1 (tight rings). |
speed | number | — | How fast the rings travel outward, 0 (still) to 3. |
softness | number | — | Ring shape, 0 (thin crisp lines) to 1 (soft swells). |
decay | number | — | How quickly the rings fade with distance, 0 (reach the edges) to 1 (stay close). |
interference | number | — | How strongly crossing rings reinforce and cancel, 0 to 1. |
intensity | number | — | How much the rings color the base, 0 to 1. |
saturation | number | — | Color intensity, 0 (grey) to 2 (vivid). |
grain | number | — | Film grain over the frame, 0 to 1. |
grainSize | number | — | Size of one grain in CSS pixels, 1 to 4. |
grainMotion | boolean | — | Let the grain flicker like film instead of holding still. |
transition | number | — | Seconds a change of `colors` or `baseColor` takes to fade through. 0 swaps at once. |
seed | number | — | Picks a different placement of the sources. |
paused | boolean | — | Hold the rings still. |
className | string | — | |
children | ReactNode | — |