KQ-1597 · RUBBER/BELT

Rubber Belt

An endless strip of pictures riding a rubber belt: a ring of masses joined by damped springs, one picture driven and the rest following through the rubber, so the strip stretches behind and bunches ahead when it speeds up, and the trailing pictures catch up and bunch when it brakes. Each picture is drawn on its own stretch of belt, its width from the spacing either side and its height answering the other way, so it squashes and stretches with the belt's acceleration and relaxes back to true; a click pulls a picture to the centre on springs.snap with one elastic overshoot the rubber carries down the strip. It is a carousel: arrow keys pull the next picture in, Home and End the first and last, Enter picks the centred one, and a drag, a throw or the wheel drives the belt too.

KQ-1597 · RUBBER/BELT

Fieldline · field notes

Autumn, eight places

Salt flats
Pine ridge
Harbour at dusk
Dune field
Glacier lake
Orchard rows
Basalt coast
Night meadow

Arrow keys pull the next picture to the centre, Home and End the first and last; Enter picks the centred picture. Drag or scroll to drive the belt.

Salt flats · 1 of 8

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/rubber-belt

Props

items
{ src?: string; alt: string; caption?: string }[]
default defaultBeltItems
The pictures on the belt. Without a src the belt draws a landscape of its own; defaultBeltItems holds eight.
elasticity
number
default 0.5
How soft the rubber is, 0 (a stiff belt, almost rigid) to 1 (a soft one that stretches far and wobbles).
gap
number
default 16
Space between pictures at rest, px. The gaps stretch and bunch with the belt.
direction
"left" | "right" | "still"
default "left"
Which way the belt drifts on its own; "still" holds it.
speed
number
default 22
The idle drift's speed, px/s.
squash
number
default 0.6
How much a picture's height answers its stretch, 0 (width only) to 1 (it keeps its area).
itemWidth
number
default —
Picture width, px. By default 30% of the belt's width, between 104 and 176.
aspect
number
default 0.72
Picture height as a share of its width.
value / defaultValue
number
default 0
Index of the picture pulled to the centre. Controlled or initial.
onValueChange
(index: number) => void
default —
Fires from the click, key, drag or wheel that pulls a new picture to the centre.
onSelect
(index: number) => void
default —
Fires when the centred picture is clicked or Enter is pressed on it.
onMotionChange
(state: "drifting" | "held" | "pulling" | "resting") => void
default —
What the belt is doing: drifting on its own, held by a hand or the wheel, pulling a picture in, or at rest.
resumeAfter
number
default 2400
Quiet time after a hand or key before the drift resumes, ms.
wheel
boolean
default true
The mouse wheel and trackpad drive the belt (either axis).
captions
boolean
default true
Show each picture's caption under it, unstretched.
paused
boolean
default false
Hold the idle drift; hands and keys still move the belt.
disabled
boolean
default false
No input at all, and no drift.
label
string
default "Pictures"
The carousel's accessible name.
className
string
default —
Classes on the outer box, which is a size container for the default picture width.