KQ-1612 · SAND/FURROW

Sand Furrow

A picture buried under fine sand, the sand a heightfield simulated on a coarse grid and shaded per pixel in WebGL2 — directional light, grain, glints, short shadows cast into the furrow and damp edges where it thins. Drag to plough: a bowl-shaped plough cuts down toward the picture and heaps what it cuts onto a bank on each side, the banks round off at their angle of repose, and about a second later they slump back in at the settle pace until the sand lies smooth and the loop stops. Double-click, Enter or Space sweeps the tray clear with a broom front that carries a ridge off the edge; Backspace pours the sand back in; arrow keys plough from a marker.

KQ-1612 · SAND/FURROW

Basinworks dig · trench 4

A floor under the dunes

Drag to plough the sand, or use the arrow keys to plough from the marker; Shift ploughs further. Double-click, Enter or Space sweeps it clear; Backspace pours it back.

buried · drag to plough a furrow

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/sand-furrow

Props

src
string
default —
The buried picture (same origin or CORS-enabled); defaults to a drawn tile mosaic.
alt
string
default "A tile mosaic of a fish among waves"
Describes the picture.
grainSize
number
default 1.5
Size of a grain of sand, 0.5 (silt) to 3 px (coarse).
settle
number
default 0.45
How quickly the banks slump back over the furrow, 0 (never) to 1.
plough
number
default 24
Width of the plough, 8 to 40 px.
depth
number
default 0.9
How much sand one pass moves, 0 to 1; 1 cuts down to the picture.
light
number
default 135
The direction the light comes from, in degrees (0 is from the right, 90 from above).
sandColor
string
default "oklch(from var(--warn) 0.82 0.055 calc(h - 8))"
The sand's colour; a pigment, the same in both themes.
cleared / defaultCleared
boolean
default false
The sand swept clear; controlled or initial.
onClearedChange
(cleared: boolean) => void
default —
Fires from the double-click or key that swept the sand clear or poured it back.
onPlough
(uncovered: number) => void
default —
Fires after each stroke, and again once the banks have settled, with the share of the picture uncovered, 0 to 1.
sound
boolean
default false
A swish as the plough moves and as the sand is swept or poured.
interactive
boolean
default true
Drag, double-click and the keys plough and sweep.
seed
number
default 5
Seeds the dunes and the grain.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
label
string
default "Sand over a picture"
The tray's accessible name; the picture and how much of it shows are added.
className
string
default "h-56 w-full"
Sizes the tray.