Skip to content
react-wrapped

Graphics gallery

GraphicsGallery is the section under the video where a viewer collects their pictures. Each graphic is a tile on the palette's own background with a download button. A graphic the scan has not found yet is a locked tile, so there is always one more to get.

4 graphics to keep.

Post them, pin them, put them in your README. 2 more unlock as the scan finds them.

Share card

The year on one card, sized for a post.

Long Haul

Contributions per week. The lit stretch is your streak: not one day missed.

Second Wind

This year against last. The ring is where last year ended, the dot is where this one did.

Clean Sheet

June, every day of it. Not one of them empty.

Still hidden

Scan your year to unlock it.

Still hidden

Scan your year to unlock it.

The share card, three insight cards and two that are still locked.

Installation

bash
pnpm add @react-wrapped/graphics @react-wrapped/core gsap
tsx
import "@react-wrapped/core/styles.css";
import "@react-wrapped/graphics/styles.css";

Usage

Describe each graphic as a WrappedGraphic and pass the list with the palette. A graphic can be an image that already has an address, or a function that draws it. Memoize the list: a tile draws its image again whenever its image function changes.

things-to-keep.tsx
import { useMemo } from "react";

import { resolvePalette, type WrappedConfig } from "@react-wrapped/core";
import {
  GraphicsGallery,
  type InsightCardSpec,
  renderInsightCard,
  renderShareCard,
  type ShareCardSpec,
  type WrappedGraphic,
} from "@react-wrapped/graphics";

/** An insight card with a name for its file, and whether the scan still has to find it. */
type Insight = InsightCardSpec & { id: string; locked?: boolean };

export function ThingsToKeep({
  card,
  insights,
  config,
}: {
  card: ShareCardSpec;
  insights: readonly Insight[];
  config: WrappedConfig;
}) {
  const { palette: id, accent, mode } = config;
  const palette = useMemo(() => resolvePalette({ palette: id, accent, mode }), [id, accent, mode]);
  // Each graphic says how to draw itself. Nothing is drawn until its tile is about to scroll into view.
  const graphics = useMemo(
    (): WrappedGraphic[] => [
      {
        id: "share-card",
        title: "Share card",
        line: "The year on one card, sized for a post.",
        image: () => renderShareCard(card, palette),
        fileName: `${card.handle}-wrapped`,
        wide: true,
      },
      ...insights.map((insight) => ({
        id: insight.id,
        title: insight.name,
        line: insight.insight,
        image: () => renderInsightCard(insight, palette),
        fileName: `${card.handle}-${insight.id}`,
        wide: true,
        locked: insight.locked,
      })),
    ],
    [card, insights, palette],
  );
  return <GraphicsGallery graphics={graphics} palette={palette} />;
}

Props

PropTypeWhat it does
graphicsreadonly WrappedGraphic[]The tiles. Unlocked ones are shown first, whatever order you pass.
paletteWrappedPaletteThe video's palette: resolvePalette(config). Each tile sits on its background.
className?stringA class for the gallery's root.
classNames?SlotClassNames<GraphicsGallerySlot>A class per part, by slot name: "gallery-tile", "gallery-download". See styling.

A graphic

KeyTypeWhat it is
idstringStable and unique in the gallery.
titlestringThe tile's heading.
linestringOne line under it.
imagestring | (() => Promise<Blob>)Where the picture comes from: the address of an image, or a function that draws it when the tile is about to be seen.
fileNamestringThe name of the saved file, without an extension. The gallery saves a PNG.
markdown?stringA snippet that embeds the image. With one, the tile gets a second button that copies it.
locked?booleanNot found yet. The tile is shown closed, with nothing to download.
wide?booleanWide artwork, such as a card. The tile takes two columns.

Locked tiles

Set locked on a graphic that belongs to a drop the scan has not found. The tile shows a lock and "Still hidden", the heading counts only what can be taken, and the line under it says how many more are waiting. When the scan finds the drop, pass the graphic again without locked and its tile draws itself.

Drawing and downloading

  • A tile draws its image when it is about to scroll into view, not when the page loads. A gallery of ten cards three screens down costs nothing until someone gets there.
  • Download saves a PNG named fileName. An image given by address is fetched and redrawn at twice its size first, so an SVG badge becomes a PNG people can post.
  • With markdown set, a second button copies that snippet. Use it for images you host, such as a badge for a README that should stay live.
  • A graphic with wide takes two columns. The grid is one column on a phone, two on a tablet and four on a wide screen.

Last updated . Read this page as Markdown.