# Marks

A mark is the logo in the bottom right corner of the frame: what the year is about. It is not pasted on like a sticker. The stage presses it out of the palette's own colours, lit from the top left, so it belongs to the frame in every theme. Set it with `subject.mark`, from the marks package or from a path of your own.

> Live preview: try it at https://bettertyped.github.io/react-wrapped/docs/marks/
>
> Pick a mark and look at the bottom right corner of the frame.

## Installation

```bash
pnpm add @react-wrapped/marks @react-wrapped/core
```

The package is data only: path strings, no components and no stylesheet. `@react-wrapped/kit` includes it.

## Usage

```tsx
import type { WrappedSubject } from "@react-wrapped/core";
import { markOf } from "@react-wrapped/marks";

export const subject: WrappedSubject = {
  handle: "ada",
  name: "Ada",
  avatarUrl: null,
  caption: "Orbit Wrapped",
  period: "Oct 2025 to Oct 2026",
  mark: markOf("github"),
};
```

Leave `mark` out and the corner keeps its plain pressed discs. The component below is the preview above: every mark as a small SVG, and the picked one pressed into a player's frame.

`mark-picker.tsx`

```tsx
import { type CSSProperties, useMemo, useState } from "react";

import type { SceneInstance, WrappedConfig, WrappedSubject } from "@react-wrapped/core";
import { type MarkId, markOf, MARKS } from "@react-wrapped/marks";
import { WrappedPlayer } from "@react-wrapped/player";

const ROOM: CSSProperties = { display: "grid", height: 520, marginTop: 16 };

const MARK_IDS = Object.keys(MARKS) as MarkId[];

export function MarkPicker({
  subject,
  seed,
  scenes,
  config,
}: {
  subject: WrappedSubject;
  seed: string;
  scenes: readonly SceneInstance[];
  config: WrappedConfig;
}) {
  const [picked, setPicked] = useState<MarkId>(MARK_IDS[0]);
  // The mark is part of who the video is about. `markOf` hands back one path, or one per shape of the mark.
  const marked = useMemo(() => ({ ...subject, mark: markOf(picked) }), [subject, picked]);
  return (
    <div>
      <div role="group" aria-label="Marks">
        {MARK_IDS.map((id) => (
          <button key={id} type="button" aria-pressed={id === picked} onClick={() => setPicked(id)}>
            {/* Every mark is path data in a 24 by 24 box, so it draws as a plain SVG too. */}
            <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden>
              <path d={MARKS[id]} fill="currentColor" />
            </svg>
            {id}
          </button>
        ))}
      </div>
      <div style={ROOM}>
        <WrappedPlayer subject={marked} seed={seed} scenes={scenes} config={config} />
      </div>
    </div>
  );
}
```

## Your own mark

A mark is SVG path data drawn in a box of 24 by 24: the `d` of a `path`. Pass your logo's path as a string. For a logo made of several shapes that should stay apart, pass an array with one path per shape, and each is pressed out on its own.

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

// One shape: a ring with a dot in it. Fill is not needed: the stage colours and lights the mark itself.
export const ORBIT: StageMark =
  "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 3a7 7 0 1 1 0 14 7 7 0 0 1 0-14zm0 4a3 3 0 1 0 0 6 3 3 0 0 0 0-6z";

// Two shapes kept apart: each gets its own edge.
export const TWO_BARS: StageMark = ["M4 4h6v16H4z", "M14 9h6v11h-6z"];
```

- Use a single colour version of the logo. Colours in the artwork are ignored.
- Fill the box. A logo drawn small in the middle of its 24 by 24 comes out small in the corner.
- Keep shapes bold. Hairlines vanish once the mark is pressed into the background.

## What the package exports

| Export | What it is |
| --- | --- |
| `MARKS` | Every mark by id, each as one path string. There are 14. |
| `MarkId` | The ids, as a type. |
| `markOf(id)` | A mark ready for `subject.mark`: one path, or one path per shape for a mark made of several. |
| `MARK_LAYERS` | The marks that are more than one flat shape, back to front, each layer with its own fill for drawing the mark in its own colours. Today: `search-console`. |

## Every mark

The ids in `MARKS`: `github`, `claude`, `openai`, `cursor`, `npm`, `stripe`, `lemon-squeezy`, `polar`, `search-console`, `hacker-news`, `gemini`, `x`, `bluesky`, `reddit`. The picker at the top of this page draws each of them.

> The names and logos belong to their owners. A path in this package is there so a year about that product can show whose year it is. It is not a claim on the mark, and it does not mean the owner endorses this library or your app. Check a brand's own guidelines before you ship its logo.

## Related

- [WrappedPlayer](https://bettertyped.github.io/react-wrapped/docs/player/wrapped-player/)
- [Theming](https://bettertyped.github.io/react-wrapped/docs/theming/)
- [Your first Wrapped](https://bettertyped.github.io/react-wrapped/docs/first-wrapped/)
- [Loading](https://bettertyped.github.io/react-wrapped/docs/player/loading/)

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