pr-visual-diff
Capture before/after screenshots of UI views with Playwright and embed them in a PR.
Skill by jesdi
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/jesdi-pr-visual-diff
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: design, frontend, testing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Node.js package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/pr-visual-diff
What's inside
- Skill name
pr-visual-diff- Description
- Capture before/after screenshots of UI views with Playwright and embed them in a PR. Use this skill whenever creating or preparing a pull request that touches frontend code (components, views, styles, layout, Tailwind classes) — even if the user just says "open a PR" or "create the PR" after UI work, and especially if they mention screenshots, visual diff, before/after, or "show what changed". Also use when the user asks to add screenshots to an existing PR.
- License
- MIT
- Instructions
- 326 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (3)
- SKILL.md
- capture-caller.yml · references/
- capture-spec-template.ts · references/
SKILL.md (first lines)
# PR Visual Diff
Produce before/after screenshots of the views affected by a branch's frontend
changes, push them to a hidden ref (never the PR branch), and embed them in the
PR body. Reviewers
should see what changed visually without checking out the branch.
The approach leans on the project's existing Playwright e2e harness with the
**API mocked**: because the data is stubbed and identical across both runs, any
pixel difference between "before" and "after" is caused by the code change
alone — that's the property that makes the comparison trustworthy. Never
screenshot against a live backend for this purpose.
Because every project wires this differently, the skill **discovers** the
project's setup once and caches it, then reuses the cache on later runs.
## Step 0. Load or build the per-project config
The config cache lives beside this skill at
`<skill-dir>/pr-visual-diff.<slug>.json`, where `<slug>` is the target repo's
directory name. It is gitignored — local to this machine. Ensure the cache file is ignored in the `.gitignore` of the repo where you install the skill directory (add an entry like `pr-visual-diff.*.json` if it isn't already).
- **If the cache exists**, read it and skip to "When NOT to run the capture".
If it says `{"supported": false}`, tell the user this project has no
mocked-API harness and create a plain PR (see Preconditions), then stop.
- **If it does not exist**, run the discovery pass below to build it.
### Discovery pass (first run only)
Inspect the target repo and record these values, then write them to the cache
file as JSON:
| Key | How to find it |
|---|---|
| `frontendDir` | the dir holding the app + its `src/` (repo root or a subdir like `frontend/`) |
| `e2eDir`, `specsDir` | the Playwright spec/support tree (look for `playwright.config.*`, a `specs/` dir) |
| `authFixtureImport`, `authFixtureName`, `authedPageProp` | the support file exporting a `test` fixture that seeds auth; note its import path, the exported name, and the authed-page property (e.g. `authenticatedPage`) |
| `mockHelperImport`, `mockHelperName` | the helper that stubs `/api` routes with fixture data; its import path + exported name |
| `port` | the `webServer` port in the Playwright config |
| `deviceProjects` | the config's `projects` (default to a desktop + a mobile project) |
| `baseBranch` | the repo's default branch (`main`/`master`; `git symbolic-ref refs/remotes/origin/HEAD`) |
| `packageManager` | infer from lockfile: `pnpm-lock.yaml`→pnpm, `package-lock.json`→npm, `yarn.lock`→yarn, `bun.lockb`→bun |
| `spinnerSelector` | every loading indicator of the app, as one selector list: spinners and skeletons (search for a spinner, `role="status"`, `aria-busy`, a skeleton component, `animate-pulse`), e.g. `.animate-spin, .animate-pulse`. A skeleton left out lets a half-loaded view pass as a good shot |
### Preconditions gate
The discovery pass is also the gate. **If there is no Playwright e2e harness
that mocks the API** (no mock helper, or no Playwright at all), write
`{ "supported": false, "reason": "<why>" }` to the cache, tell the user that a
trustworthy before/after diff isn't possible here (unmocked data would differ
between runs for reasons other than the code change), and **create a plain PR
instead** — no screenshots. Then stop.
## When NOT to run the capture
If `git diff --name-only $(git merge-base <baseBranch> HEAD)...HEAD` shows no
changes under `<frontendDir>/src/`, there is nothing visual to diff — create the
PR normally and say so. Test-only, docs-only, or backend-only diffs don't need
screenshots.
## Always run the capture in a subagent
Steps 2–6 (writing the spec, capturing, **reading every PNG back to eyeball
it**, pushing them to the hidden ref, embedding) MUST run inside a single dispatched subagent — not
in the main context. Reading screenshots back is this skill's dominant token
cost, and those image bytes are worthless to the main thread; keeping them in a
subagent's throwaway context is the whole savings, with no loss of verification.
Main context does only: step 1 (map the diff, get the user's go-ahead), then
dispatch a subagent with the plan and the config values. The subagent returns a
compact report: the screenshot file names + pinned URLs, the PR-body
markdown, and any views it flagged. The main context creates/edits the PR from
that report — it never reads a PNG.
## Where the capture runs
- **Local** (the default): steps 3–5 below, on this machine.
- **Remote**: when the session instructions say so (the agent-ops box does),
or when this machine cannot start a Playwright browser. A GitHub workflow of
the target repo captures both sides and pushes the hidden ref; see "Remote
capture". Steps 1, 2 and 6 stay the same.
## Workflow
### 1. Map the diff to views, then get the user's go-ahead
List changed files against the merge base (`git merge-base <baseBranch> HEAD`).
For each changed component, trace upward (imports → page/route component → route
path) to find the route(s) where it renders, and note any interaction needed to
make it visible (open a modal, select a tab). Classify each view as **changed**
(existed at the merge base) or **new** (introduced by this branch) — new ones
get an after-only shot.
This capture is heavy (temp worktree, two Playwright passes, images pushed to a
hidden ref, PR body rewritten). ALWAYS confirm with AskUserQuestion before
running any of it. The question must cover **both** (a) whether to run the whole
before/after capture at all, and (b) that it will push the screenshots to a
hidden ref on the remote and embed them in the PR. Include the proposed plan: which routes/states, and which
device projects — default to the config's `deviceProjects`; add more only when
the change is layout-sensitive. If they decline, create the PR normally and stop.
In an unattended session (nobody answers questions, as on the agent-ops box),
do not ask: run the capture with the plan above and name the plan in the PR
body.
### 2. Write the capture spec
Copy `references/capture-spec-template.ts` from this skill into
`<specsDir>/__pr-capture__.spec.ts` and substitute the `__PVD_*__` markers from
the config:
- `__PVD_AUTH_FIXTURE_IMPORT__` → `authFixtureImport` (and, if the fixture isn't
named `test`, adjust the `import { <authFixtureName> as test }` accordingly)
- `__PVD_MOCK_HELPER_IMPORT__` → `mockHelperImport` (and `mockHelperName` if not
`mockApi`)
- `__PVD_SPINNER_SELECTOR__` → `spinnerSelector`
- the `{ authenticatedPage: page }` destructure → `{ <authedPageProp>: page }`
Then fill in the `VIEWS` array. This file is scaffolding: never commit it, andFrom jesdi/general-skills, MIT.
More from jesdi/general-skills
- 0.570score
backlog
jesdi
Manage a GitHub-Issues-backed backlog and a Projects-v2 work graph via five verbs.
SkillAFreshness: AClaude Code +9 - 0.565score
pr-risk
jesdi
Merge-risk block of a PR body.
SkillAFreshness: AClaude Code +9 - 0.565score
review-page
jesdi
One interactive HTML page for a plan review or a questionnaire, built from a fixed template.
SkillAFreshness: AClaude Code +9 - 0.565score
to-openspec
jesdi
Turn settled discovery notes and a sketched data model into a spec folder in openspec shape (proposal, spec, design) under specs/<slug>/, plus ticket files…
SkillAFreshness: AClaude Code +9 - 0.565score
review-diff
jesdi
Review a branch before merge: first a gate (the repo's check command plus crap-gate), then three independent reviewers in parallel — spec (did we build what…
SkillAFreshness: AClaude Code +9 - 0.561score
to-tickets
jesdi
Break a spec, plan, or the current conversation into numbered tracer-bullet ticket files under .agent/tickets/, each declaring its blocking edges and…
SkillAFreshness: AClaude Code +9 - 0.561score
babysit-pr
jesdi
Babysit an open pull request until it is merged or handed to a human.
SkillAFreshness: AClaude Code +9 - 0.555score
implement-spec
jesdi
Implement a specification in code.
SkillAFreshness: AClaude Code +9 - 0.534score
test-prune
jesdi
Mutation-guided test pruning: a fixer proposes deleting redundant tests and strengthening weak ones, an independent reviewer accepts or rejects each proposal…
SkillAFreshness: AClaude Code +9 - 0.524score
deep-quality-review
jesdi
Extremely strict maintainability review of a branch's changes: duplicated concepts, complexity that got rearranged instead of deleted, spaghetti branching…
SkillBFreshness: BClaude Code +9 - 0.524score
crap-gate
jesdi
Score every function a branch changed with CRAP (cyclomatic complexity × untested fraction), fail on existing functions above 15 and new functions above 9…
SkillBFreshness: BClaude Code +9 - 0.524score
red-team-data-model
jesdi
Attack a proposed or existing data model for the ways it breaks under real conditions — concurrency, time windows, money, permissions — without proposing a…
SkillBFreshness: BClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 23
- Last commit (this folder)
- Oct 15, 2026 (14 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/jesdi/general-skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from jesdi
- 0.570score
backlog
jesdi
Manage a GitHub-Issues-backed backlog and a Projects-v2 work graph via five verbs.
SkillAFreshness: AClaude Code +9 - 0.565score
review-diff
jesdi
Review a branch before merge: first a gate (the repo's check command plus crap-gate), then three independent reviewers in parallel — spec (did we build what…
SkillAFreshness: AClaude Code +9 - 0.565score
review-page
jesdi
One interactive HTML page for a plan review or a questionnaire, built from a fixed template.
SkillAFreshness: AClaude Code +9 - 0.565score
to-openspec
jesdi
Turn settled discovery notes and a sketched data model into a spec folder in openspec shape (proposal, spec, design) under specs/<slug>/, plus ticket files…
SkillAFreshness: AClaude Code +9 - 0.565score
pr-risk
jesdi
Merge-risk block of a PR body.
SkillAFreshness: AClaude Code +9 - 0.561score
babysit-pr
jesdi
Babysit an open pull request until it is merged or handed to a human.
SkillAFreshness: AClaude Code +9
Cite this page
pr-visual-diff skill. Agent Mart. https://agentmart.dev/skills/jesdi-pr-visual-diff (last updated 2026-10-24)