responsive-breakpoint-runner
Produces a single breakpoint-matrix report (rows = pages/stories, columns = viewports) across Percy, Chromatic, Playwright snapshots, or Storybook test-runner. Routes per-engine viewport syntax, runs each, and aggregates the results into one cross-breakpoint view. Use when the team needs one unified pass/fail view across three or more viewport widths instead of separate per-engine or per-breakpoint reports. The matrix-view output is the distinguishing trait: it dispatches to playwright-snapshots (and the other engines) rather than replacing any single-engine skill.
Install with skills.sh (any agent)
npx skills add testland/qa --skill responsive-breakpoint-runnerresponsive-breakpoint-runner
Overview
Most teams need to assert a UI across multiple breakpoints (mobile, tablet, desktop, sometimes wide-desktop). The four engines covered here each have their own way to express a viewport list:
This skill is a dispatcher: pick the engine the project already runs, follow the matching pattern, then aggregate into a single breakpoint report. It does not replace any engine - it composes the plugin's per-engine skills. The per-engine viewport syntax lives in references/engine-viewport-syntax.md.
When to use
If the project only covers a single breakpoint, defer this skill - go directly to the relevant per-engine SKILL.md.
Dispatcher: pick by engine
Is the project using Chromatic + Storybook?
├── Yes → Chromatic pattern.
└── No
├── Is the project using Percy?
│ └── Yes → Percy pattern.
└── No
├── Is the project using @storybook/test-runner without Chromatic?
│ └── Yes → Storybook test-runner pattern.
└── No (project uses raw @playwright/test snapshots)
└── Playwright pattern.Each pattern - per-engine viewport syntax and its source docs - is in references/engine-viewport-syntax.md.
If the project uses two engines (e.g. Chromatic for stories + Playwright snapshots for full pages), apply the matching pattern to each independently and use the visual-baseline-gate skill to aggregate verdicts.
How to use
Worked example
A dashboard app already runs Playwright snapshots at desktop-1280 only and wants mobile + tablet + wide coverage without tripling test files.
| Page / Story | mobile-375 | tablet-768 | desktop-1280 | wide-1920 |
|--------------|:----------:|:----------:|:------------:|:---------:|
| /dashboard | ✅ | ✅ | ✅ | ✅ |
| /onboarding | ✅ | ✅ | ✅ | ✅ |
| /pricing | ✅ | ❌ | ❌ | ✅ |The two red cells in the /pricing row tell the reviewer exactly which breakpoints regressed. Pipe the matrix into $GITHUB_STEP_SUMMARY and feed the rows to visual-baseline-gate, which exits non-zero on the failed cells.
Producing the unified report
Every per-engine run can produce a per-breakpoint pass/fail line. To build a single "what broke at which breakpoint" view, normalize each engine's output to a row shape:
{
"engine": "playwright",
"breakpoint": "mobile-375",
"story_or_url": "/dashboard",
"status": "fail",
"diff_pixels": 1234,
"diff_url": "playwright-report/data/dashboard-mobile-375-diff.png"
}Then render a markdown matrix (rows = pages/stories, columns = breakpoints):
| Page / Story | mobile-375 | tablet-768 | desktop-1280 | wide-1920 |
|-------------------------|:----------:|:----------:|:------------:|:---------:|
| /dashboard | ❌ | ✅ | ✅ | ✅ |
| /onboarding | ✅ | ✅ | ✅ | ✅ |
| /pricing | ✅ | ❌ | ❌ | ✅ |A single failed cell tells the reviewer which breakpoint broke, which is the entire reason this skill exists. Pipe the matrix into $GITHUB_STEP_SUMMARY (or the GitLab / Jenkins equivalent) for a clickable PR-side summary.
For a hard CI gate that fails on any cell, use visual-baseline-gate - it accepts this row shape directly.
CI integration
The CI workflow follows whichever per-engine SKILL.md you dispatched to; the only added concern is uploading every breakpoint's report artifact (Playwright HTML report, Chromatic build URL, Percy build URL) so a reviewer can see the diff for a specific cell:
- name: Upload all visual artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: visual-reports-all-breakpoints
path: |
playwright-report/
test-results/
.chromatic/
.percy/
retention-days: 14References
Per-engine viewport syntax
View source (opens in new window)Per-engine viewport syntax
Pick the engine the project already runs, follow the matching pattern below, then aggregate into a single breakpoint report (see the skill's "Producing the unified report" section). This does not replace any engine - it composes the plugin's per-engine skills. If the project uses two engines, apply each pattern independently and aggregate verdicts with visual-baseline-gate.
Chromatic dispatch
Per the Chromatic viewports docs (opens in new window), viewports are configured per story via parameters.chromatic.viewports. Pixel widths, set inside the story's parameters block:
// Header.stories.ts
export default {
title: 'Components/Header',
component: Header,
parameters: {
chromatic: {
viewports: [375, 768, 1280, 1920],
},
},
};A story with multiple viewports produces one snapshot per viewport in the same Chromatic build. Pair with TurboSnap (--only-changed, see chromatic-visual-regression-testing) so a per-PR breakpoint matrix doesn't blow up snapshot quota.
Percy dispatch
Per Percy CLI (opens in new window), project-wide widths are set in the Percy config file (.percy.yml, percy.config.js, etc., resolved per the order documented in percy-visual-regression-testing):
# .percy.yml
version: 2
snapshot:
widths: [375, 768, 1280, 1920]
min-height: 1024For a single overridden snapshot, pass the widths in the SDK call:
await percySnapshot(page, 'Homepage', { widths: [375, 1280] });(Per the per-engine readme - when in doubt, check the latest percy/cli (opens in new window) release for the current snapshot config schema.)
Playwright dispatch
Per playwright-snapshots (opens in new window), the canonical pattern is one project per breakpoint, each with its own viewport set:
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{ name: 'mobile-375', use: { ...devices['Desktop Chrome'], viewport: { width: 375, height: 667 } } },
{ name: 'tablet-768', use: { ...devices['Desktop Chrome'], viewport: { width: 768, height: 1024 } } },
{ name: 'desktop-1280',use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 800 } } },
{ name: 'wide-1920', use: { ...devices['Desktop Chrome'], viewport: { width: 1920, height: 1080 } } },
],
});Run the matrix:
npx playwright test --project=mobile-375
npx playwright test --project=tablet-768
npx playwright test # runs all projects in parallelEach project produces its own snapshot suffix (-chromium-linux-mobile-375.png etc.) so baselines are isolated. See playwright-snapshots for the naming convention.
Storybook test-runner dispatch
When using @storybook/test-runner without Chromatic, drive the viewport via the test-runner's preVisit hook (per storybook-test-runner (opens in new window)):
// .storybook/test-runner.ts
import type { TestRunnerConfig } from '@storybook/test-runner';
import { expect } from '@playwright/test';
const VIEWPORTS = [375, 768, 1280, 1920];
const config: TestRunnerConfig = {
async postVisit(page, context) {
for (const width of VIEWPORTS) {
await page.setViewportSize({ width, height: Math.round(width * 0.75) });
await expect(page.locator('#storybook-root')).toHaveScreenshot(
`${context.id}-${width}.png`
);
}
},
};
export default config;Note this pattern multiplies snapshot count by VIEWPORTS.length - acceptable for a few hundred stories; reconsider above ~1000 stories where Chromatic's TurboSnap makes more economic sense.
Source docs
Related skills
chromatic-visual-regression-testing
Authors and runs Chromatic visual tests on Storybook, Playwright, or Cypress projects via the `chromatic` CLI; configures baselines, TurboSnap, UI Review, and CI gating; reads exit codes for change-vs-error classification. Use when the project ships visual regression coverage to Chromatic Cloud.
percy-visual-regression-testing
Authors Percy visual snapshot tests via the @percy/cli + framework SDK (Playwright, Cypress, Selenium, Storybook), runs them with `percy exec -- {test command}`, configures viewports / masking / ignored regions, and reviews diffs in the Percy build UI. Use when the project ships visual regression coverage to BrowserStack Percy.
playwright-snapshots
Authors Playwright `expect(page).toHaveScreenshot()` assertions, configures masks / clips / threshold / maxDiffPixels per test, manages the per-OS / per-browser snapshot directory, and runs the update flow with `--update-snapshots`. Use when the project ships self-hosted visual regression coverage in Playwright (no external snapshot service).
storybook-visual-regression-testing
Sets up visual regression coverage for a Storybook project - either via the official @chromatic-com/storybook addon (hosted) or via @storybook/test-runner with a postVisit hook that calls Playwright's toHaveScreenshot (self-hosted). Covers test-runner install, lifecycle hooks (setup / preVisit / postVisit), and CI integration. Use when a repo already has a working `.storybook/` config and the team wants per-story visual coverage rather than page-level snapshots.
visual-baseline-conventions
Reference catalog for visual regression coverage decisions - which Storybook stories or pages get baselines, how to choose breakpoints, when to mask vs adjust threshold, when to add or remove a baseline, and a decision matrix for picking among Percy / Chromatic / Playwright / Storybook test-runner. Use when designing visual coverage for a new project or auditing an existing baseline set.
visual-baseline-gate
Consumes pre-classified visual-diff JSON and a reviewer-signed acceptance log to produce a single go/no-go CI verdict for visual regression. Blocks when intentional baseline changes lack a non-author reviewer sign-off or when regressions are present, and emits a markdown + JSON artifact for the CI step. Use this skill when the gate's input is pre-classified diff data and the enforcement concern is reviewer approval, not when the goal is fanning out to multiple engines (use a multi-engine CI orchestrator for that).
visual-diff-summarizer
Triages a PR's visual regression diffs when there are too many changed screenshots to review one by one. Clusters snapshots (from Percy, Chromatic, Playwright `toHaveScreenshot`, Storybook, Loki) by component / route, separates changes that match PR intent from cascade / regression suspects, recommends which baselines to update, and emits one PR comment pointing the reviewer at the screenshots that need actual eyes. Use when a PR has 20+ visual diffs / changed screenshots and the reviewer needs help deciding which to open.