KQ-1474 · OIL/FILM

Oil Film

A background of oil floating on a dark wet ground, its colour computed rather than painted: a WebGL2 shader builds the film's thickness from noise warped by noise and wound into spiral arms, then turns thickness into colour by thin-film interference summed across nine wavelengths, so the colours fall in a puddle's true order — dark where the film is thinnest, deep blue, magenta and gold, pearl where it lies thick. Moving the pointer stirs it with vortex pairs that carry the oil along the stroke and spread as they settle, and a press touches the film like a drop of solvent: a ring spreads on the springs.glide constants and the colours race outward round a dark eye that slowly heals. Keyboard focus on a control inside touches the film behind it.

KQ-1474 · OIL/FILM

Basinworks Finishes

Colour that changes as you pass

Six lacquers, one coat

film 0.45 · swirl 0.50 · drifting

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/oil-film

Props

children
React.ReactNode
default —
The content on top of the film: a hero line, a heading, a call to action.
thickness
number
default 0.45
How thick the oil lies, 0 (a breath of film: deep, dark colour) to 1 (a thick slick: washed pearl).
swirl
number
default 0.5
How far the film is wound into spiral arms, 0 (loose clouds) to 1 (tight whorls).
saturation
number
default 0.7
How much colour the light carries, 0 (pearl and grey) to 1 (full interference colour).
speed
number
default 0.5
How fast the film drifts and winds, 0 (still) to 2.
scale
number
default 360
The size of one patch of colour, px.
sheen
number
default 0.45
A broad soft reflection of the sky across the wet surface, 0 to 1.
ground
string
default —
The wet ground under the oil. Defaults to a dark pigment in the page's hue.
grain
number
default 0.25
A whisper of grain that also hides banding, 0 to 1.
settle
number
default 5200
How long a stir or a touch takes to settle back into the film, ms.
interactive
boolean
default true
The pointer stirs the film and a press touches it; keyboard focus inside touches it too.
pointerStrength
number
default 0.6
How hard the hand stirs, 0 to 1.
radius
number
default 140
How far a stir reaches and how wide a touch's ring spreads, px.
paused
boolean
default false
Hold the film still; the hand still stirs and touches it.
seed
number
default 1
Seeds the film, so two puddles never match.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
onActiveChange
(active: boolean) => void
default —
Fires when the pointer or keyboard focus starts (true) or stops (false) stirring the film.
onTouchFilm
(x: number, y: number) => void
default —
Fires when a press or keyboard focus touches the film, with the point in the box's own px.
className
string
default "h-full w-full"
Sizes and shapes the box.