# Your first opening

A card opening needs three things from you: the cards, which of them are already opened, and somewhere on the page for a card to leave from. This page builds the smallest one that works, then swaps it for the whole hunt in one line.

> Live preview: see it play at https://bettertyped.github.io/react-cards-opening/docs/first-opening/
>
> What this page builds. Press the card.

## Describe the cards

A card is an `id` and a `rarity`. The ready-made face also reads a `name`, a `line` of text and `art`, a pixel glyph from the set that ships or one you type out.

`cards.ts`

```tsx
import { GLYPHS, type GlyphCard } from "@react-cards-opening/ui";

export const cards: GlyphCard[] = [
  {
    id: "storm-bolt",
    rarity: "epic",
    name: "Storm Bolt",
    line: "Strikes the same place twice, on purpose.",
    art: GLYPHS.bolt,
  },
];
```

## Open one

`open-a-card.tsx`

```tsx
import { useCardOpening, useOpenedCards } from "@react-cards-opening/core";
import { CardOpening } from "@react-cards-opening/ui";
import { useRef } from "react";
import "@react-cards-opening/ui/styles.css";

import { cards } from "./cards";

export function OpenACard() {
  const button = useRef<HTMLButtonElement>(null);
  // Which cards are opened, remembered on this device under this key.
  const { opened, open } = useOpenedCards("my-deal");
  // The rules: the queue, and what every press means.
  const hunt = useCardOpening({ cards, opened, onOpen: open });

  return (
    <>
      <button ref={button} onClick={() => hunt.start()} disabled={hunt.running || hunt.allOpened}>
        {hunt.allOpened ? "All opened" : "Open a card"}
      </button>
      {/* The reveal. The card flies out of the button. */}
      <CardOpening opening={hunt.opening} launch={() => button.current} />
    </>
  );
}
```

1. `useOpenedCards` keeps the list of opened ids in local storage. Pass `null` to keep it in memory, or bring your own state.
2. `useCardOpening` takes the cards and that list. `start()` queues every card still unopened and opens them one after another.
3. `CardOpening` draws it. `launch` answers where the current card comes out of.

## Give it somewhere to land

A card with nowhere to go fades out where it is. Name an element with `landing` and it shrinks into that instead: a slot in a collection, a counter, a tab.

```tsx
<CardOpening
  opening={hunt.opening}
  launch={() => button.current}
  landing={(card) => document.getElementById(`slot-${card.id}`)}
/>
```

## Or take the whole hunt

If hiding the cards in a grid and scanning for them is what you want, [CardHunt](https://bettertyped.github.io/react-cards-opening/docs/components/card-hunt/) is all of the above plus the grid, the scan button and the list of finds, in one component.

```tsx
import { CardHunt } from "@react-cards-opening/ui";

<CardHunt cards={cards} opened={opened} onOpen={open} levels={levels} />
```

> Live preview: see it play at https://bettertyped.github.io/react-cards-opening/docs/first-opening/
>
> The same idea with five cards and somewhere to hide them.

## Related

- [CardOpening](https://bettertyped.github.io/react-cards-opening/docs/components/card-opening/)
- [useCardOpening](https://bettertyped.github.io/react-cards-opening/docs/core/use-card-opening/)
- [CardHunt](https://bettertyped.github.io/react-cards-opening/docs/components/card-hunt/)
- [Theming](https://bettertyped.github.io/react-cards-opening/docs/theming/)

Source: https://bettertyped.github.io/react-cards-opening/docs/first-opening/
