/diff
Reconcile a converted/built web page against its source prototype with two complementary probes — a PIXEL/layout diff (stretched images, dropped wraps, blank renders, colour flips) and a STRUCTURAL content+typography diff (dropped/mis-slotted headings, eyebrows, CTAs;
$ npx -y skills add adobe/skills --skill diff --agent claude-codeHow 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
/diff
Context preview
The summary Claude sees to decide when to auto-load this skill.
Reconcile a converted/built web page against its source prototype with two complementary probes — a PIXEL/layout diff (stretched images, dropped wraps, blank renders, colour flips) and a STRUCTURAL content+typography diff (dropped/mis-slotted headings, eyebrows, CTAs;
SKILL.md
diff.SKILL.mdname: diff
description: Reconcile a converted/built web page against its source prototype with two complementary probes — a PIXEL/layout diff (stretched images, dropped wraps, blank renders, colour flips) and a STRUCTURAL content+typography diff (dropped/mis-slotted headings, eyebrows, CTAs; rendered-face font forks). Stack-agnostic via profiles (eds | generic). Use after converting a prototype to EDS/AEM (the stardust:deploy Step 10), or for any prototype↔build fidelity check; invocable as stardust:diff and from workflows.
license: Apache-2.0
stardust:diff — prototype ↔ build reconcile
Two probes that compare a **source** prototype against a **built** page. They catch **disjoint** failure classes — run BOTH; either alone gives a false "looks fine".
Both are framework-agnostic Playwright probes that compare two rendered URLs by **computed style + DOM** (not pixels). All stack-specific language lives in a **profile** (`--profile eds|generic`); the comparison logic is generic.
When to use
- After converting a prototype to EDS (the `stardust:deploy` skill's Step 10) — use `--profile eds`.
- Any "does the build match the design?" check between two rendered URLs (a Figma export vs a React build, a legacy page vs a rebuild) — use `--profile generic`.
- Inside a conversion/QA workflow as the validation gate (see *Workflow use*).
Not for: a single static file with no JS decoration (use the build/harness URL so components are decorated — a raw `.plain.html` has no roles to classify).
The two probes
| Probe | Script | Sees | Blind to | |---|---|---|---| | **Pixel / layout** | `skills/diff/scripts/visual-diff.mjs` | stretched images, dropped max-width wraps, blank renders, surface/ground colour flips, image-count gaps | "right text, wrong slot"; a dropped CTA (full pixels, plausible colours → no flag) | | **Structural content + type** | `skills/diff/scripts/content-diff.mjs` | MISSING / ROLE-SWAPPED headings·eyebrows·CTAs, invented/dropped body copy, rendered-FACE font forks (width probe) | geometry / layout regressions |
`content-diff` extracts an ordered, role-classified inventory (`heading` / `eyebrow` / `cta`+href / `body`) from each `<main>`, classifying by **computed style + tag** so the prototype's DOM and the built DOM compare symmetrically, then diffs them.
Run it
# Prereq 0: playwright importable from the project root — probe
# node -e "import('playwright').then(()=>process.exit(0))"
# and re-install (npm i -D playwright --no-save --legacy-peer-deps) on failure:
# a --no-save install from extract is PRUNED by any later real npm i
# (extract SKILL.md § Setup). Run the copied scripts from the project, not the plugin.
# Copy the WHOLE skills/diff/scripts/ dir: content-diff imports its local diff-profiles.mjs
# AND content-inventory.mjs. (The deploy gates #93/#94 now use their OWN synced copies in
# skills/deploy/scripts/ — A6/A2 are independent of this skill; the two copies must stay in
# sync until the diff-skill abrasion PR consolidates them.)
# Prereq: a RENDERABLE source. Static → serve from its own dir (python3 -m http.server).
# The build URL must be the DECORATED page (live/preview or a local harness), not raw markup.
PROTO="http://localhost:8791/<prototype>.html"
BUILD="https://<branch>--<repo>--<owner>.aem.page/<path>" # or http://localhost:3000/<harness>
# 1. PIXEL/layout
node skills/diff/scripts/visual-diff.mjs "$PROTO" "$BUILD" --profile eds --sections ".hero"
# 2. STRUCTURAL content + type
node skills/diff/scripts/content-diff.mjs "$PROTO" "$BUILD" --profile eds # --json dumps both inventoriesFlags (both tools): `--profile eds|generic` (default `eds`), `--width <px>` (default 1280), `--main <selector>` (content root; content-diff defaults from the profile, visual-diff to `main`), plus the live-target set (shared engine: `scripts/live-session.mjs` — every context sends the real-Chrome UA **and** the standard Chrome request headers; the UA alone still 403s on Akamai-class bot management):
- `--ua <string>` — user agent override (default: real-Chrome desktop UA).
- `--wait-until <state>` — goto wait override. Default rule (one shared
`defaultWaitUntil` in `scripts/live-session.mjs`), decided **per URL side**, three tiers:
- localhost/127.0.0.1 → `networkidle` (local prototypes / harnesses, unchanged);
- EDS build/preview origins — hostnames ending in `.aem.page`, `.aem.live`, `.hlx.page`,
`.hlx.live` → `networkidle` (they decorate asynchronously and reliably reach networkidle; measuring at domcontentloaded reads the pre-decoration DOM — flaky false reds / FONT FORK on deploy Step 10);
- all other live http(s) → `domcontentloaded` (live sites with analytics beacons
never reach networkidle).
`--wait-until` overrides all three tiers.
- `--dismiss [sel,...]` — dismiss overlays on both sides: cookie consent (clicked, not
removed) AND timed marketing/newsletter modals, plus optional extra site-specific selectors; the mouse is parked afterwards.
- `--headed` — escalation for bot-managed sites: headed stealth real Chrome.
- `--locale <tag>` — pin Accept-Language + context locale (geo-redirecting sites capture a
different locale per run otherwise).
`visual-diff` also: `--out <dir>`, `--sections a,b` (per-section screenshots).
A bot-management challenge/blocked interstitial on either navigation fails LOUD with **exit 3** — it is never measured as the source. Escalate with `--headed`; if that is still blocked, the site needs crawl.mjs-class capture and the check cannot run headless.
A plain (non-challenge) HTTP error on either side — e.g. a **404 build side, normal on aem.page before preview propagation** — is NOT fatal: the probe logs a loud warning, measures the error page, and the flags (BLANK RENDER / content asymmetry) carry the signal with **exit 0**. That is the probes' advisory contract: 0 = ran (flags advisory), 1 = probe error, 3 = bot challenge.
Reading content-diff
- 🔴 **MISSING CTA /
Read more
name: diff description: Reconcile a converted/built web page against its source prototype with two complementary probes — a PIXEL/layout diff (stretched images, dropped wraps, blank renders, colour flips) and a STRUCTURAL content+typography diff (dropped/mis-slotted headings, eyebrows, CTAs; rendered-face font forks). Stack-agnostic via profiles (eds | generic). Use after converting a prototype to EDS/AEM (the stardust:deploy Step 10), or for any prototype↔build fidelity check; invocable as stardust:diff and from workflows. license: Apache-2.0
stardust:diff — prototype ↔ build reconcile
Two probes that compare a **source** prototype against a **built** page. They catch **disjoint** failure classes — run BOTH; either alone gives a false "looks fine".
Both are framework-agnostic Playwright probes that compare two rendered URLs by **computed style + DOM** (not pixels). All stack-specific language lives in a **profile** (`--profile eds|generic`); the comparison logic is generic.
When to use
- After converting a prototype to EDS (the `stardust:deploy` skill's Step 10) — use `--profile eds`.
- Any "does the build match the design?" check between two rendered URLs (a Figma export vs a React build, a legacy page vs a rebuild) — use `--profile generic`.
- Inside a conversion/QA workflow as the validation gate (see *Workflow use*).
Not for: a single static file with no JS decoration (use the build/harness URL so components are decorated — a raw `.plain.html` has no roles to classify).
The two probes
| Probe | Script | Sees | Blind to | |---|---|---|---| | **Pixel / layout** | `skills/diff/scripts/visual-diff.mjs` | stretched images, dropped max-width wraps, blank renders, surface/ground colour flips, image-count gaps | "right text, wrong slot"; a dropped CTA (full pixels, plausible colours → no flag) | | **Structural content + type** | `skills/diff/scripts/content-diff.mjs` | MISSING / ROLE-SWAPPED headings·eyebrows·CTAs, invented/dropped body copy, rendered-FACE font forks (width probe) | geometry / layout regressions |
`content-diff` extracts an ordered, role-classified inventory (`heading` / `eyebrow` / `cta`+href / `body`) from each `<main>`, classifying by **computed style + tag** so the prototype's DOM and the built DOM compare symmetrically, then diffs them.
Run it
# Prereq 0: playwright importable from the project root — probe
# node -e "import('playwright').then(()=>process.exit(0))"
# and re-install (npm i -D playwright --no-save --legacy-peer-deps) on failure:
# a --no-save install from extract is PRUNED by any later real npm i
# (extract SKILL.md § Setup). Run the copied scripts from the project, not the plugin.
# Copy the WHOLE skills/diff/scripts/ dir: content-diff imports its local diff-profiles.mjs
# AND content-inventory.mjs. (The deploy gates #93/#94 now use their OWN synced copies in
# skills/deploy/scripts/ — A6/A2 are independent of this skill; the two copies must stay in
# sync until the diff-skill abrasion PR consolidates them.)
# Prereq: a RENDERABLE source. Static → serve from its own dir (python3 -m http.server).
# The build URL must be the DECORATED page (live/preview or a local harness), not raw markup.
PROTO="http://localhost:8791/<prototype>.html"
BUILD="https://<branch>--<repo>--<owner>.aem.page/<path>" # or http://localhost:3000/<harness>
# 1. PIXEL/layout
node skills/diff/scripts/visual-diff.mjs "$PROTO" "$BUILD" --profile eds --sections ".hero"
# 2. STRUCTURAL content + type
node skills/diff/scripts/content-diff.mjs "$PROTO" "$BUILD" --profile eds # --json dumps both inventoriesFlags (both tools): `--profile eds|generic` (default `eds`), `--width <px>` (default 1280), `--main <selector>` (content root; content-diff defaults from the profile, visual-diff to `main`), plus the live-target set (shared engine: `scripts/live-session.mjs` — every context sends the real-Chrome UA **and** the standard Chrome request headers; the UA alone still 403s on Akamai-class bot management):
- `--ua <string>` — user agent override (default: real-Chrome desktop UA).
- `--wait-until <state>` — goto wait override. Default rule (one shared
`defaultWaitUntil` in `scripts/live-session.mjs`), decided **per URL side**, three tiers:
- localhost/127.0.0.1 → `networkidle` (local prototypes / harnesses, unchanged);
- EDS build/preview origins — hostnames ending in `.aem.page`, `.aem.live`, `.hlx.page`,
`.hlx.live` → `networkidle` (they decorate asynchronously and reliably reach networkidle; measuring at domcontentloaded reads the pre-decoration DOM — flaky false reds / FONT FORK on deploy Step 10);
- all other live http(s) → `domcontentloaded` (live sites with analytics beacons
never reach networkidle).
`--wait-until` overrides all three tiers.
- `--dismiss [sel,...]` — dismiss overlays on both sides: cookie consent (clicked, not
removed) AND timed marketing/newsletter modals, plus optional extra site-specific selectors; the mouse is parked afterwards.
- `--headed` — escalation for bot-managed sites: headed stealth real Chrome.
- `--locale <tag>` — pin Accept-Language + context locale (geo-redirecting sites capture a
different locale per run otherwise).
`visual-diff` also: `--out <dir>`, `--sections a,b` (per-section screenshots).
A bot-management challenge/blocked interstitial on either navigation fails LOUD with **exit 3** — it is never measured as the source. Escalate with `--headed`; if that is still blocked, the site needs crawl.mjs-class capture and the check cannot run headless.
A plain (non-challenge) HTTP error on either side — e.g. a **404 build side, normal on aem.page before preview propagation** — is NOT fatal: the probe logs a loud warning, measures the error page, and the flags (BLANK RENDER / content asymmetry) carry the signal with **exit 0**. That is the probes' advisory contract: 0 = ran (flags advisory), 1 = probe error, 3 = bot challenge.
Reading content-diff
- 🔴 **MISSING CTA /
Repo: adobe/skills
Other skills on adobe-skills.
- /aa-conversion-funnel-analysis
Analyzes a multi-step conversion funnel to find where visitors drop off and which steps have the worst leakage. Use this skill when someone describes a journey and asks about conversion rates, drop-off, fallout, or step completion. Trigger for "analyze our checkout funnel,"
Open skill - /aa-executive-briefing
Generates a concise, executive-ready performance summary covering key metrics, trends, and what's driving movement. Use this skill when someone needs to produce a briefing, executive summary, performance narrative, or stakeholder readout — for example, "write an exec summary of
Open skill - /aa-kpi-pulse
Produces a compact KPI digest showing how key metrics changed over a period and what's driving the movement. Use this skill when someone asks for a performance summary, a weekly recap, a morning briefing, a KPI update, or any variation of "how did we do this week/month." Also
Open skill - /aa-segment-performance-comparator
Compares the performance of two or more audience segments across key metrics side by side. Use this skill when someone wants to compare audiences or visitor groups — for example, "how do mobile visitors compare to desktop on conversion," "compare new vs. returning visitors,"
Open skill - /aa-top-movers-watchlist
Identifies which items (pages, campaigns, products, channels, regions) had the biggest increases or decreases for a key metric between two time periods. Use this skill when someone asks "what's up and what's down," "which campaigns moved the most," "top gainers and losers,"
Open skill - /cja-dimension-analysis
Comprehensive dimension analysis and reporting for CJA. Use this skill whenever the user wants to analyze one or more dimensions — including cardinality, distribution/skew, trends, anomalies, data quality errors, comparisons, and forecasting. Also trigger when someone asks "what
Open skill

