Install
$ agentstack add skill-hoiung-sst3-skills-design-fidelity ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README — it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Design-Fidelity — Visual Design-Fidelity Loop
> Scope contract (Invariant): this skill ONLY shoots screenshots, diffs them, reads computed CSS, and SUGGESTS CSS changes for the operator to apply. It NEVER deploys, NEVER edits live-site config or DNS, and NEVER pushes to a live site. It reads; the operator decides and edits. Screenshot output is always written OUTSIDE any git repo so a capture can never be committed.
> Related: drawing/annotating a schematic diagram (not matching a live page)? See docs/guides/diagram-annotation-qa.md (../dotfiles/docs/guides/... from a consumer repo) — it reuses this skill's shoot.py for the render-and-inspect step of the Hybrid diagram pipeline.
> Hard dependency: the three helpers scripts/shoot.py, scripts/compare_computed_style.py, and scripts/pixel-drift.sh; the two mechanics guides references/playwright-fallback.md (capture + computed-CSS + pixel-diff command bodies) and references/chrome-devtools-mcp.md (MCP route); the playwright Python lib + its bundled chromium_headless_shell (per-repo .venv OR global python3 — the helpers fail loud with the install command if it is missing); and ImageMagick compare (the pixel-diff engine — pixelmatch is NOT installed). The skill is available in every repo where its directory is present on the Claude Code skills path.
SST3 Anti-Patterns Governing This Skill
Respect these APs (full detail in ANTI-PATTERNS.md):
- AP #10 Duplicate Rules: the capture / computed-CSS / pixel-diff MECHANICS live in the two guides. This skill points at them — it does NOT restate the command bodies. Grep the guides before adding any mechanic doc here.
- AP #16 Monitor, Don't Fire-and-Forget: after every
shoot.py/compare_computed_style.py/pixel-drift.shrun, VERIFY the exit code and read the stderr telemetry (which wait-strategy fired, normalisation WxH,comparerc). "Ran the script" is not "got the shot". - AP #17 Keep Going Until Done: a per-page 3x loop runs its iterations without pausing to ask "should I continue?". Stop ONLY at 80% context, a destructive action needing consent, genuinely stuck, or task complete.
- AP #18 Sample-Invocation: a real end-to-end shoot + compare + drift on one live page IS the Workflow/E2E-tier verification. Keep the per-repo
.design-fidelity.json+ the produced numbers as the evidence.
Operator Prerequisites
- playwright + chromium: per-repo
.venv/bin/python -m playwright install chromium(or global). WSL works out of the box with the bundledchromium_headless_shell— no Windows Chrome, no extra flags. - ImageMagick:
compare,convert,identifyon PATH. On a host whosepolicy.xmldenies the PNG coder,pixel-drift.sh's probe guard fails loud — re-allow the PNG coder. - A reachable base_url: the operator runs the local build server (e.g.
hugo server) OR supplies a live URL. The skill does not own the server lifecycle by default (an opt-inhugoblock exists for convenience). - A per-repo
.design-fidelity.json(optional): the page→path map, viewports, and out_dir for that repo. The sample values are an EXAMPLE, never a default.
When to Invoke
- "Screenshot this page / the whole site at desktop and mobile."
- "Compare my local build against the live site and tell me what's off."
- "Match the design of — measure how close we are and what to change."
- "Show me the pixel-diff drift between local and live for the home page."
- Greenfield capture-only (no live reference yet): just shoot the build for review.
Mandatory Reading on Invoke
references/playwright-fallback.md— the canonical capture + "Live computed-CSS reads" + "Pixel-diff scoring" mechanics (command bodies live HERE, not in this file).references/chrome-devtools-mcp.md— the MCP route + the browser-state security note.- The per-repo
.design-fidelity.jsonif it exists (page map / viewports / out_dir). - The screenshots output directory for the active repo under
~/DevProjects/screenshots//(where captures and diffs land — OUTSIDE the repo).
The Per-Page 3x Iterate Loop
Work ONE page at a time. Each iteration runs this concrete dual-URL recipe:
- Shoot both sides at both viewports. Shoot the LOCAL build (
shoot.pywithbase_url= the local server) for the target page path at desktop (1440) + mobile (390), and shoot/cache the LIVE reference (shoot.pywithbase_url= the live base) for the same path at the same viewports. Capture local and live at identical viewport widths so the drift number is not inflated by stretch. - Measure the gap. Run
compare_computed_style.py --local-url --live-url --selectoron the selector(s) you are matching (exact spacing / colour / font deltas per viewport), AND runpixel-drift.shon the PNG pair (a measurable AE + closeness% + a diff-highlight image). - Tweak and re-shoot. Apply the smallest CSS change the deltas point to, rebuild the local site, then re-shoot and re-measure.
Repeat at most 3 times per page. Watch the drift number trend DOWN and the computed-CSS deltas shrink toward zero. Then move to the next page.
Sub-Commands
/design-fidelity shoot— capture only (shoot.py). Works STANDALONE with no live reference (greenfield repo): just produces full-page desktop+mobile screenshots for review./design-fidelity compare— run the full per-page loop above against a live reference:shoot.py(local + live) →compare_computed_style.py→pixel-drift.sh. Fires ONLY when a live reference URL is supplied./design-fidelity diff— re-runpixel-drift.shon an existing local/live PNG pair to re-measure drift after a tweak.
Triple-Check Discipline
> Maps to the Three-Tier Testing Framework (SST3 STANDARDS.md "Three-Tier Testing Framework").
- Unit Tier:
tests/run_unit_tests.shasserts each helper's contract (config-merge + parsers, the null-selector_errorpath, and the pixel-drift output binary) with no browser/live-site dependency. - Workflow Tier: a real
shoot.pycapture run against a reachablebase_url, exit 0, with the expected PNGs written outside the repo. - E2E Tier: a full shoot + compare + drift on one live page end-to-end, producing a real drift number + diff image — the AP #18 sample-invocation.
Security: chrome-devtools browser state
When you drive a LIVE site via the chrome-devtools MCP (the alternative to the headless playwright route), the MCP runs with full browser access — it can read open-tab cookies, auth tokens in request/response headers, pasted secrets in form fields, and cached credentials surfaced by the page (live browser state). Disable chrome-devtools via /plugin BEFORE pasting any secret. The DEFAULT route in this skill is headless playwright, which carries no live browser state, so prefer it. Full detail: references/chrome-devtools-mcp.md "Security note".
Anti-Overfit Constraint
The pixel-drift number is a TREND diagnostic — the operator watches it decrease across iterations; it is NEVER a hard pass-gate. The target is a STRUCTURAL match, not pixel-perfection (anti-aliasing, font-hinting, and dynamic content make pixel-perfect impossible and pointless). The page→path map, base_url, and viewport list are PER-REPO config — the proto values are an example, NOT a default.
File Locations
| File | Location | |------|----------| | Capture helper | scripts/shoot.py | | Computed-CSS delta helper | scripts/compare_computed_style.py | | Pixel-drift helper | scripts/pixel-drift.sh | | Unit tests | tests/run_unit_tests.sh | | Capture / computed-CSS / pixel-diff mechanics | references/playwright-fallback.md | | MCP route + browser-state security | references/chrome-devtools-mcp.md | | Per-repo config | /.design-fidelity.json | | Screenshot output (OUTSIDE any repo) | ~/DevProjects/screenshots// |
Skill Surface Contract
- Inputs: a
base_url(local build or live), a page→path map, viewports, and optional selectors. Via.design-fidelity.jsonand/or CLI overrides. - Outputs: full-page PNGs + diff-highlight PNGs under
~/DevProjects/screenshots//; computed-CSS deltas + drift numbers on stdout; decision-branch telemetry on stderr. - Never writes into the consumer repo tree; never deploys; never edits the live site.
- Exit codes are load-bearing (AP #16): the helpers fail loud on a missing dependency, a blocked PNG coder, or a missing selector rather than producing a silent empty result.
- The
.design-fidelity.jsonconfig is treated as UNTRUSTED (it is repo-local, so a cloned repo could ship a hostile one).shoot.py: the opt-inhugo.cmdlauncher spawns NOTHING unless the operator passes the explicit--allow-hugo-launcherCLI flag (config alone can never start a process); when enabled it allowlists the executable to STATIC dev-servers only (hugo/jekyll/vite/serve/http-server — bare PATH names, no./hugopath component — and no interpreters ornpm run-style wrappers) and rejects inline-code/eval flags;base_urlis http(s)-only (nofile://); page labels + viewport names must be[A-Za-z0-9_-]+; viewport width/height must be ints in1..8192;scroll.stepmust be a positive int (settle clamped);out_dirmust resolve strictly UNDER$HOMEor the system temp dir. Each violation is a loud exit 2. - Residual trust the threat model deliberately does NOT remove — only pass
--allow-hugo-launcheron a repo you TRUST: (1)viteandjekyllexecute the repo's OWN build config (vite.config.{js,ts}, Jekyll_config.yml/_plugins) by design when they start, so launching them runs that repo's build code;hugo/serve/http-serverdo not. (2)base_url/page paths are scheme-restricted to http(s) but NOT host-filtered (the tool MUST reachhttp://127.0.0.1:for local builds), so a hostile config can point captures at internal/loopback/cloud-metadata HTTP endpoints (e.g.169.254.169.254) — do not run an untrusted repo's config on a host with sensitive internal HTTP reachability.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: hoiung
- Source: hoiung/sst3-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.