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 pleated gradient: a smooth multi-color gradient printed across a sheet that is folded like an accordion, blended in Oklab. Every pleat has a lit face and a shaded face from a movable light, soft shadow in the valleys and a thin highlight along the ridges, and the sheet breathes as a slow swell opens and closes the folds while a gentle sway travels down each pleat. Colors, base, fold count, depth, pleat angle, light angle, breathing, sway, sheen, gradient direction, speed, saturation and film grain are all props, and a new palette fades through over a set time. The pleats under the cursor ease open and the light leans toward it. It unfolds softly out of its base color on load, adapts its resolution to the device, pauses offscreen, holds a still frame for reduced motion and falls back to CSS pleat stripes without WebGL.
The import and the props worth knowing about, in one place.
import { FoldGradient } from "@/components/beste/component/fold-gradient";
// As a layer behind content
<section className="relative min-h-[40rem]">
<FoldGradient className="absolute inset-0" />
<div className="relative">...</div>
</section>
// Fine horizontal pleats in a cool palette, lit from above
<FoldGradient
className="min-h-[32rem]"
colors={["#0f2a4a", "#2f6fd6", "#9fd3ff", "#f4f1ea"]}
baseColor="#0f2a4a"
folds={26}
angle={0} // pleats run left to right
lightAngle={90}
depth={0.7}
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
colors | string[] | — | The printed gradient, 1 to 6 colors in order. Any CSS color, tokens included. |
baseColor | string | — | The flat color the sheet unfolds from on load, and the wrapper background. |
folds | number | — | How many pleats cross the frame, 4 to 40. |
depth | number | — | How deep the pleats are and how strongly they shade, 0 (flat) to 1. |
angle | number | — | Direction the pleats run, in degrees (90 = vertical pleats). |
lightAngle | number | — | Direction the light comes from, in degrees (0 = right, 90 = top). |
breathe | number | — | How much the pleats open and close as a slow wave passes across them, 0 to 1. |
wave | number | — | A gentle sway travelling along each pleat, 0 to 1. |
sheen | number | — | Highlight along the ridges, 0 to 1. |
gradientAngle | number | — | Direction of the printed gradient, in degrees (0 = left to right, 90 = bottom to top). |
speed | number | — | How fast the sheet breathes and sways, 0 (still) to 3. |
saturation | number | — | Color intensity, 0 (grey) to 2 (vivid). |
grain | number | — | Film grain over the sheet, 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` takes to fade through. 0 swaps at once. |
seed | number | — | Picks a different phase for the breathing and the sway. |
interactive | boolean | — | The pleats under the cursor ease open and the light leans toward it. |
paused | boolean | — | Hold the sheet still. |
className | string | — | |
children | ReactNode | — |