Skip to content
react-wrapped

Rarity and drops

A drop is a scene that starts out hidden: an achievement the year earned, or an easter egg handed out by luck. Each has a rarity, common, rare, epic or legendary, and the rarity decides its colour everywhere it shows up. This page covers the data a drop is made of and how one turns into a scene.

Common#8b949e
Rare#39c5cf
Epic#c5e85b
Legendary#f2cc60
Long HaulAchievement, Epic
Second WindAchievement, Epic
Clean SheetAchievement, Epic
Comet DragonEaster egg, Legendary

The four rarities in the current palette, then the sample year's drops.

The four rarities

RarityLabelColour variable
commonCommon--wr-common
rareRare--wr-rare
epicEpic--wr-epic
legendaryLegendary--wr-legendary

RARITY_LABELS maps each rarity to its word. The colours are not fixed: every palette brings four that sit well on it, in palette.rarity, and the custom palette cuts them from your accent. On a stage, data-rarity on an element sets --wr-rarity for everything inside it, which is how a chart lights its point in the colour of the scene it is in.

rarities.tsx
import type { CSSProperties } from "react";

import { PIXEL_ART, RARITY_LABELS, type Rarity, resolvePalette, type WrappedConfig } from "@react-wrapped/core";
import { type HiddenDrop, PixelGlyph } from "@react-wrapped/scan";

const GRID: CSSProperties = { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 10 };
const TILE: CSSProperties = { display: "grid", gap: 12, padding: 16, borderRadius: 18 };
const NAME: CSSProperties = { display: "block", fontWeight: 650, fontSize: 15 };
const SMALL: CSSProperties = { display: "block", fontSize: 13, fontWeight: 600 };

// Easiest to hardest. The colours are the palette's own, so they change with the theme.
const RARITIES: readonly Rarity[] = ["common", "rare", "epic", "legendary"];

export function Rarities({ drops, config }: { drops: readonly HiddenDrop[]; config: WrappedConfig }) {
  const palette = resolvePalette(config);
  const tile = { ...TILE, background: palette.card, color: palette.fg };
  return (
    <div style={GRID}>
      {RARITIES.map((rarity) => (
        <div key={rarity} style={tile}>
          <PixelGlyph art={PIXEL_ART.trophy} colour={palette.rarity[rarity]} cell={8} />
          <span>
            <b style={NAME}>{RARITY_LABELS[rarity]}</b>
            <small style={{ ...SMALL, color: palette.rarity[rarity] }}>{palette.rarity[rarity]}</small>
          </span>
        </div>
      ))}
      {drops.map((drop) => (
        <div key={drop.id} style={tile}>
          <PixelGlyph art={drop.art} colour={palette.rarity[drop.rarity]} cell={8} />
          <span>
            <b style={NAME}>{drop.name}</b>
            <small style={{ ...SMALL, color: palette.rarity[drop.rarity] }}>
              {`${drop.kind}, ${RARITY_LABELS[drop.rarity]}`}
            </small>
          </span>
        </div>
      ))}
    </div>
  );
}

A hidden drop

HiddenDrop is what the scan knows about a drop: enough to draw its card. The scene itself is yours and stays out of the video until the drop is found.

KeyTypeWhat it is
idstringStable for this drop. found and onOpen speak in ids.
namestringWhat the card and the badge call it.
rarity"common" | "rare" | "epic" | "legendary"How rare it is. Decides the colour and how big a show the card gets.
kindstringThe small word next to the rarity: "Achievement", "Easter egg".
linestringOne line on the back of the card, in this year's own numbers.
artPixelArtNine rows of nine characters: x lit, o half lit, . off.

From a drop to a scene

Build your scenes from the list of opened ids. A drop that has been opened gets a scene, placed with drop set to its rarity (the timeline colours its segment) and with locked (nobody rewrites what was assigned):

tsx
import { PIXEL_ART, RARITY_LABELS, type SceneInstance } from "@react-wrapped/core";
import type { HiddenDrop } from "@react-wrapped/scan";
import { factScene } from "@react-wrapped/scenes";

const DROPS: readonly HiddenDrop[] = [
  {
    id: "long-haul",
    name: "Long Haul",
    rarity: "epic",
    kind: "Achievement",
    line: "48 days in a row without missing one.",
    art: PIXEL_ART.flame,
  },
];

/** The scenes of every drop opened so far. Add them to the story where they belong. */
export function dropScenes(opened: readonly string[]): SceneInstance[] {
  return DROPS.filter((drop) => opened.includes(drop.id)).map((drop) =>
    factScene(
      {
        stamp: RARITY_LABELS[drop.rarity],
        rarity: drop.rarity,
        title: [drop.name],
        description: drop.line,
        art: drop.art,
        variant: 0,
      },
      { key: `drop-${drop.id}`, label: drop.name, drop: drop.rarity, locked: true },
    ),
  );
}

Give a drop's scene a place in the story, not the end of it: put it right after the scene it continues. When the viewer has reordered the cut by hand, arrangeScenes still drops a new scene in after the one you put before it.

Which drops a year gets

cutDrops picks the drops a video really gets out of everything a year qualified for. It follows two rules. At most one easter egg: a video padded with eggs is a run of jokes. And every other drop is an achievement that can draw a picture of its own numbers, with no two drawing the same kind of picture.

ts
import { cutDrops } from "@react-wrapped/scan";

interface Trait {
  id: string;
  kind: "achievement" | "easterEgg";
  /** The chart this achievement would draw for this year, or null when it has none. */
  chart: string | null;
}

export function dropsFor(rolled: readonly Trait[], earned: readonly Trait[]): Trait[] {
  // `drops` is what was rolled: its length is how many slots there are, and its egg is the egg.
  // `earned` is every achievement, hardest first. The hardest ones that can be drawn get the slots.
  return cutDrops({ drops: rolled, earned }, (trait) => trait.chart);
}

Last updated . Read this page as Markdown.