KQ-1352 · DRUM/WORDS
Drum Words
One word of a sentence on a ratcheted drum: the slot is a window onto a cylinder of faces placed with real 3D transforms about an axis behind the line, so the outgoing word tips away over the top while the next comes up from below foreshortened and shaded. Each change is one detent — a hair backwards on springs.flick as the pawl lifts, then forward on springs.snap, whose single overshoot is the detent catching — and the slot's width follows the word on springs.glide so the sentence glides instead of jumping. The word is a spinbutton: Up/Right, Enter and Space turn it forward, Down/Left back, Home/End to the ends, and a vertical drag turns the drum 1:1 with a throw committing to the detent it was heading for.
Fieldline · maps that work offline
We build maps for
field crews.
turning · 1 of 5 · field crews
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/drum-words
Props
- words
- string[]
- default —
- The words on the drum's faces, in turning order.
- before
- string
- default ""
- The sentence before the slot; end it with "\n" to set the word on its own line so a longer word never re-wraps the sentence.
- after
- string
- default ""
- The sentence after the slot, including any leading space it needs.
- as
- "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div"
- default "h2"
- The element rendered.
- index / defaultIndex
- number
- default 0
- The word showing, controlled or initial.
- onIndexChange
- (index: number) => void
- default —
- Fires from the turn that changed it — the timer, a key, a tap or a throw — with the new index.
- interval
- number
- default 2400
- How long each word rests before the drum turns, ms; 0 turns only by hand.
- depth
- number
- default 0.6
- Drum curvature, 0 to 1: 0 is a nearly flat roll, 1 a tight drum with deep foreshortening.
- width
- "fit" | "widest"
- default "fit"
- "fit" springs the slot to each word so the sentence glides; "widest" holds the widest word so it never moves.
- align
- "start" | "center"
- default "start"
- Where a word sits in a slot wider than it.
- color
- string
- default "var(--accent-bright)"
- The words' colour.
- pauseOnHover
- boolean
- default true
- Hold the drum while the pointer rests on the word.
- paused
- boolean
- default false
- Stop turning on the timer; keys, taps and throws still turn it.
- interactive
- boolean
- default true
- The word is a control: drag or throw it vertically, tap it, or use the arrow keys.
- trigger
- "mount" | "inView" | "hover" | "manual"
- default "inView"
- When the timer runs: from mount, once seen, only while the sentence is hovered or focused, or never (turn by index).
- once
- boolean
- default false
- Turn through the words a single time and rest on the last.
- delay
- number
- default 0
- Extra wait before the first turn, ms.
- sound
- boolean
- default false
- Tick on every detent the visitor turns; the timer's turns are silent.
- onComplete
- () => void
- default —
- Fires when a once cycle comes to rest on the last word.
- className
- string
- default —
- Classes for the sentence; set the type size and colour here.
| Prop | Type | Default | Description |
|---|---|---|---|
| words | string[] | — | The words on the drum's faces, in turning order. |
| before | string | "" | The sentence before the slot; end it with "\n" to set the word on its own line so a longer word never re-wraps the sentence. |
| after | string | "" | The sentence after the slot, including any leading space it needs. |
| as | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div" | "h2" | The element rendered. |
| index / defaultIndex | number | 0 | The word showing, controlled or initial. |
| onIndexChange | (index: number) => void | — | Fires from the turn that changed it — the timer, a key, a tap or a throw — with the new index. |
| interval | number | 2400 | How long each word rests before the drum turns, ms; 0 turns only by hand. |
| depth | number | 0.6 | Drum curvature, 0 to 1: 0 is a nearly flat roll, 1 a tight drum with deep foreshortening. |
| width | "fit" | "widest" | "fit" | "fit" springs the slot to each word so the sentence glides; "widest" holds the widest word so it never moves. |
| align | "start" | "center" | "start" | Where a word sits in a slot wider than it. |
| color | string | "var(--accent-bright)" | The words' colour. |
| pauseOnHover | boolean | true | Hold the drum while the pointer rests on the word. |
| paused | boolean | false | Stop turning on the timer; keys, taps and throws still turn it. |
| interactive | boolean | true | The word is a control: drag or throw it vertically, tap it, or use the arrow keys. |
| trigger | "mount" | "inView" | "hover" | "manual" | "inView" | When the timer runs: from mount, once seen, only while the sentence is hovered or focused, or never (turn by index). |
| once | boolean | false | Turn through the words a single time and rest on the last. |
| delay | number | 0 | Extra wait before the first turn, ms. |
| sound | boolean | false | Tick on every detent the visitor turns; the timer's turns are silent. |
| onComplete | () => void | — | Fires when a once cycle comes to rest on the last word. |
| className | string | — | Classes for the sentence; set the type size and colour here. |