@juangadm/pre-post
v0.3.0
Published
Visual diff tool for PRs — captures before/after screenshots of web pages
Maintainers
Readme
pre-post
Visual diff tool that captures pre/post screenshots for PRs. Use it as a Claude Code skill for automatic visual documentation, or run it directly from the CLI.
Originally forked from before-and-after by James Clements / Vercel Labs.
What Changed from the Original
| Area | before-and-after | pre-post |
|------|-----------------|----------|
| Browser engine | agent-browser (Vercel-proprietary) | Playwright (direct dependency) |
| Screenshot quality | 1x | 2x retina (deviceScaleFactor: 2) |
| Route detection | Manual | Automatic from git diff (Next.js App/Pages Router, generic fallback) |
| Responsive capture | Single viewport | Desktop + mobile per route (--responsive) |
| CLI subcommands | URL pairs only | detect, compare, run subcommands |
| Skill orchestration | Basic capture | Full workflow: route detection, Claude refinement, user approval, PR posting |
| Font/animation handling | None | Waits for document.fonts.ready, disables CSS animations |
How It Works
flowchart TD
A[pre-post] --> B{Mode?}
B -->|Manual| C["pre-post url1 url2"]
B -->|Subcommand| D{"detect | compare | run"}
B -->|Claude Code Skill| E["/pre-post"]
D -->|detect| F["Git: diff, staged, unstaged, untracked"]
D -->|compare| J
D -->|run| F
F --> G{Detect framework}
G -->|Next.js App Router| H[Map files → routes]
G -->|Next.js Pages Router| H
G -->|Generic| H
H --> I{Routes found?}
I -->|Yes| J[Route list with confidence]
I -->|No| J2["Default to /"]
J2 --> J
E --> E1[Pre-flight checks]
E1 --> F
E1 --> K[Claude refines routes]
K --> K1[User approves routes]
K1 --> J
C --> L[Playwright]
J --> L
L --> M{Launch Chromium}
M -->|"PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH"| M1[Custom path — fail hard if invalid]
M -->|Auto-detect| M2[System Chrome → Bundled → Cached]
M1 --> P[Navigate + wait for network idle]
M2 --> P
P --> Q[Disable CSS animations]
Q --> R[Wait for document.fonts.ready]
R --> S[Take 2x retina screenshot]
S --> T[Save to ~/Downloads]
T --> T1{--markdown?}
T1 -->|No| U[Done]
T1 -->|Yes| V{Upload method}
V -->|Default| W["git-native: commit to .pre-post/"]
V -->|--upload-url| Y["HTTP: 0x0.st / Vercel Blob / PUT"]
W --> X[Build blob+SHA URL]
Y --> X
X --> Z[Markdown table]
Z --> Z1{Skill mode?}
Z1 -->|Yes| Z2[User approves screenshots]
Z2 --> Z3["gh pr edit — append to PR body"]
Z1 -->|No| Z4[Copy to clipboard]
style A fill:#4f46e5,color:#fff
style L fill:#2563eb,color:#fff
style S fill:#059669,color:#fffPrerequisites
- Node.js 18+
- Chromium — install once via Playwright:
npx playwright install chromiumCI / Sandboxed Environments
pre-post needs a Chromium binary. In restricted environments where npx playwright install chromium fails (CDN blocked):
# Point to a pre-installed Chrome/Chromium binary
export PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/path/to/chrome
# This is treated as an explicit override — pre-post will fail with a
# clear error if the path is wrong, rather than silently falling back.When no custom path is set, pre-post auto-detects in order: system Chrome, bundled Playwright Chromium, then any builds in ~/.cache/ms-playwright/.
If no browser is available at all, use image-only mode:
pre-post before.png after.png --markdownProxy URLs: If your git remote uses a proxy (e.g., http://proxy@host/git/owner/repo), set the repo explicitly:
export GH_REPO=owner/repoGoogle Fonts: Container egress proxies typically block fonts.googleapis.com.
Screenshots will render with system font fallbacks. This is cosmetic only —
document.fonts.ready still resolves and layout is preserved.
Install
npm install -D @juangadm/pre-postBasic Use
As a Claude Code Skill (recommended)
After making visual UI changes, say /pre-post or "take pre and post screenshots". Claude will:
- Detect affected routes from your git diff
- Propose routes for your approval
- Capture desktop + mobile screenshots (production vs localhost)
- Show you the screenshots for approval
- Upload and append markdown to your PR
From the CLI
Capture any two URLs:
pre-post site.com localhost:3000Use existing images:
pre-post before.png after.pngCLI Subcommands
detect -- Route Detection
Detect affected routes from git changes:
pre-post detect # Auto-detect framework
pre-post detect --framework nextjs-app # Force frameworkOutputs JSON with route paths, confidence levels, and source files.
compare -- URL Comparison
Compare pre/post states across routes:
pre-post compare --before-base https://prod.com --after-base http://localhost:3000
pre-post compare --before-base URL --after-base URL --routes /dashboard,/settings
pre-post compare --before-base URL --after-base URL --responsive # Desktop + mobilerun -- Full Auto
Combines detect + compare:
pre-post run --before-base https://prod.com --after-base http://localhost:3000Options
Capture a specific element using a CSS selector:
pre-post url1 url2 ".hero"Use different selectors for pre and post:
pre-post url1 url2 ".old" ".new"Capture at mobile (375x812), tablet (768x1024), or custom viewport:
pre-post url1 url2 --mobile
pre-post url1 url2 --size 1920x1080Capture the entire scrollable page:
pre-post url1 url2 --fullOutput a markdown table for PR descriptions:
pre-post url1 url2 --markdownSave to a custom location:
pre-post url1 url2 --output ./screenshotsUpload to a custom image storage service:
pre-post url1 url2 --markdown --upload-url https://my-s3-bucket.amazonaws.comBy default, --markdown commits screenshots to the PR branch (under .pre-post/) and serves them via GitHub blob URLs pinned to the commit SHA. This works for both public and private repos. Use --upload-url to point at your own storage instead. It auto-detects the protocol for 0x0.st, Vercel Blob, and any generic PUT endpoint (like S3). Screenshots auto-append to the PR body, newest on top.
Route Detection
Pre-post automatically maps git diff --name-only to affected UI routes:
| Changed File | Detected Route | Confidence |
|---|---|---|
| app/page.tsx | / | high |
| app/dashboard/page.tsx | /dashboard | high |
| app/(marketing)/about/page.tsx | /about (strips route groups) | high |
| app/blog/[slug]/page.tsx | /blog/[slug] | high |
| app/dashboard/layout.tsx | /dashboard | medium |
| app/dashboard/components/Chart.tsx | /dashboard | medium |
| globals.css, tailwind.config.ts | / | low |
| app/api/*, middleware.ts | Skipped (no visual) | -- |
Supports:
- Next.js App Router (route groups, dynamic segments, parallel routes, catch-all)
- Next.js Pages Router (
pages/,_app.tsx,_document.tsx) - Generic fallback (defaults to
/)
Add Skill
Install as an agent skill using the skills CLI:
npx skills add juangadm/pre-post # interactive — pick your agent(s)
npx skills add juangadm/pre-post -y # auto-install to all universal agents
npx skills add juangadm/pre-post -y -g # install globally (all projects)This copies skill/SKILL.md into the appropriate directory for your agent (e.g., .claude/skills/ for Claude Code, .agents/skills/ for Amp/Codex/Gemini CLI, etc.).
The skill uses gh to detect the associated PR and Playwright for screenshots.
Note: The npm package (
@juangadm/pre-post) is published on npmjs.com, not GitHub Packages — so the "Packages" section on the GitHub repo page will show none.
Credits
- Original before-and-after by James Clements at Vercel Labs
- Browser automation powered by Playwright
License
MIT
