Skip to content
react-cards-opening

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

tsx
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

PropTypeWhat it does
cardsreadonly C[]What was won, in the order the spins stop on them.
openedreadonly string[]Ids already won on the wheel.
onOpen(id: string) => voidA card was turned face up for the first time.
pool?readonly C[]What is on the wheel. The deal itself when left out.
segments?numberHow many wedges the wheel has, from four to twelve. Eight when left out.
theme?CardThemeThe colours. moss in the dark when left out.
rarities?readonly RarityTier[]Your tiers. The six defaults when left out.
actions?ReactNodeExtra buttons in the header, next to the spin button.
onRunChange?(running: boolean) => voidA spin started or came to rest.
labels?Partial<CardWheelLabels>Every word in the panel, and what the hub says.
landing?(card) => HTMLElement | nullWhere a won card lands, instead of its badge here.
renderFace?(card, info) => ReactNodeThe front of the card, instead of the ready-made face.
renderBack?(card) => ReactNodeThe 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 | falseWhat each tier plays on top of the card's own reveal. The signature shows when left out, false for none.
className?stringA class for the panel.
classNames?CardWheelClassNamesA class of your own for each part: the panel's, the wheel's and the reveal's.
style?CSSPropertiesInline 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.

tsx
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} />
PropTypeWhat it does
winnerC | nullThe card the next spin stops on. With none, the wheel shows what could come up and waits.
poolreadonly C[]What is on the wheel: every card that could have come up.
segments?numberHow many wedges, from four to twelve. Eight when left out.
theme?CardThemeThe colours.
rarities?readonly RarityTier[]Your tiers.
handle?Ref<PrizeWheelHandle>spin(show, { flash, onLock }): plays the wheel and answers a launch.
children?ReactNodeWhat sits in the hub: a count, a button, a logo.
className?stringA class for the wheel's root.
classNames?PrizeWheelClassNamesA class of your own for each part of the wheel.
style?CSSPropertiesInline styles for the root: the place for --rco-wheel-size.

Parts and variables

KeyThe library's classThe part
wheel.rco-wheelThe wheel's root. className on a PrizeWheel used alone.
disc.rco-wheel-discThe disc that turns.
wedge.rco-wheel-wedgeEvery wedge. The winner also gets data-won.
prize.rco-wheel-prizeWhat a wedge holds: the card's glyph.
pointer.rco-wheel-pointerThe pointer the wheel stops under.
hub.rco-wheel-hubThe middle of the wheel.
wheelGlow.rco-wheel-glowThe light behind the wheel once it has stopped, in the winner's colour.
KeyThe library's classThe part
root.rco-panelThe panel. The same as className.
flash.rco-panel-flashThe flash over the whole panel on a loud card.
head.rco-panel-headThe row that holds the words and the buttons.
headline.rco-panel-headlineThe headline.
subline.rco-panel-sublineThe line under it.
actions.rco-panel-actionsThe buttons' row.
mainButton.rco-button-mainThe main button: Spin, or Open the case.
sideButton.rco-button-skipTake all during a run, and the replay button after it.
finds.rco-findsThe list of badges.
badge.rco-badgeEach badge, won or not. A won one is a button.
badgeArt.rco-badge-artThe little glyph's box in a badge.
badgeName.rco-badge-nameThe card's name in a badge.
badgeWhere.rco-badge-whereThe second line of a badge.
VariableWhat it setsWhen left out
--rco-wheel-sizeThe wheel's width. Everything on it scales with this.360px

Last updated . Read this page as Markdown.