About distill-design
A skill that inspects a live website and produces a structured `DESIGN.md` design-system specification for AI agents. It prioritizes measured visual tokens and generates previews or demos only on request.
Key features
- 01Extracts design details from live pages
- 02Measures styles with a headless browser
- 03Writes an 11-section `DESIGN.md`
- 04Can create optional HTML previews and demos
Use cases
- 01Documenting a website's design system
- 02Preparing brand references for AI-generated UI
- 03Creating a visual token preview when requested
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ ake77-code/ distill-design --skill distill-designAfter installing, type/distill-designin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
reference/demo-guide.mdextraction-guide.mdformat-spec.mdpreview-template.htmltemplate.mdDetails
From the project README/distill-design — Distill a DESIGN.md from a website
Turn a live website into a DESIGN.md: a plain-text design-system spec (YAML
token frontmatter + 11 prose sections) that any AI agent can read to generate
on-brand UI. Concept and format follow
VoltAgent/awesome-design-md.
Argument: a website URL ($ARGUMENTS). If none was given, ask for one.
What gets produced: by default, only DESIGN.md. The visual preview.html
and the realistic demo.html are opt-in — generate them only when the user
asks (see the two "on request" sections below).
Read these first
reference/format-spec.md— the exact frontmatter schema and 11-section body.reference/extraction-guide.md— how to measure tokens off a live site.reference/template.md— theDESIGN.mdskeleton you fill in.reference/preview-template.html— the canonical, data-drivenpreview.html. Copy it verbatim and inject only the token JSON (see "Generate the token preview").reference/demo-guide.md— how to build the realistic demo (only when asked). (These ship next to thisSKILL.md, so read them as siblings.) Thepreview.htmlshell is the same for every brand — use the template above, never hand-write it. For a bespokedemo.html, the sample foldersexamples/stripe,examples/linear,examples/spotifyin the source repo (ake77-code/distill-design) are references.
Where to write output
By default, write into the current project (not this skill's own folder):
- A single spec →
./DESIGN.md(project root). An optionalpreview.html/demo.htmlgo alongside it only when requested. - Several specs → use a
distill-design/<brand>/folder per brand. - Always honor an explicit path the user gives.
Workflow
1. Scope the target
Confirm the URL. Identify a few page types worth inspecting beyond the homepage: marketing, pricing, docs, and the app/dashboard if reachable. Brands often flip polarity (light marketing → dark app) — plan to capture both.
2. Inspect & measure
Prefer measured values over guesses. Drive a real headless browser and read
getComputedStyle — try these in strict order, stop at the first that works
(full snippets in extraction-guide.md):
- Playwright (preferred) — script Chromium via Bash; install with
npx -y playwright install chromium(orbunx playwright install chromium) if missing, thenpage.$eval(sel, …)to read exact hex, font stacks, radii, padding, shadows. Screenshot too. (npxandbunxare interchangeable throughout.) - Puppeteer (fallback) — same approach via
require("puppeteer")if Playwright is unavailable; install withnpx -y puppeteer browsers install chrome(or thebunxequivalent). - Browser MCP (Chrome / Preview) — only if one is already connected.
WebFetch/ fetch (LAST RESORT) — text only, no pixel values. Use ONLY when no browser can run; combine with brand knowledge and label the output an inspired interpretation in the Colors note and## Known Gaps.
Sweep heros, body text, buttons, cards, nav, inputs, and footer. Pull colors → roles, the type scale, radius scale, spacing base unit, elevation, per-component specs and states, and the 2–3 signature motifs.
3. Map to tokens — go DEEP
The most common failure is a too-thin file. Real brands have many tokens; match that
depth (see format-spec.md for the targets):
- Colors ~18–30+, named by role, kept FLAT. Carry polarity inside
colors:with*-on-darktext variants andsurface-dark-*tiles; tier muted inks by approximate opacity in the name (ink-muted-64). Only dedupe same-role hexes within ~2%. - Typography ~12–20 SEMANTIC roles (
hero-display,lead,tagline,body-strong,dense-link,caption-strong,button-large,fine-print,micro-legal,nav-link), each with weight, line-height,letterSpacingin px, andfontFeatureonly when real. Capture rare weights (300 / 600-vs-700). roundedwithnone:0+full;spacingwith measured oddities (17px) and asectionstep. Use measured values, not idealized 4/8/12.- Components ~15–30+, each a
{group.token}composition (literal padding/height/ size allowed). Variants are SEPARATE keys (-active,-focus,-selected,-2). Never documenthover. - Choose an open-source substitute for any proprietary font.
4. Write DESIGN.md
Fill reference/template.md into the output path (default ./DESIGN.md — see
"Where to write output"). Follow the 11-section structure and the prose tone of the
bundled samples. name: is <Brand>-design-analysis. The frontmatter description is
the most important field — one dense paragraph on a single line (plain scalar, not a
> block) vivid enough to picture the site with eyes closed.
5. Self-check the DESIGN.md
- Frontmatter is valid YAML; run a quick parse if unsure (see verification below).
- Every
{group.token}in the body resolves to a defined frontmatter key. - All 11 sections present and non-empty (Overview → Known Gaps), including the
required
## Known Gaps. - Depth targets met (~18+ colors, ~12+ type roles, ~15+ components).
descriptionis inline. No-hovercomponent keys (brief prose hover is fine).letterSpacingin px. - Colors are role-named and deduped; proprietary fonts have a substitute.
6. Offer the visualizations (always end with this)
The DESIGN.md is the deliverable. Do not auto-generate preview.html or
demo.html. End your reply by reminding the user they can opt into either, e.g.:
已生成
DESIGN.md。需要的话我还能基于它生成: ①preview.html—— 设计系统可视化(色板 / 字阶 / 组件,带顶部导航与明暗切换); ②demo.html—— 像真实网站的 Web 落地页或移动端界面。 两者都按需生成,要哪个告诉我。
(Match the user's language.) Generate preview.html only if asked → follow
"Generate the token preview" below. Generate demo.html only if asked → follow
"Generate a realistic demo" below.
Generate the token preview preview.html (on request)
Do NOT hand-write per-brand HTML/CSS. The preview shell is identical for every
website — only the injected data changes. The skill ships one canonical, data-driven
template: reference/preview-template.html — a polished design-system showcase page:
a sticky nav (the brand wordmark + a distill-design GitHub chip that links to
github.com/ake77-code/distill-design + section anchors + light/dark toggle + a CTA),
a two-column hero (Design System Analysis of <displayName> + the description + a
device-mock card), then numbered sections
("01 — Color Palette", "02 — Typography Scale", "03 — Components", "04 — Spacing &
Radius", "05 — Elevation & Depth", "06 — Responsive Behavior") rendering grouped swatch
cards, a type ladder, a component gallery, spacing/radius blocks, and a breakpoints
table. No footer. Zero dependencies (system fonts, no CDN).
To generate a brand's preview.html:
- Copy
reference/preview-template.htmlverbatim to<output>/preview.html. - Replace ONLY the JSON inside
<script type="application/json" id="design-data">with the brand's tokens, derived from the DESIGN.md. Change nothing else — the shell, CSS, and renderer stay byte-identical across brands.
The injected JSON schema (see the comment above that block in the template):
meta:{ name, displayName, description, source, nativeTheme: "light"|"dark", navCta, heroCtas, sections? }.nameis the real brand; the hero reads "Design System Analysis ofdisplayName" — setdisplayNameto the real brand name (e.g. "Apple", "Stripe", "Figma"). Do NOT invent fictional product names — use the actual brand the URL belongs to.descriptionis the frontmatter description verbatim;sourceis the live URL;nativeThemeis the brand's polarity (dark for Linear etc.). OptionalnavCta(nav button label, e.g. "Buy" / "Get started") andheroCtas["Learn more","Buy"]set the brand's CTA wording. OptionalheroArtpicks the hero visual to match the signature motif:device(default product mock),mesh(gradient-mesh fill — Stripe-like brands), orglow(dark glow — Linear-like brands). Optionalsections={ colors:{heading,intro}, typography:{...}, components:{...} }gives each section a brand-voiced heading/intro (e.g. "One blue. Three near-blacks.") pulled from the matching DESIGN.md body sections; omit for defaults.colors: the flat palette as role→hex (rgba strings ok). Every role renders as a swatch, auto-grouped (Brand & Accent / Surface / Text / Hairlines & Borders / Semantic).colorRoles(optional, recommended):{ role: "one-line description" }— the per-color usage note from the DESIGN.md Colors section; shows as the swatch's 3rd line so cards match the reference depth.colorNames(optional):{ role: "Friendly Name" }→ renders as "role (Friendly Name)".colorsDark: optional opposite-polarity overrides (else dark is synthesized).typography: role→{ fontFamily, fontSize, fontWeight, lineHeight, letterSpacing }.rounded,spacing: token→value maps.components: role→{ backgroundColor, textColor, typography, rounded, padding, border, height, size }; values may use{group.token}refs (resolved by the renderer) so each gallery sample renders in the real component style.responsive(optional):{ breakpoints:[{name,width,changes}], touchTargets, collapsing, imageBehavior }from the DESIGN.md Responsive Behavior section — drives "06 — Responsive Behavior". Omit the whole key to hide the section.
The template already provides the nav, hero, numbered sections, swatch grouping,
type ladder, component gallery, spacing/radius/elevation blocks, a responsive
breakpoints table, and the
light/dark toggle (localStorage). The nav wordmark shows the brand name
(not a third-party brand); the GitHub chip reads distill-design and points at
github.com/ake77-code/distill-design.
After injecting the data, verify it opens standalone (file://) and visually reads as
a polished design-system analysis page in the brand's colors. For pixel-level reference,
the awesome-design-md project renders each brand at getdesign.md/design-md/<brand>/preview.html.
Generate a realistic demo demo.html (on request)
Goal: a single .html file with zero external dependencies (all CSS/JS inline,
no CDN, no network requests — system/-apple-system font stacks only) that reads
like a real product, not a token catalog. It is distinct from preview.html:
preview.html documents the system; the demo uses it to ship a believable page.
Read reference/demo-guide.md for the full recipe. In short:
- Ask form factor if unclear: Web (responsive landing page) or Mobile (a phone-framed app screen). Default to Web.
- Build a real page from the tokens — pull every color, font, radius, spacing,
shadow and component straight from the
DESIGN.md:- Web: sticky nav → hero (headline + sub + primary/secondary CTA) → social-proof logos → 3-up feature cards → pricing tiers → testimonial → CTA band → footer.
- Mobile: a phone frame (status bar, notch) wrapping a real app screen — top bar, content list/feed/cards, and a bottom tab bar or now-playing/sticky CTA.
- Make it feel real — plausible copy and product name, the brand's signature
motif (e.g. gradient mesh, glow hairlines, green play button), realistic imagery
via inline SVG/CSS gradients (never hot-link external images), and tasteful
hover/scroll micro-interactions in a tiny inline
<script>. - Save next to the spec as
demo.html(ordemo-mobile.html). - Verify it opens standalone (double-click /
file://) with no console errors and visibly resembles a real site in the brand's language.
Verify
# YAML frontmatter parses (frontmatter is between the first two '---' lines)
python3 - "$f" <<'PY'
import sys, yaml
t = open(sys.argv[1]).read().split('---', 2)
yaml.safe_load(t[1]); print("frontmatter OK")
PY
Then grep the spec for the two most common slips — both must return nothing:
grep -nE '^\s+[a-z0-9-]*-hover:' "$f" # no hover-STATE component keys (prose ok)
grep -c '^## ' "$f" # must be 11 (Overview … Known Gaps)
If you generated a preview.html or demo.html, open it in a browser — or
screenshot it with a browser MCP — and confirm it renders in the brand's language.
Notes
- Keep folder names lowercase, URL-safe (
stripe,together.ai). name:is<Brand>-design-analysis. When values are interpreted (WebFetch-only, no measured CSS) rather than officially sanctioned, say so in the Colors source-pages note and the## Known Gapssection — don't fabricate precision.- One brand per folder; document state variants as separate component keys; never hover.