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 mesh gradient: up to six colors drift as soft fields that blend in Oklab, so every mix between two hues stays clean and bright instead of going muddy. A fractal domain warp lets the fields flow into each other, a slow swirl twists the center, and a film grain sits on top, held still or flickering like film. Colors, speed, scale, distortion, swirl, softness, saturation, grain amount and size, posterized bands and the seed are all props; a new palette fades through over a set time, and the cursor draws the field toward itself like a soft lens. It grows softly out of its first color on load, adapts its resolution to the device, pauses offscreen, holds a still frame for reduced motion and falls back to soft CSS color pools without WebGL.
The import and the props worth knowing about, in one place.
import { MeshGradient } from "@/components/beste/component/mesh-gradient";
// As a layer behind content
<section className="relative min-h-[40rem]">
<MeshGradient className="absolute inset-0" />
<div className="relative">...</div>
</section>
// A pale, heavily grained pastel with theme tokens
<MeshGradient
className="min-h-[32rem]"
colors={["var(--background)", "#ffd6e0", "#c9e4ff", "var(--primary)"]}
distortion={0.8}
softness={0.8}
grain={0.6}
grainSize={2}
transition={2} // a new palette fades in over 2 seconds
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
colors | string[] | — | The colors of the mesh, 1 to 6. Any CSS color, tokens included. Fewer than 6 repeat around the field. |
speed | number | — | How fast the colors drift, 0 (still) to 3. |
scale | number | — | Size of the color fields, 0.5 (many small) to 2 (few large). |
distortion | number | — | How much the fields warp into each other, 0 (round) to 1 (liquid). |
swirl | number | — | A slow twist around the center, 0 to 1. |
softness | number | — | How softly neighboring colors blend, 0 (crisp edges) to 1 (haze). |
saturation | number | — | Color intensity, 0 (grey) to 2 (vivid). 1 keeps the colors as given. |
grain | number | — | Film grain over the gradient, 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. |
bands | number | — | Posterize the gradient into this many light steps, 2 to 16. 0 keeps it smooth. |
transition | number | — | Seconds a change of `colors` takes to fade through. 0 swaps at once. |
seed | number | — | Picks a different arrangement of the color fields. |
interactive | boolean | — | The field leans toward the cursor and swells under it. |
paused | boolean | — | Hold the gradient still. |
className | string | — | |
children | ReactNode | — |