Scanner
The scanner is the part of a Wrapped people come back to. Some scenes of the video start out hidden somewhere in the year: achievements that were earned, an easter egg or two. A beam sweeps the calendar, locks onto a day, a card flies out and turns over, and that scene joins the video. Use it when part of the story should be found, not just watched.
Your year is hiding 4 scenes.
Achievements you earned and a few easter eggs. Each one joins your video when the scan finds it.
- Still hidden
- Still hidden
- Still hidden
- Still hidden
Press the button. Click a card to turn it, click again to add it.
Installation
pnpm add @react-wrapped/scan @react-wrapped/core gsapimport "@react-wrapped/core/styles.css";
import "@react-wrapped/scan/styles.css";What is in it
- YearScanThe panel: the year, the beam, the cards and the list of finds.
- Rarity and dropsWhat a hidden scene is, the four rarities, and which drops a year gets.
- useOpenedDropsRemembers what was opened, on this device or for this visit.
How a find becomes a scene
- You decide which scenes are hidden and describe each as a
HiddenDrop: a name, a rarity, a line and pixel art. - The scan gets all of them in
dropsand the ids already opened infound. - When a card is turned over the scan calls
onOpen(id). - You add the id to
foundand build your scenes again, this time with that drop's scene in them. Give that scene the keydrop-followed by the drop's id. - The player rebuilds only what changed, and the card flies to the timeline segment with that key.
So a drop is never a special kind of scene. It is an ordinary scene, usually a fact scene, that your code leaves out until its id is in found.
Scan first
For someone's own year the scan can come before the video. With opening.gate on WrappedView, a creator who has opened nothing gets the scan as the whole page. It says "Your Wrapped is almost ready." and offers one button. When the scan has run and found something, the video takes its place and the scan moves under it. Anyone who has scanned before, and anyone only watching a shared link, gets the video straight away.
The whole page, starting from the scan.
import { useMemo, useState } from "react";
import {
type CalendarLevels,
DEFAULT_WRAPPED_CONFIG,
type HiddenDrop,
type SceneInstance,
useOpenedDrops,
type WrappedConfig,
type WrappedSubject,
WrappedView,
} from "@react-wrapped/kit";
/** What your director returns for one year, given the drops opened so far. */
interface Cut {
subject: WrappedSubject;
seed: string;
/** The story, with a scene for every drop that has been opened. */
scenes: readonly SceneInstance[];
calendar: CalendarLevels;
/** Every hidden scene, found or not. */
drops: readonly HiddenDrop[];
}
export function ScanFirst({
direct,
describeDay,
storageKey,
}: {
direct: (opened: readonly string[]) => Cut;
describeDay: (day: number) => string;
/** Where the opened drops are remembered on this device. Null keeps them for this visit only. */
storageKey: string | null;
}) {
const [config, setConfig] = useState<WrappedConfig>(DEFAULT_WRAPPED_CONFIG);
const { opened, open, ready } = useOpenedDrops(storageKey);
// Directed again whenever a drop is opened: that is how a found scene gets into the video.
const cut = useMemo(() => direct(opened), [direct, opened]);
// Until storage has been read, nobody knows whether this creator has scanned before.
if (!ready) return null;
return (
<WrappedView
subject={cut.subject}
seed={cut.seed}
scenes={cut.scenes}
config={config}
onConfigChange={setConfig}
opening={{
calendar: cut.calendar,
drops: cut.drops,
found: opened,
onOpen: open,
describeDay,
// The scan is the page until it has run once. Without this the video plays and the scan sits under it.
gate: true,
}}
/>
);
}opening is everything WrappedView needs to run the scan for you:
| Key | Type | What it does |
|---|---|---|
calendar | CalendarLevels | Handed on to the scan. |
drops | readonly HiddenDrop[] | Handed on to the scan. |
found | readonly string[] | Handed on to the scan. |
onOpen | (id: string) => void | Handed on to the scan. |
describeDay | (day: number) => string | Handed on to the scan. |
actions? | ReactNode | Handed on to the scan. |
sessionKey? | string | null | Handed on to the scan. |
gate? | boolean | Puts the scan first. Until the creator has run it once, the scan is the page and the video is not shown. |
The full example has a switch for both starts. To run the same flow without WrappedView, see build the page from parts.
