---
name: convention-storybook
type: convention
description: "Conventions for Storybook and visual regression in Aled's system — the build-first harvest-from-build model, the component hierarchy, the story coverage bar, design-token wiring, client-facing Chromatic publish, the Figma design↔code bridge, dual-readable autodocs, and the per-repo instance shape. Read before standing up or extending Storybook on any repo (meirionpritchard-com, careeros-web), or before breaking down a Storybook ticket. Grown as the conventions solidify."
---

# convention-storybook

How Storybook is used in Aled's system. Follows the same per-repo tool-convention pattern as `convention-vercel` and `convention-github` — one convention, one instance per repo. Grown here as the conventions solidify.

## Role

Storybook is the **component workshop and the source of truth for the UI**. It documents every built component in isolation, gives design and build a shared reference, and is the base layer visual-regression testing runs against. It is a development tool by default, published to a client-facing URL for review (see *Hosting*).

The decisive point: Aled's sites were **built in code, not designed 1:1 in Figma first**. So the real components live in the codebase, and Storybook documents what is actually built — it is not generated from a Figma design system. This inverts the usual design-first flow, and everything below follows from it.

## The build-first inversion (the key principle)

The flow is **harvest-from-build, not Figma-first**:

1. **Audit the built components** — read the repo and inventory what actually exists (the component set, their props, their states).
2. **Document them in Storybook** — write a story file per component; Storybook becomes the source of truth for the UI.
3. **Recreate the equivalents in Figma** — once Storybook documents reality, the Figma library is rebuilt *from* it, as a separate design track (see *Figma*).

So a Storybook ticket's **first step is always an audit of what is built**, never "wait for the Figma design system". Any ticket blocked-by a Figma design-system ticket has the dependency the wrong way round and should be inverted — the Figma work is downstream of Storybook, not upstream of it.

## Repos and instances in scope

One convention, a per-repo instance — like Vercel and Sanity.

| Instance | Repo | Status |
| -- | -- | -- |
| meirionpritchard-com | assoc-one/meirionpritchard-com | **Lead instance** — first build (A1-15). Clean slate; the convention lands here first. |
| careeros-web | assoc-one/careeros-web | Has live Storybook work (COS-148 foundation, COS-156 stories, COS-159 Chromatic, COS-167 structure). Reconciles to this convention once it is saved. |

Both are Next.js / React / TypeScript repos, so each instance uses the Next.js framework preset, CSF3, and TypeScript stories.

## Structure and hierarchy

Organise the sidebar as a **layered hierarchy**, deepest primitives first:

`tokens → assets → components → sections → templates`

- **Tokens** — colour, type, spacing, radius, shadow (docs pages, from the real token source; see *Design-token wiring*).
- **Assets** — icons, logos, imagery.
- **Components** — the atomic UI set (button, input, card).
- **Sections** — composed blocks made of components (a hero, a work-list row).
- **Templates** — page-level compositions.

Set this with the story `title` / `component` meta and the folder layout. Story files live **alongside the component** (`Button/Button.stories.tsx`), never in a separate stories tree — the co-located file is development-only and excluded from the production bundle. (COS-167 is the careerOS planning ticket on exactly this hierarchy; it generalises to here.)

## Story authoring standard

