KQ-1865 · TABLE/SPREAD
Table Spread
A deck squared on a felt table that sweeps into a long, even line under the hand: every card the hand passes is left at its slot while the rest ride on beneath it, and a release commits by projection on springs.glide carrying the hand's velocity. Flicking the first card sends a turnover wave down the spread — each card lifting, turning about its long edge in perspective and landing as the front passes, at turnSpeed cards a second — while a hovered card raises its edge on springs.flick and a picked card steps out of the line and flips face up on springs.snap. The cards are real buttons in a roving tabindex: arrows and Home/End move, Enter picks, T turns the spread over and Escape gathers the deck.
Fernworks card room · pick a card
Drag the deck to the right to spread it, or press Enter. In the spread, arrow keys move between cards, Enter picks a card, T turns the whole spread over and Escape gathers the deck. Flick the first card to the right to turn the spread over.
deck squared · drag it across the felt
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/table-spread
Props
- cards
- TableSpreadCard[]
- default defaultTableSpreadCards
- The deck, bottom card first: { id, rank, suit }. Fifteen seeded cards by default.
- spacing
- number
- default 0.4
- How much of each card shows in the spread, as a fraction of its width; a narrow table tightens it to fit.
- turnSpeed
- number
- default 22
- How fast the turnover wave runs along the spread, in cards per second.
- felt
- "green" | "navy" | "claret" | "slate" | string
- default "green"
- The cloth: a preset pigment or any CSS colour.
- backColor
- string
- default a claret pigment
- The colour printed on the card backs, any CSS colour.
- spread / defaultSpread
- boolean
- default false
- Whether the deck lies spread across the table.
- onSpreadChange
- (spread: boolean) => void
- default —
- Fires from the sweep, tap or key that spread or gathered the deck.
- faceUp / defaultFaceUp
- boolean
- default false
- Whether the spread lies face up. A host that changes it gets the same wave a flick would.
- onFaceUpChange
- (faceUp: boolean) => void
- default —
- Fires when a turnover wave the visitor started has turned the whole spread.
- picked / defaultPicked
- string | null
- default null
- The id of the card picked out of the line, or null.
- onPickedChange
- (id: string | null) => void
- default —
- Fires from the tap or key that picked a card or put it back.
- lift
- number
- default 6
- How far a hovered card's edge rises, px.
- intro
- boolean
- default false
- Spread the deck by itself the first time it comes into view, silently.
- label
- string
- default "Deck of cards"
- The table's accessible name.
- sound
- boolean
- default false
- Paper sounds for the sweep, each card the wave lands and the pick.
- disabled
- boolean
- default false
- Shows the table as it is; nothing sweeps, turns or picks.
- className
- string
- default "h-56"
- Size the table with a height class; the cards follow its height and the spacing tightens to fit its width.
| Prop | Type | Default | Description |
|---|---|---|---|
| cards | TableSpreadCard[] | defaultTableSpreadCards | The deck, bottom card first: { id, rank, suit }. Fifteen seeded cards by default. |
| spacing | number | 0.4 | How much of each card shows in the spread, as a fraction of its width; a narrow table tightens it to fit. |
| turnSpeed | number | 22 | How fast the turnover wave runs along the spread, in cards per second. |
| felt | "green" | "navy" | "claret" | "slate" | string | "green" | The cloth: a preset pigment or any CSS colour. |
| backColor | string | a claret pigment | The colour printed on the card backs, any CSS colour. |
| spread / defaultSpread | boolean | false | Whether the deck lies spread across the table. |
| onSpreadChange | (spread: boolean) => void | — | Fires from the sweep, tap or key that spread or gathered the deck. |
| faceUp / defaultFaceUp | boolean | false | Whether the spread lies face up. A host that changes it gets the same wave a flick would. |
| onFaceUpChange | (faceUp: boolean) => void | — | Fires when a turnover wave the visitor started has turned the whole spread. |
| picked / defaultPicked | string | null | null | The id of the card picked out of the line, or null. |
| onPickedChange | (id: string | null) => void | — | Fires from the tap or key that picked a card or put it back. |
| lift | number | 6 | How far a hovered card's edge rises, px. |
| intro | boolean | false | Spread the deck by itself the first time it comes into view, silently. |
| label | string | "Deck of cards" | The table's accessible name. |
| sound | boolean | false | Paper sounds for the sweep, each card the wave lands and the pick. |
| disabled | boolean | false | Shows the table as it is; nothing sweeps, turns or picks. |
| className | string | "h-56" | Size the table with a height class; the cards follow its height and the spacing tightens to fit its width. |