Skip to content
Development
Skill

/visual-diff-branches

Use when the question is how pages render on one git ref versus another: checking a design-system, tokens, typography or styling PR for visual regressions on your feature's pages, producing before/after screenshots for a designer, answering 'did this branch change how X looks',

From plugin
flagrare-agent-skills
1134 skills
Install
$ npx -y skills add Flagrare/agent-skills --skill visual-diff-branches --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/visual-diff-branches

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when the question is how pages render on one git ref versus another: checking a design-system, tokens, typography or styling PR for visual regressions on your feature's pages, producing before/after screenshots for a designer, answering 'did this branch change how X looks',

SKILL.md

visual-diff-branches.SKILL.md
name: visual-diff-branches
description: "Use when the question is how pages render on one git ref versus another: checking a design-system, tokens, typography or styling PR for visual regressions on your feature's pages, producing before/after screenshots for a designer, answering 'did this branch change how X looks', or when a screenshot comparison is needed and no image library (ImageMagick, Pillow, sharp, pixelmatch) is installed. Triggers on 'compare main vs this branch', 'before and after screenshots', 'visual regression on this PR', 'what changed visually', 'side by side for design'."

Visual Diff Branches

Answer "what does this branch change on these pages" with evidence: the same pages captured on each ref, pixel-diffed to show *where*, and measured with computed styles to show *what*. Everything runs on the browser the project already has (Playwright's Chromium), so nothing gets installed.

Scripts live in `scripts/` next to this file. They resolve `@playwright/test` from the **project's** `node_modules`, so run them with the project root as the working directory and pass the scripts by absolute path. The only file you write per project is a `shots.mjs` config (contract in `references/config.md`, worked example in `references/shots.example.mjs`).

---

Step 1: Decide what "the branch" means

A PR branch is usually behind its base. Comparing the raw branch against main mixes the PR's own changes with every fix main landed since the branch forked, and those show up as regressions the PR did not cause. Decide up front and say which one you compared:

| Question | Compare | |---|---| | "What will land if this merges?" (the usual case) | a throwaway branch: `git checkout -B smoke/<name> origin/<branch> && git merge --no-edit origin/main` | | "What does the branch look like exactly as pushed?" | the branch itself |

Check `git rev-list --count origin/<branch>..origin/main` and quote the number in the report. If a difference appears on the raw branch but not on the merged one, it is a missing main fix, not a PR finding; say so and name the commit (`git log --oneline origin/<branch>..origin/main -- <file>`).

Tell the user before the first checkout. Their working tree is about to change branches under a running dev server.

Step 2: Write `shots.mjs`

One config per project, kept out of git (`.build/` or the scratchpad). It names the base URL, the saved login state, the locales and viewports, the shot list (a URL plus an optional `after(page)` that clicks into a flyout, picks a menu, opens an editor), and the measurement targets. See `references/config.md`.

Pick pages that exercise what the branch touches: a list with a table, a form with inputs and buttons, a flyout or modal, an empty state. Include every locale the product ships if the change is typographic; a font-size change can be harmless in one script and unreadable in another.

Probe each URL once before running the matrix. One URL that redirects to login or fires a logout call (a venue the saved session cannot open, for example) turns every later shot in the run into a login page. Drop it or switch to a URL the session can reach.

Step 3: Capture, one variant at a time

pnpm exec playwright test --project=setup          # or whatever refreshes the saved session
node <skill>/scripts/capture.mjs ./shots.mjs main ./shots
git checkout -B smoke/pr origin/feat/pr && git merge --no-edit origin/main
<skill>/scripts/wait-for-rebuild.sh <dev-server-log> <any-watched-source-file>
pnpm exec playwright test --project=setup
node <skill>/scripts/capture.mjs ./shots.mjs pr ./shots

Three things the loop above encodes, learned the hard way:

  • **Refresh the saved session before every variant.** Sessions expire in well under an hour; a run that outlives one silently produces login pages from that point on, all the same file size.
  • **Wait for a clean compile after a checkout.** The watcher usually compiles once mid-checkout (missing modules) and once clean. `wait-for-rebuild.sh` waits for a new compile line without errors and re-touches a file when the last one was dirty.
  • **Read the size column.** `capture.mjs` prints the rendered page size per shot. A shot that is viewport-height when its siblings are three screens tall was captured on a spinner; re-run it with `--only <name>`.

Run capture with the sandbox disabled when your agent sandbox blocks `localhost`.

Step 4: Measure, do not squint

Pixel diffs locate a change; they cannot tell a 3px radius from a pill, or 16px from 14px. Run the measurement pass on each variant and compare:

node <skill>/scripts/measure.mjs ./shots.mjs main ./shots
node <skill>/scripts/measure.mjs ./shots.mjs pr ./shots
node <skill>/scripts/compare-measures.mjs ./shots main pr

Targets are Playwright locators, so use text and roles (`getByText('Save changes')`, `getByRole('button', …)`) that survive markup changes. Mark containers with `box: true` to also record background, border, radius, padding, height and width. The compare output lists only rows that differ, with the base value first.

Every finding in the report should rest on a measured pair, not on how a screenshot looks. "Buttons look rounder" becomes "button radius 3px → 80px on Save, Cancel, New Modifier", which the author can act on and the reviewer can verify.

Step 5: Diff and compose

node <skill>/scripts/diff.mjs ./shots main pr
node <skill>/scripts/compose.mjs ./shots main pr ./for-design --labels "main (today)|design-system PR" \
     modifiers.en.1280.png:190,80,900,600 item-flyout.en.1280.png

`diff.mjs` writes `diff-pr/<file>.png` with changed pixels in red over a faded base and prints changed %, both sizes and the bounding box per file. Use the table to pick which shots deserve a composite; a 0.3% change confined to one row is a note, a 7% change across the page is a screenshot. Read at least two diff images before describing a variant as "only X changed". A localized red blob you did not expect

Read more
Ships withflagrare-agent-skills

Thirty-three skills that wrap around your development cycle in Claude Code. They turn tickets into ATDD plans, smoke-test features against a running app or service, hunt down bugs with runtime evidence, guard commits against doc drift, run seven-axis code

Get the whole plugin
Stats
11
Stars
2
Forks
Active
Maintenance
JavaScript
Language
3d ago
Last commit
4mo ago
Created

Repo: Flagrare/agent-skills

Other skills on flagrare-agent-skills.