KQ-1530 · SATIN/RAKE

Satin Rake

A length of satin lying in soft folds, shaded per pixel in one WebGL2 pass: meandering folds crisp in the crease and rounded on the ridge, a wrapped diffuse that keeps the dye rich in the troughs, and an anisotropic sheen whose lobe runs long along each fold, so the highlights streak down the ridges. The light is a lamp a little above the cloth that sweeps slowly back and forth on its own; the pointer takes it (where on springs.glide, how much on springs.drift) and raking it over a trough turns the trough's walls to the light, while a click sends one slow wave rolling out through the cloth, lifting and kinking every fold it crosses. One slider under the content steers the lamp from the keyboard and Enter sends a wave.

KQ-1530 · SATIN/RAKE

Arrow keys move the lamp across the satin; Enter sends a wave through it.

Fernworks Atelier

Duchess satin, cut to order

Fourteen dyes, finished by hand

lamp sweeping · 7 folds, sheen 0.70

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/satin-rake

Props

children
React.ReactNode
default —
The content on top of the satin: a headline, a product plate, a call to action.
foldCount
number
default 7
How many long folds lie across the cloth, 3 to 14.
sheen
number
default 0.7
How strongly the ridges streak with sheen, 0 (matte silk) to 1 (liquid satin).
tint
"cobalt" | "ivory" | "rose" | "jade" | string
default "cobalt"
The dye: a named satin or any CSS colour. Named dyes hold their lightness, so the cloth is the same on a light and a dark page.
angle
number
default -28
The direction the folds run, in degrees from horizontal (negative rises to the right).
softness
number
default 0.55
The folds' profile, 0 (pressed creases) to 1 (soft rolls).
depth
number
default 0.6
How deep the folds are, 0 (nearly flat) to 1 (deep drape).
lampHeight
number
default 0.3
How high the lamp hangs over the cloth, 0 (raking, deep shadows) to 1 (overhead, even light).
reach
number
default 0.6
The size of the lamp's pool of light, as a share of the box's diagonal, 0.2 to 1.
sweep
number
default 9000
One slow return trip of the unattended lamp, in ms.
waveStrength
number
default 0.6
How high a click's wave lifts the cloth, 0 (no waves) to 1.
waveSpeed
number
default 180
How fast a wave rolls out through the cloth, px per second.
interactive
boolean
default true
The pointer and keys steer the lamp, and a click sends a wave.
paused
boolean
default false
Hold the unattended lamp still; the hand and waves still move.
seed
number
default 1
Seeds the drape, so two lengths of satin never fold alike.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
label
string
default "Steer the lamp"
The accessible name of the lamp control.
onWave
(origin: { x: number; y: number }) => void
default —
Fires when a click or Enter sends a wave, with its origin as shares of the box (0 to 1).
onActiveChange
(active: boolean) => void
default —
Fires when the pointer or the keyboard takes the lamp (true) or hands it back to its sweep (false).
className
string
default —
Sizes and shapes the box; it fills its parent by default (h-full w-full).