KQ-1355 · DEPOT/BOARD
Depot Board
A split-flap departure board: each cell flips its top flap down over a hinge with real flap physics — integrated under gravity, slow off the top and fast at the bottom, landing on the stop with a small bounce before it rests — through its character ring one flap at a time until it reaches its letter, columns a ripple apart so the board settles in a wave, and only the cells whose letter changes move at all. Messages cycle once the board has settled and rested; the board is a button, so a press, Enter or Space shows the next message and Left/Right step back and forth, with the visitor's flips clacking when sound is on and the message announced once it settles.
flipping · 1 of 4 · Coldbrook 09:15 plat 4
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/depot-board
Props
- messages
- string[]
- default —
- The messages the board cycles through; "\n" forces a new row and longer rows wrap between words.
- index / defaultIndex
- number
- default 0
- The message showing, controlled or initial.
- onIndexChange
- (index: number) => void
- default —
- Fires from whatever changed the message — the timer, a press or a key — with the new index.
- interval
- number
- default 3600
- How long a settled message stays before the next, ms; 0 changes only by hand.
- speed
- number
- default 1
- Flip speed, 0.5 to 2: how fast each flap falls and how fast the motor feeds the next.
- cells
- number
- default 14
- Columns on the board; the type scales so they always fit.
- rows
- number
- default —
- Rows on the board; by default as many as the longest message needs.
- ripple
- number
- default 28
- Delay from one column to the next, ms, so the board settles in a wave.
- ring
- "letters" | "digits" | "full"
- default "full"
- The characters each cell's flaps carry, in order: letters, digits, or both with punctuation.
- size
- number
- default 40
- The tallest a cell may be, px; narrow boards scale cells down to fit.
- align
- "start" | "center"
- default "start"
- Where a row's words sit.
- color
- string
- default "var(--foreground)"
- The letters.
- flapColor
- string
- default "color-mix(in oklab, var(--foreground) 6%, var(--card))"
- The flaps.
- paused
- boolean
- default false
- Hold the current message: the timer stops, a press still changes it.
- interactive
- boolean
- default true
- The board is a button: a press or Enter shows the next message, Left and Right step through them.
- trigger
- "mount" | "inView" | "hover" | "manual"
- default "inView"
- When the first message clatters in from blank: on mount, when scrolled into view, on hover or keyboard focus, or — manual — when you control index or on the first press.
- once
- boolean
- default false
- Cycle through the messages once and rest on the last.
- delay
- number
- default 150
- Wait before the first clatter, ms.
- sound
- boolean
- default false
- Clack each flap the visitor sets falling, throttled; the timer's changes are silent.
- caption
- React.ReactNode
- default —
- A line set into the housing above the cells — a title, a clock; it takes the board's width and never widens it.
- label
- string
- default "Departures"
- The board's accessible name.
- as
- "div" | "section" | "aside" | "figure"
- default "div"
- The element rendered around the board.
- onComplete
- (index: number) => void
- default —
- Fires each time the board settles on a message, with its index.
- className
- string
- default —
- Classes for the outer element.
| Prop | Type | Default | Description |
|---|---|---|---|
| messages | string[] | — | The messages the board cycles through; "\n" forces a new row and longer rows wrap between words. |
| index / defaultIndex | number | 0 | The message showing, controlled or initial. |
| onIndexChange | (index: number) => void | — | Fires from whatever changed the message — the timer, a press or a key — with the new index. |
| interval | number | 3600 | How long a settled message stays before the next, ms; 0 changes only by hand. |
| speed | number | 1 | Flip speed, 0.5 to 2: how fast each flap falls and how fast the motor feeds the next. |
| cells | number | 14 | Columns on the board; the type scales so they always fit. |
| rows | number | — | Rows on the board; by default as many as the longest message needs. |
| ripple | number | 28 | Delay from one column to the next, ms, so the board settles in a wave. |
| ring | "letters" | "digits" | "full" | "full" | The characters each cell's flaps carry, in order: letters, digits, or both with punctuation. |
| size | number | 40 | The tallest a cell may be, px; narrow boards scale cells down to fit. |
| align | "start" | "center" | "start" | Where a row's words sit. |
| color | string | "var(--foreground)" | The letters. |
| flapColor | string | "color-mix(in oklab, var(--foreground) 6%, var(--card))" | The flaps. |
| paused | boolean | false | Hold the current message: the timer stops, a press still changes it. |
| interactive | boolean | true | The board is a button: a press or Enter shows the next message, Left and Right step through them. |
| trigger | "mount" | "inView" | "hover" | "manual" | "inView" | When the first message clatters in from blank: on mount, when scrolled into view, on hover or keyboard focus, or — manual — when you control index or on the first press. |
| once | boolean | false | Cycle through the messages once and rest on the last. |
| delay | number | 150 | Wait before the first clatter, ms. |
| sound | boolean | false | Clack each flap the visitor sets falling, throttled; the timer's changes are silent. |
| caption | React.ReactNode | — | A line set into the housing above the cells — a title, a clock; it takes the board's width and never widens it. |
| label | string | "Departures" | The board's accessible name. |
| as | "div" | "section" | "aside" | "figure" | "div" | The element rendered around the board. |
| onComplete | (index: number) => void | — | Fires each time the board settles on a message, with its index. |
| className | string | — | Classes for the outer element. |