- **CSF3, TypeScript.** `Meta`/`StoryObj` typed against the component; `satisfies Meta<typeof X>`; UpperCamelCase named exports for stories. This is the current Storybook standard (v10, CSF3).
- **Autodocs.** Tag stories for autodocs so each component gets a generated docs page from its args and types — the docs bar comes for free rather than being hand-written.
- **Autodocs are written for two readers — human and machine.** Document every prop with TSDoc/JSDoc on the prop interface and a component-level doc comment: it renders as the human props table *and* sits in the type layer the Figma MCP / AI consume. Prose ("when to use", gotchas) goes in `parameters.docs.description`; every prop is described in TSDoc so it lands in both the table and the types. The machine/AI channel is Storybook's generated `index.json` plus typed CSF — derive both from one source, never hand-maintain a separate spec.
- **Args over hardcoding.** Drive state through `args` so Controls work; compose args across composite components (a section reuses its components' story args) so a prop change updates in one place.
- **Interaction and states.** Use the `play` function for interactive states (a filled form, an open menu) so the state is captured, not just described.

## Story coverage bar

**Start with the Work-section set, then widen.** The bar is not "every component from day one" — the lead instance proves the pattern on the Work section (the components and sections that make up the work list and case-study surfaces), then extends outward to full coverage. Token and asset docs pages are part of the bar from the start; full component coverage is the destination, reached iteratively. This sequencing also lets Chromatic come in cleanly once there are stories to baseline (see *Visual regression*).

## Design-token wiring

Tokens flow **from the real token source into the stories**, so Storybook reflects the live system rather than a hand-copied palette. Wire the repo's actual token layer (CSS variables / Tailwind theme / token file) into `.storybook/preview` so components render with production tokens, and expose the tokens themselves as docs pages under *tokens*. If a token changes in the codebase, the stories reflect it without a second edit.

## Hosting

**Local by default, publishable to a client-facing URL.** `storybook dev` for development. For client review, **publish to Chromatic** and share an open-access link — the shared reference the client and team point at ("change that colour / tweak that component"). Chromatic over a plain static host because it adds **in-place commenting** on stories (the review conversation) and is the same publish that powers Storybook Connect. Visual regression is a separate Chromatic feature, not required for the publish itself. A branded Vercel static build stays an option but loses commenting, so Chromatic is the default for client review.

## Visual regression — Chromatic (deferred until stories exist)

Visual regression runs on **Chromatic**, added **after** the first stories exist, not stood up with the empty convention — an empty baseline is noise. The careerOS decisions (COS-159) are the standard, generalised here:

- **Chromatic free plan**, project per repo.
- **GitHub Action** under `.github/workflows`, running Chromatic on PRs.
- **All-stories baseline** — snapshot the full story set.
- **TurboSnap off** to start. TurboSnap only re-snapshots stories whose dependencies changed (via the build's dependency graph), which is a real saving at scale, but it adds moving parts — full rebuilds on `preview.js`/config/lockfile changes, and rebase/squash edge cases — that are not worth it until the story set is large. Turn it on once snapshot volume justifies it.
- **Chromium-only** to start, to keep snapshot count and cost down; add browsers later if needed.

### Credential split (how a Chromatic setup ticket is broken down)

Chromatic needs a project token that only Aled can create, so split the setup the same way as any credential-gated work (the APP-230 pattern, worked on COS-235 / COS-236):

- A **human leaf** — Aled creates the Chromatic project and adds the token to the repo's GitHub secrets. Labelled `human`, assigned to Aled.
- An **agent leaf** — add the GitHub Actions workflow and document the review flow. **Blocked-by** the human leaf, so it only runs once the secret exists.

This keeps the agent work from stalling on a secret it cannot set, and gives Aled a clear, isolated action.

## Figma (separate design track)

Recreating components in Figma is **not part of this convention** — it is a downstream design track that starts *once Storybook is the source of truth*. This convention ends at "the built UI is documented in Storybook". The Figma rebuild (harvest-from-build → recreate) is its own body of work, sequenced after, and owned by the design side (Pixel). Keeping it separate stops the Storybook rollout from being blocked on Figma, which is the whole point of the build-first inversion.

## Figma design↔code bridge

Two distinct tools; do not conflate.

- **Storybook Connect (the link we use)** — free Figma plugin linking a Figma component to its live Storybook story, both directions. Needs the Storybook published to Chromatic (the client publish already does this) and works on **current Figma Pro** — no upgrade. This is the design↔code link.
- **Code Connect (deferred)** — Figma's deeper bridge: a literal code snippet in **Dev Mode** Inspect, powering the Figma MCP. Requires **Org/Enterprise + Full/Dev seat**, not Pro. The CLI is open-source but Dev-Mode display still needs the paid plan. Adopt only when human devs need code in Figma and the library/Figma rebuild justify the Org cost.
- **Figma Console MCP (Pro-plan alternative to spike)** — TJ Pitre / Southleft, `github.com/southleft/figma-console-mcp`. An MCP server giving AI full access to the Figma project as JSON plus bidirectional token sync; may not need the Org upgrade. Does **not** give human devs Dev-Mode code snippets. Spike licence/auth before committing to Enterprise if the goal is AI-facing.

## What requires human action

- Creating the Chromatic project and adding its token to GitHub secrets (account-level; the human leaf above).
- Publishing Storybook to Chromatic and sharing the client link (account-level).
- Installing Storybook Connect in Figma and linking stories (design-side, one-off per component).
- Any deployed/published Storybook hosting (account-level on the host).
- Approving visual changes in Chromatic's review UI (the accept/deny is a human review gate).

## Rollout

- **meirionpritchard-com (A1-15)** is the lead instance. Break A1-15 down against this convention: step 1 is an **audit of what's built**; invert its current `blocked-by A1-14` (Figma design system) dependency so Storybook leads and Figma follows; scope the first stories to the Work-section set; defer Chromatic to a later leaf (with the credential split) once stories exist.
- **careeros-web** reconciles its existing Storybook tickets (COS-148/156/159/167) to this convention once saved — the hierarchy, coverage bar, and Chromatic decisions here supersede the ad hoc careerOS versions.

## Gotchas

- Story files must be **co-located** with components and excluded from the production build — a stray stories tree in the app bundle ships dev-only code.
- **Don't gate Storybook work on Figma.** The build is the source of truth; a Storybook ticket blocked-by a Figma design-system ticket has the dependency inverted (see *The build-first inversion*).
- **Storybook Connect ≠ Code Connect.** The plugin (free, Pro) is the link we use; Code Connect (Org/Enterprise) is the Dev-Mode code-snippet feature. Don't cite the plan gate against the plugin.
- **Chromatic full rebuilds** are triggered by changes to `preview.js`, the Storybook config, the static dir, or an out-of-sync lockfile — keep global decorators lean and the lockfile in sync to avoid re-snapshotting everything (matters more once TurboSnap is on).
- **TurboSnap and rebases/squashes** behave like merges (union of both ancestors' changes), so a squash-merge can re-snapshot more than expected — a reason to leave TurboSnap off until the story set is large enough to need it.
- Chromatic snapshot cost scales with stories × browsers — starting Chromium-only and Work-section-first keeps the free plan viable.
