Open from a button
No grid, no scan, no collection. A button deals one card from a pool, weighted by rarity, and the reveal comes out of the button. This is the shape of a daily reward, a loot drop after a level, or a thank-you after a purchase.
The example below, with a card in place of the button so it has somewhere to land.
The code
import { rollCards, useCardOpening } from "@react-cards-opening/core";
import { CardOpening } from "@react-cards-opening/ui";
import { useRef, useState } from "react";
import "@react-cards-opening/ui/styles.css";
import { pool } from "./cards";
export function DailyCard({ userId, today }: { userId: string; today: string }) {
const button = useRef<HTMLButtonElement>(null);
// The same person gets the same card all day, on any device.
const [cards] = useState(() => rollCards({ pool, count: 1, seed: `${userId}:${today}` }));
const [opened, setOpened] = useState<string[]>([]);
const hunt = useCardOpening({ cards, opened, onOpen: (id) => setOpened((now) => [...now, id]) });
return (
<>
<button ref={button} onClick={() => hunt.start()} disabled={hunt.running || hunt.allOpened}>
{hunt.allOpened ? `You got ${cards[0].name}` : "Open today's card"}
</button>
<CardOpening opening={hunt.opening} launch={() => button.current} />
</>
);
}Notes
- The roll is seeded with the person and the day, so a reload cannot reroll it. For a card that is worth something, roll on your server instead.
- There is no
landing, so the card fades out where it is once it has been read. Add one to send it to a counter or a collection. - A press on the card turns it early, a second press sends it away. Nothing here had to say so.
Show the odds
import { chances } from "@react-cards-opening/core";
const odds = chances(pool);
<ul>
{pool.map((card) => (
<li key={card.id}>
{card.name}: {(odds.get(card.id)! * 100).toFixed(1)}%
</li>
))}
</ul>