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 background of dense parallel lines in the spirit of Bridget Riley: they ripple in slow waves, swell from hairline to heavy across the field and bulge around the cursor or a wandering focus. Ink and paper colors, line count, angle, wave, weight, contrast, speed and pull are all props. Lines stay crisp at any size, the resolution adapts to the device, it pauses offscreen, holds a still frame for reduced motion and falls back to CSS stripes without WebGL.
The import and the props worth knowing about, in one place.
import { OpArt } from "@/components/beste/component/op-art";
// As a layer behind content
<section className="relative min-h-[40rem]">
<OpArt className="absolute inset-0" />
<div className="relative">...</div>
</section>
<OpArt
className="min-h-[32rem]"
inkColor="var(--primary)" // any CSS color, tokens included
paperColor="var(--background)"
lines={48} // lines across the height
angle={-12} // rotation, in degrees
wave={0.8} // ripple, 0 to 1
weight={0.3} // average thickness, 0 to 1
contrast={0.9} // thin to heavy swing, 0 to 1
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
inkColor | string | — | Color of the lines. Any CSS color, tokens included. |
paperColor | string | — | Color between the lines. |
lines | number | — | Number of lines across the height. |
angle | number | — | Rotation of the line field, in degrees. |
wave | number | — | How far the lines ripple, 0 to 1. |
weight | number | — | Average line thickness, 0 (hairline) to 1 (solid). |
contrast | number | — | How much lines swell from thin to heavy across the field, 0 to 1. |
speed | number | — | Motion speed, 1 is the default pace. |
interactive | boolean | — | Lines bulge around the cursor; a wandering focus takes over when it leaves. |
pull | number | — | Strength of the bulge, 0 to 1. |
paused | boolean | — | Freeze the field on its current frame. |
className | string | — | |
children | ReactNode | — |