# Storybook

One command opens every story of a built Storybook in Chromium, takes a screenshot at each width and uploads them.

## Install

The capture uses the Playwright in your project and needs Storybook 7 or newer, which writes the `index.json` the CLI reads.

```sh terminal
npm   install   -D   stateofpixel   playwright
npx   playwright   install   chromium
```

## Run it on CI

```yaml .github/workflows/visual.yml
steps :
  -  uses :  actions/checkout@v7
     with :
       fetch-depth :  0
  -  run :  npm ci
  -  run :  npx playwright install --with-deps chromium
  -  run :  npx storybook build
  -  run :  npx stateofpixel storybook storybook-static --viewports 375,1280
```

Keep `id-token: write` and the push trigger on `main` from the [Quickstart](https://stateofpixel.com/docs.md).

Each story is captured at every width in `--viewports` and named `Title/Name [chromium 1280]`, like `Button/Primary [chromium 375]`.

## Pick stories and wait for them

```sh terminal
npx   stateofpixel   storybook   storybook-static   \
   --include   "Components/**"   \
   --exclude   "**/Playground"   \
   --tag   snapshot   \
   --wait-for-selector   "[data-ready]"   \
   --delay   200   \
   --device-scale-factor   2
```

| Flag                             | Default               | What it does                             |
| -------------------------------- | --------------------- | ---------------------------------------- |
| `--viewports <widths>`           | `1280`                | Comma separated viewport widths.         |
| `--include <glob>`               |                       | Only stories whose title/name match.     |
| `--exclude <glob>`               |                       | Skip stories whose title/name match.     |
| `--tag <tag>`                    |                       | Only stories with this tag.              |
| `--wait-for-selector <selector>` | `#storybook-root > *` | Wait for this before each screenshot.    |
| `--delay <ms>`                   | `0`                   | Wait this long before each screenshot.   |
| `--device-scale-factor <n>`      | `1`                   | Pixels per CSS pixel, like 2 for retina. |

Each story opens in Chromium at a height of 720px, with reduced motion, grayscale text anti-aliasing and the device scale factor from `--device-scale-factor`, and the screenshot covers the full page. A story has 15 seconds to load and to match `--wait-for-selector`. After that, the CLI waits for the story's `play` function to finish, for its requests, Web Worker replies and the network to go idle and for images to load, including lazy ones, stops GIFs, videos and SVG animations, and takes screenshots until two in a row match. A story that keeps changing gets its last screenshot and a warning. When a story does not render, the command lists it and stops before anything uploads.

In `--include` and `--exclude`, `*` stays inside one segment of `Title/Name` and `**` crosses segments.

`--tag` keeps only stories that have that tag in their `tags`.

With `--device-scale-factor 2`, a screenshot has twice the width and height in pixels. Each image can be up to 25 MB, so a tall story at 2 may go over it. See [Limits](https://stateofpixel.com/docs/limits.md#limits).

`storybook` also takes every flag of `upload`, like `--build-name`, `--shard` and `--threshold`. With `--shard 2/4`, it captures only every fourth story, starting at the second, so each CI job takes its share. See the [CLI](https://stateofpixel.com/docs/cli.md) reference. Use `--dry-run` to capture and print the plan without uploading.

Stories that load data or fonts late are the usual cause of noisy diffs. [Stable screenshots](https://stateofpixel.com/docs/stable-screenshots.md) has the fixes.

## Capture with Storybook globals

`--globals` sets [Storybook globals](https://storybook.js.org/docs/essentials/toolbars-and-globals) for every story, in the same `key:value;key:value` form as the `globals` URL parameter. To capture each value of a global, run once per value with its own `--build-name`, so each one gets its own baselines:

```sh terminal
npx   stateofpixel   storybook   storybook-static   --build-name   storybook
npx   stateofpixel   storybook   storybook-static   --build-name   storybook-dark   --globals   theme:dark
```

## Use your Chromatic parameters

With `--chromatic`, the CLI loads the built Storybook, reads each story's `parameters.chromatic` and captures what Chromatic captures:

- Stories with `disableSnapshot: true` or `disable: true` are skipped.
- Each mode in `modes` is one screenshot named after the mode, like `Button/Primary [chromium dark 1280px]`. Modes with `disable: true` are skipped.
- A mode's `viewport` sets the width, in pixels or as the name of a viewport in `parameters.viewport` whose width is in pixels. Without `viewport`, the mode uses the first width in `--viewports`. The mode's other keys, except `a11y`, are passed as globals and override `--globals`.
- Stories without modes use `viewports` from `parameters.chromatic`, or `--viewports`.
- `delay` replaces `--delay` for that story.

```sh terminal
npx   stateofpixel   storybook   storybook-static   --chromatic
```

Parameters and tags come from Storybook at runtime, so values set through shared objects or helper functions count too. `--include`, `--exclude` and `--tag` still apply on top. `diffThreshold` is not read, so use `--threshold` for the whole build.
