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