CardWheel
CardWheel is the wheel of a daily spin. Wedges in their tiers' colours turn under a pointer that is knocked aside by each one that passes. The wheel slows, stops on a card, the winning wedge lights up, and the card lifts out of it into the reveal. One press is one spin.
5 spins left.
Every spin lands on one of your cards.
- Not won yet
- Not won yet
- Not won yet
- Not won yet
- Not won yet
Press Spin, or the middle of the wheel.
Usage
import { useOpenedCards } from "@react-cards-opening/core";
import { CardWheel } from "@react-cards-opening/ui";
function DailySpin({ won, catalog }) {
const { opened, open } = useOpenedCards("spin:2026-10-11");
return <CardWheel cards={won} pool={catalog} opened={opened} onOpen={open} />;
}The wheel decides nothing
cards is what was won, decided before anything moves: deal it with rollCards on your server. pool is what goes on the wheel. Every card of the pool gets a wedge while there is room, and the wedge under the pointer at the end is always the card that was dealt. What is on the wheel stays the same from spin to spin, and it is laid out from a seed, so a server and a browser draw the same wheel.
Props
| Prop | Type | What it does |
|---|---|---|
cards | readonly C[] | What was won, in the order the spins stop on them. |
opened | readonly string[] | Ids already won on the wheel. |
onOpen | (id: string) => void | A card was turned face up for the first time. |
pool? | readonly C[] | What is on the wheel. The deal itself when left out. |
segments? | number | How many wedges the wheel has, from four to twelve. Eight when left out. |
theme? | CardTheme | The colours. moss in the dark when left out. |
rarities? | readonly RarityTier[] | Your tiers. The six defaults when left out. |
actions? | ReactNode | Extra buttons in the header, next to the spin button. |
onRunChange? | (running: boolean) => void | A spin started or came to rest. |
labels? | Partial<CardWheelLabels> | Every word in the panel, and what the hub says. |
landing? | (card) => HTMLElement | null | Where a won card lands, instead of its badge here. |
renderFace? | (card, info) => ReactNode | The front of the card, instead of the ready-made face. |
renderBack? | (card) => ReactNode | The back of the card. |
readingOf? | (card, info) => readonly string[] | The text on a face of your own, so the card stays up long enough to read. |
effects? | EffectPlan | false | What each tier plays on top of the card's own reveal. The signature shows when left out, false for none. |
className? | string | A class for the panel. |
classNames? | CardWheelClassNames | A class of your own for each part: the panel's, the wheel's and the reveal's. |
style? | CSSProperties | Inline styles for the panel. |
PrizeWheel on its own
CardWheel is PrizeWheel and CardOpening wired to useCardOpening. When the layout is yours, take the wheel alone. Its handle has one call: spin plays the wheel and hands back what launch on CardOpening takes. Whatever you put inside it sits in the hub.
import { CardOpening, PrizeWheel, type PrizeWheelHandle } from "@react-cards-opening/ui";
const wheel = useRef<PrizeWheelHandle>(null);
<PrizeWheel handle={wheel} winner={hunt.current} pool={catalog} segments={10}>
<button onClick={() => hunt.start()}>Spin</button>
</PrizeWheel>
<CardOpening opening={hunt.opening} launch={(card, show) => wheel.current?.spin(show) ?? null} />| Prop | Type | What it does |
|---|---|---|
winner | C | null | The card the next spin stops on. With none, the wheel shows what could come up and waits. |
pool | readonly C[] | What is on the wheel: every card that could have come up. |
segments? | number | How many wedges, from four to twelve. Eight when left out. |
theme? | CardTheme | The colours. |
rarities? | readonly RarityTier[] | Your tiers. |
handle? | Ref<PrizeWheelHandle> | spin(show, { flash, onLock }): plays the wheel and answers a launch. |
children? | ReactNode | What sits in the hub: a count, a button, a logo. |
className? | string | A class for the wheel's root. |
classNames? | PrizeWheelClassNames | A class of your own for each part of the wheel. |
style? | CSSProperties | Inline styles for the root: the place for --rco-wheel-size. |
Parts and variables
| Key | The library's class | The part |
|---|---|---|
wheel | .rco-wheel | The wheel's root. className on a PrizeWheel used alone. |
disc | .rco-wheel-disc | The disc that turns. |
wedge | .rco-wheel-wedge | Every wedge. The winner also gets data-won. |
prize | .rco-wheel-prize | What a wedge holds: the card's glyph. |
pointer | .rco-wheel-pointer | The pointer the wheel stops under. |
hub | .rco-wheel-hub | The middle of the wheel. |
wheelGlow | .rco-wheel-glow | The light behind the wheel once it has stopped, in the winner's colour. |
| Key | The library's class | The part |
|---|---|---|
root | .rco-panel | The panel. The same as className. |
flash | .rco-panel-flash | The flash over the whole panel on a loud card. |
head | .rco-panel-head | The row that holds the words and the buttons. |
headline | .rco-panel-headline | The headline. |
subline | .rco-panel-subline | The line under it. |
actions | .rco-panel-actions | The buttons' row. |
mainButton | .rco-button-main | The main button: Spin, or Open the case. |
sideButton | .rco-button-skip | Take all during a run, and the replay button after it. |
finds | .rco-finds | The list of badges. |
badge | .rco-badge | Each badge, won or not. A won one is a button. |
badgeArt | .rco-badge-art | The little glyph's box in a badge. |
badgeName | .rco-badge-name | The card's name in a badge. |
badgeWhere | .rco-badge-where | The second line of a badge. |
| Variable | What it sets | When left out |
|---|---|---|
--rco-wheel-size | The wheel's width. Everything on it scales with this. | 360px |