# Scenes

A scene is one beat of the video: something to read, drawn on the frame, with the motion that brings it in. react-wrapped ships eleven of them, enough to tell a whole year. You decide what each one says and in which order they play, and the player does the rest.

- [Opening](https://bettertyped.github.io/react-wrapped/docs/scenes/opening/): 365 cells settling into a year, then the headline.
- [Big number](https://bettertyped.github.io/react-wrapped/docs/scenes/big-number/): The number counts while the year fills in under it.
- [Big day](https://bettertyped.github.io/react-wrapped/docs/scenes/big-day/): One cell of the year, grown to the size of the frame.
- [Bars](https://bettertyped.github.io/react-wrapped/docs/scenes/bars/): Seven columns, the busiest one lit.
- [Chart](https://bettertyped.github.io/react-wrapped/docs/scenes/chart/): A day clock chart inside the chart scene.
- [List](https://bettertyped.github.io/react-wrapped/docs/scenes/list/): Three rows, each measured against the first.
- [Split](https://bettertyped.github.io/react-wrapped/docs/scenes/split/): Four shares of one bar, drawn in a single stroke.
- [Fact](https://bettertyped.github.io/react-wrapped/docs/scenes/fact/): An easter egg: pixel art, the name, its rarity and one line.
- [Persona](https://bettertyped.github.io/react-wrapped/docs/scenes/persona/): Pixel art from the centre out, then the name.
- [Summary](https://bettertyped.github.io/react-wrapped/docs/scenes/summary/): The whole year on one card, held for two and a half seconds.
- [Trophies](https://bettertyped.github.io/react-wrapped/docs/scenes/trophies/): Four trophies found and two still hidden.

## Placing a scene

Every scene is a function with the same two arguments: `scene(props, { key, label })`. The props are what this scene says. The second argument is how the video knows it. The result is a `SceneInstance`, and a video is an array of them.

```tsx
import { barsScene, bigNumberScene } from "@react-wrapped/scenes";

export const scenes = [
  bigNumberScene(
    {
      eyebrow: "This year you made",
      value: 2052,
      title: ["contributions."],
      lede: "That's **5.6 a day**.",
      counter: "climb",
      variant: 0,
    },
    { key: "total", label: "Total contributions" },
  ),
  barsScene(
    {
      eyebrow: "Your week",
      title: ["You ship on", "*Fridays.*"],
      bars: [
        { label: "Thu", value: 352 },
        { label: "Fri", value: 398, peak: true },
        { label: "Sat", value: 84 },
      ],
      lede: "Weekends took **9%** of your work.",
    },
    { key: "week", label: "Your week" },
  ),
];
```

| Key | Type | What it does |
| --- | --- | --- |
| `key` | `string` | The scene's name inside this video, unique among its scenes. Hidden scenes, their order, edits and picked transitions are all stored by it, so do not change it between visits. |
| `label` | `string` | What the timeline and the scene editor call the scene. |
| `drop?` | `"common" \| "rare" \| "epic" \| "legendary"` | Marks a scene that is this person's own find. The timeline colours its segment with that rarity. |
| `locked?` | `boolean` | A scene that was assigned, not written: none of its texts can be rewritten. |

## Text marks

Scene text is plain strings with two marks, so anyone can edit it without an editor. Wrap words in single stars and they take the palette's accent colour. Wrap them in double stars and they are set bold at full strength.

- `title` is an array on most scenes: one entry per line on screen. Each line rises out of its own mask.
- `"You ship on *Fridays.*"` puts the last word in the accent colour.
- `"That's **5.6 a day**."` makes the number bold.

## The calendar

Three scenes draw the year as a grid of cells, the way a contribution graph does: a column per week, seven cells tall. They take it as a `CalendarLevels`: a level from 0 to 4 for each day, oldest first, and `lead`, the number of empty slots before the first day. `calendarFromCounts` makes one from a count per day:

```tsx
import { calendarFromCounts } from "@react-wrapped/core";

// One count per day, oldest first. The second argument is the date of the first count.
const counts = [0, 3, 12, 7, 0, 0, 5];

export const calendar = calendarFromCounts(counts, new Date("2025-10-11"));
```

- A day with nothing is level 0. The others are levels 1 to 4 by quartiles of the active days, so one huge day does not flatten the rest of the year.
- The date is read in UTC, so the server and the browser agree on the weekday.
- The result has `months` too, a short name per month. The [big number scene](https://bettertyped.github.io/react-wrapped/docs/scenes/big-number/) writes them across the top of its grid.
- To build a `CalendarLevels` by hand, a level of -1 leaves a slot empty.

## Variants and the seed

Some scenes take a `variant`, a second layout or entrance, so two videos do not look alike. Others pick small things themselves from the video's seed: which side a list slides in from, how a counter counts. To pick your own variants the same way, draw them from `createRng(seed)`. The same seed then always gives the same video, on every replay and in the exported file.

```tsx
import { createRng } from "@react-wrapped/core";

// One source per video. `fork` gives a part of it its own stream, so adding a choice
// in one scene does not reshuffle the others.
const rng = createRng("ada:2026").fork("director");

export const variant = rng.int(2);
export const eyebrow = rng.pick(["Your biggest day", "The day you went off", "Peak you"]);
```

## How long a scene stays

A scene plays its entrance and then holds. The hold is never shorter than its text takes to read at about 240 words a minute, so a long line keeps its scene up longer and you do not set durations by hand. A scene that is too tall for the frame is scaled down as a whole, to 60 percent at most, before anything animates.

## A scene of your own

All eleven are made with `defineScene`, which is exported too. Give it a `render` and an `animate` and you get a scene function like the ones on this page: it works with every transition, the timeline and the editor. The [custom scene guide](https://bettertyped.github.io/react-wrapped/docs/guides/custom-scene/) builds one from start to finish.

## Related

- [Custom scene](https://bettertyped.github.io/react-wrapped/docs/guides/custom-scene/)
- [Charts](https://bettertyped.github.io/react-wrapped/docs/charts/)
- [Transitions](https://bettertyped.github.io/react-wrapped/docs/transitions/)
- [Player](https://bettertyped.github.io/react-wrapped/docs/player/)
- [Your first Wrapped](https://bettertyped.github.io/react-wrapped/docs/first-wrapped/)

Source: https://bettertyped.github.io/react-wrapped/docs/scenes/
