Install
$ agentstack add skill-nathanonn-agent-skills-extract-design-md ✓ 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
Extract DESIGN.md from a site
Given a live URL, produce a DESIGN.md — YAML design tokens (colors, typography, rounded, spacing, components) plus prose in canonical section order — good enough to hand a coding agent so it builds new UI matching the source site.
Core idea (from research): tokens map ~1:1 to a site's CSS custom properties + computed styles, so the heavy lifting is a cheap in-browser extraction — not vision. Screenshots feed prose only. The official linter is a free quality gate.
URL ─▶ 1 DISCOVER ─▶ 2 EXTRACT TOKENS ─▶ 3 HARVEST COMPONENTS
─▶ 4 CAPTURE FEEL ─▶ 5 SYNTHESIZE ─▶ 6 VALIDATE ─▶ DESIGN.md
Prerequisites
This skill drives three external tools — make sure each is available before running:
- playwright-cli on
PATH— the in-browser
extraction and screenshots run through it. Install once with npm install -g @playwright/cli@latest then playwright-cli install --skills (needs Node.js 18+). Check: which playwright-cli.
- A reachable Firecrawl instance — used for page
discovery (firecrawl map) and optional copy scraping. The hosted API or a self-hosted / local instance both work; if Firecrawl is unreachable the skill falls back to playwright link discovery (thinner page coverage). Confirm your instance responds before a run.
npx(Node.js) — pulls the official@google/design.mdlinter on demand for the quality
gate. If it's unavailable the skill writes the file anyway and notes "lint skipped".
> If your agent sandboxes network or filesystem access, allow the outbound calls this skill makes > (headless browsing, Firecrawl, npx) before running.
Let SKILL = this skill's directory. Pick a stable playwright session name, e.g. S=designmd.
Flags
| Flag | Default | Effect | |---|---|---| | ` | required | Entry-point URL | | --pages | 5 | Max pages to sample | | --pages-list | auto | Pin exact pages (skips the confirm prompt) | | --no-screenshots | shots ON | Skip the feel pass; prose then leans on token names + copy | | --theme | auto | auto detects; both forces dual; light/dark pin one | | --out | .design_mds/-YYYYMMDD/ | Output folder | | --no-lint | lint ON | Skip the linter (auto-skips if npx` is unavailable) |
Stage 1 — Discover pages
firecrawl map "" > "/raw/map.json"
Bucket the returned URLs into page-type slots and pick the best match per slot (always include the homepage), capped at --pages (default 5):
- homepage (the input URL, always) — core palette + type + hero CTA
- pricing / product — cards, toggles, tables
- auth / login / signup / contact — inputs, form fields
- blog / docs / changelog — long-form prose type
- brand / about / design — often states colors & fonts explicitly; high value
Show the auto-picked list and accept add/remove/replace before crawling (one concise prompt; skip it if --pages-list was given). Skip a slot with no match — never force a sample. If Firecrawl is down, fall back to playwright link discovery (run-code returning [...document.links].map(a=>a.href)) — see references/edge-cases.md.
Stage 2 — Extract global tokens (the core)
Open the homepage, wait for it to settle, run the bundled extractor. The extractor (scripts/extract-tokens.js) reads noise-filtered :root vars, mode-samples computed styles of visible main-content elements, tags the prominent CTA + first input, and forces hover/focus — see references/extraction.md for what it returns and why.
Intermediate artifacts live under /raw/ so the two deliverables stay uncluttered at the folder root — see [Output layout](#output-layout). Create the folders once:
S=designmd
mkdir -p "/raw/tokens" "/raw/components" "/raw/copy" "/raw/logs" "/screenshots"
playwright-cli -s=$S open ""
sleep 2 # let CSS/fonts settle (FR-ROB.1)
playwright-cli -s=$S run-code "$(cat "$SKILL/scripts/extract-tokens.js")" \
| bash "$SKILL/scripts/slice-result.sh" > "/raw/tokens/tokens.home.json"
slice-result.sh strips playwright-cli's markdown wrapper so you get clean JSON. Read it back and sanity-check varsTotal / vars count. If vars is thin (the site isn't Tailwind-ish), relax the filter using varsExtra — see references/edge-cases.md (EC-FW.1 / no-design-system).
Theme detection (decision 8)
Inspect themeSignal in the JSON. A site is dual-theme when it exposes a light/dark switch — a .dark class or data-theme on `, or a prefers-color-scheme response. When two themes exist and --theme is auto/both, extract **once per theme**: toggle, re-settle, re-run the extractor into a second file (raw/tokens/tokens.home.dark.json`). Toggle order of preference:
- click the site's own theme switch, else
- set the class/attribute directly, e.g.
run-codedoingdocument.documentElement.classList.add('dark')(orsetAttribute('data-theme','dark')), else - emulate
prefers-color-scheme.
Re-sleep 2 after toggling. If the alternate theme can't be triggered reliably, capture the loaded theme only, emit one DESIGN.md, and say so in the report. --theme light|dark pins one theme even on a dual-theme site. Full detail: references/edge-cases.md (EC-TH).
Stage 3 — Harvest components + states (pages 2–N)
For each additional page, don't re-dump global vars (they're shared) — sample the components that page is good for (inputs on auth, cards/toggles on pricing, prose on blog). Reuse the same extractor; keep each page's JSON:
playwright-cli -s=$S goto ""
sleep 2
playwright-cli -s=$S run-code "$(cat "$SKILL/scripts/extract-tokens.js")" \
| bash "$SKILL/scripts/slice-result.sh" > "/raw/tokens/tokens..json"
Any bespoke per-page component captures (card/pill candidates, etc.) go to /raw/components/; scraped copy to /raw/copy/; per-step logs to /raw/logs/.
The extractor already forces hover on the CTA and focus on the first input and returns the diffs in states. Keep only states that differ from the base (FR-ST.3) when you synthesize. Merge across pages: union the CSS vars (homepage wins the core palette, flag conflicts); accumulate components, collapsing identical styles.
Stage 4 — Capture feel (optional, default ON)
One viewport screenshot per sampled page (not full-page), into screenshots/:
playwright-cli -s=$S screenshot --filename="/screenshots/.png"
Optionally firecrawl scrape --only-main-content "" the homepage + brand page for copy/tagline, saved to /raw/copy/. Screenshots stay at /screenshots/ (they feed prose and the user may look at them). Screenshots and copy feed prose only (Overview, Do's & Don'ts) — never read token values off them. --no-screenshots skips this stage.
Stage 5 — Synthesize the DESIGN file(s)
Read the merged raw/tokens/*.json and map them onto the DESIGN.md schema. The full schema, the token→DESIGN mapping table, and the canonical prose section order live in references/design-md-schema.md — read it before writing the file. Key rules:
- Resolve primary-palette colors to hex from the computed
rgb(...)values; keep the
raw CSS var (lab()/color-mix() etc.) as a fallback. Never invent a color.
- Name colors by semantic role (
--color-accent→primary/accent); fold long
gray ramps into a representative neutral set — capture the system, not every shade.
- Use
{path.to.token}refs insidecomponentsso values stay DRY and the linter
validates them. A primary color must exist or the linter errors.
- Capture only components the pages actually expose (decision 10) — never invent a
card/chip that isn't there. Track which of the common set (button, input, card, link, chip) were found vs. missing for the report.
- Emit prose sections only where you have real evidence, always in canonical order,
never a duplicate ## heading.
Dual-theme output (decision 8)
When two themes were captured, emit DESIGN.light.md + DESIGN.dark.md — each a complete, lint-valid file. typography, rounded, and spacing are shared; colors and any color-dependent components are per theme. A single-theme site emits one DESIGN.md. Prose may note the sibling theme exists.
Stage 6 — Validate (quality gate)
Lint every generated file:
npx -y @google/design.md lint "/DESIGN.md"
- Auto-fix structural errors only: wrong section order, broken
{refs}, missing
primary/required fields.
- Flag value-level issues (out-of-gamut color, odd dimension) in the report —
never silently delete a captured token to satisfy the linter (decision 12). The user decides on flagged values.
- Surface non-fatal warnings (e.g. WCAG AA contrast) without blocking.
- Re-lint after fixes; the final file must be error-clean. If
npx/the linter is
unavailable, write the file anyway and warn "lint skipped" in the report.
Output layout
The two deliverables sit at the folder root; everything intermediate is tucked under raw/ so the output reads cleanly at a glance.
.design_mds/-YYYYMMDD/ # = host with dots→hyphens
├── DESIGN.md # single-theme (or DESIGN.light.md + DESIGN.dark.md)
├── screenshots/.png # 1 desktop-viewport PNG per page (if enabled)
└── raw/ # intermediate artifacts (audit trail + re-runs)
├── tokens/tokens..json # raw extracted token/computed-style data per page/theme
├── components/ # any bespoke per-page component captures
├── copy/ # scraped page copy (if screenshots stage ran)
├── logs/ # per-step playwright/firecrawl logs
└── map.json # firecrawl page-discovery result
The raw/tokens/*.json are always kept (decision 9) so prose can be regenerated without re-crawling and any value is traceable. Conflict guard: if the folder already exists for today's domain, ask (overwrite / suffix -2 / abort) — never silently overwrite.
Final report
Keep it tight and honest. State what was captured, which components were found vs. missing, which themes, and exactly what the linter said. If a stage degraded (no design system, Firecrawl down, lint skipped), say so — don't imply full fidelity.
DESIGN.light.md + DESIGN.dark.md → .design_mds/cursor-com-20260630/
Sampled 4 pages: home, pricing, sign-in, blog
Themes: light + dark (detected via .dark on )
Captured: 9 colors/theme, 6 type roles, 7 radius, full spacing
Components found: button-primary (+hover), input-field (+focus), card · missing: chip
Lint: ✓ both files clean (1 contrast warning on dark: text-muted on bg — AA borderline)
Screenshots: screenshots/ (4, desktop viewport)
Ask-first rule (standing)
Whenever <95% confident about a mapping or an ambiguous choice — which of two colors is "primary", whether a site even has a real design system, how to resolve a same-day output conflict — ask with a recommendation rather than guess. At minimum, surface the ambiguity in the report. Any sub-agents you spawn run sequentially, never in parallel, and must carry the Firecrawl + sandbox rules above.
Bundled files
scripts/extract-tokens.js— the in-browser extractor forrun-code(noise filter,
mode sampling, CTA/input detection, hover/focus). The proven nucleus, productionized.
scripts/slice-result.sh— strips playwright-cli's markdown wrapper to clean JSON.references/extraction.md— what the extractor returns, field by field, and how to
use varsExtra to relax the filter.
references/design-md-schema.md— the DESIGN.md YAML schema, token→DESIGN mapping
table, and canonical prose order. Read before Stage 5.
references/edge-cases.md— no design system, non-Tailwind, dual-theme toggling,
merge conflicts, crawl/load failures, empty results.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: nathanonn
- Source: nathanonn/agent-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.