Claude
Skills
Sign in
Back

distill

Included with Lifetime
$97 forever

Analyze a set of design samples (HTML mockups + website URLs) and produce a structured style guide that anchors the rest of the stardust redesign pipeline. Use when the user supplies reference designs ("design samples", "mockups", "inspiration sites", "style references") and wants to extract a consistent visual language — type system, color palette, spacing, motion, and reusable component patterns — before redesigning a target site. Triggers on phrases like "distill these samples", "extract a style guide from these examples", "use these as design references", or "analyze these mockups". Outputs a `trait-matrix.json` (structured per-sample + cross-sample design tokens) and a `SAMPLES.md` narrative brief that `stardust:direct` reads under Mode B (anchor-reference precedence) when picking a redesign direction.

Design

What this skill does


# stardust:distill

Read a directory of user-provided design samples — static HTML files
the user has placed under `samples/static/`, plus a `samples/live/urls.json`
manifest of live URLs to fetch — and produce two artifacts that anchor
the rest of the stardust pipeline:

1. `samples/trait-matrix.json` — structured per-sample + cross-sample
   trait data (type system, color, spacing, motion, component
   patterns, voice, assets).
2. `samples/SAMPLES.md` — a narrative vocabulary brief, the file
   `stardust:direct` reads under Mode B as the resolved anchor set.

This skill is **descriptive and pre-extract**. It does not crawl an
origin (that is extract's job). It does not invent design opinions
(that is direct's job). It produces the brief the user hands to direct
as Mode B anchor references when they want stardust to follow a
specific visual language — captured from samples — instead of rolling
the divergence seed cold.

Distill is optional. Users who do not have samples skip straight to
extract. Distill becomes load-bearing when the user has been
instructed by a brand team, a designer, or an art director to honor
specific reference material that is *not* the existing site (the
common case: a refresh whose visual direction has been pre-set by
design leadership and arrives as a folder of HTML + screenshots).

## Inputs

- `<samples-dir>` — optional positional. Defaults to `samples/`.
- `--from-static` — distill only static samples; skip live fetching.
  Use when no live URLs are listed or when the user wants to defer
  the live pass.
- `--from-live` — distill only live samples; skip static parsing.
  Use when the static pass has already run and only live snapshots
  need refreshing.
- `--cap <N>` — cap live URLs to fetch (default 8). Matches extract's
  small-sample philosophy: 8 reference URLs is enough to triangulate
  a visual language without burning budget on near-duplicates.
- `--refresh` — re-fetch and re-parse every sample even if cached
  snapshots exist under `samples/live/snapshots/`. Default behaviour
  is to reuse cached snapshots and only fetch URLs that are missing.

## Setup

Run the master skill's setup procedure first
(`skills/stardust/SKILL.md` § Setup): impeccable dep check, context
loader, state read.

Additional checks for this sub-command:

1. **Playwright availability** — same dep check as extract. The live
   pass needs a real browser. Detect Playwright in this order: a
   Playwright MCP server, then `npx playwright`. If neither is
   available and `--from-static` was not passed, stop and tell the
   user how to install Playwright.
2. **Samples directory structure** — verify the input dir exists and
   contains at least one of: `static/<sample>/`, `live/urls.json`.
   If neither, stop and explain the expected layout:
   ```
   samples/
     static/
       <sample-1>/
         index.html         (or any .html file)
         assets/            (optional; reused if present)
       <sample-2>/
         ...
     live/
       urls.json            (array of { url, slug?, role? } objects)
   ```
3. **State precedence** — if `stardust/state.json` already records a
   `samples.distilledAt` timestamp and `--refresh` was not passed,
   ask whether the user wants to re-distill (overwriting) or skip.
   Distill is idempotent; re-running it overwrites the prior brief
   and trait matrix.

## Procedure

### Phase 1 — Inventory the static samples

For each subdirectory of `samples/static/`:

1. Identify the entry HTML file (`index.html` if present, otherwise
   the largest `.html` file by size).
2. Read the file and its referenced stylesheets (inline `<style>` +
   linked `<link rel="stylesheet">` resolved relative to the sample
   dir, both `samples/static/<sample>/...` and any sibling
   `assets/` directory).
3. If a screenshot or PDF lives in the sample dir, note its path —
   reviewers may want to compare against the parsed traits.
4. Record an entry in the in-memory inventory:
   `{ slug, kind: "static", entryHtml, stylesheets[], screenshot?,
   role? }`. The role (if any) is inferred from the directory name
   (`bizpro-hub-prototype` → `business`; `plan-page` →
   `pricing`; etc.) — store the inference, surface to user for
   correction.

### Phase 2 — Fetch the live samples

If `live/urls.json` exists and `--from-static` was not passed:

1. Read the manifest. Each entry: `{ url, slug?, role? }`. Auto-
   generate `slug` from the URL hostname + path if missing.
2. For each URL (capped per `--cap`):
   - Check cache: if `live/snapshots/<slug>.html` + `.png` exist and
     `--refresh` was not passed, skip the fetch and use the cached
     pair.
   - Otherwise, render with Playwright following `extract`'s
     `playwright-recipe.md`: viewport 1440 × 900 @ 2× DPR, wait
     mode `medium`, reduced motion, scroll-to-bottom pass, capture
     the full DOM + a full-page screenshot.
   - Save:
     - `live/snapshots/<slug>.html` (rendered DOM)
     - `live/snapshots/<slug>.png` (full-page screenshot)
     - `live/snapshots/<slug>.log` (one-line provenance:
       `{ url, fetchedAt, waitMs, status }`)
3. Record an entry in the inventory:
   `{ slug, kind: "live", url, snapshotHtml, snapshotPng,
   snapshotLog, role? }`.

### Phase 3 — Per-sample trait extraction

For each entry in the inventory, parse the HTML + computed styles
(use a headless browser pass with `getComputedStyle()` on representative
elements — same technique as extract's per-section style summary).
Extract per-sample:

- **Type system** — every named CSS variable matching
  `--*font-*`, `--*type-*`, plus computed style on every heading,
  body paragraph, button, eyebrow, link. Aggregate into
  `{ headingFamily, bodyFamily, labelFamily, weights[], scale: {
  title-1, title-2, ..., body-lg, body-sm, eyebrow, label },
  rules[] }`. Detect modular scale per `extract/reference/brand-surface.md`
  § Modular-scale audit.
- **Color** — every named CSS variable matching `--*color-*`,
  `--*bg-*`, `--*surface-*`, `--*text-*`, plus computed background-
  color and color on representative elements. Aggregate into
  `{ palette: { neutrals[], brand: {}, surfaces: {} },
  reservations: [{ color, reservedFor[] }], rules[] }`. The
  `reservedFor` list is inferred from class names + CSS selectors
  (e.g., `.brand-mnemonic` ⇒ `reservedFor: ["brand-mnemonic"]`).
- **Spacing** — every named CSS variable matching `--*space-*`,
  `--*spacing-*`, `--*pad-*`, `--*gap-*`. Detect density tier
  (compact / balanced / packed) by clustering section padding
  values per `intent-dimensions.md` § 4.
- **Radius / shadow / motion tokens** — every named CSS variable
  matching `--*radius-*`, `--*shadow-*`, `--*ease-*`, `--*duration-*`,
  `--*motion-*`.
- **Motion stack** — detect loaded libraries via `<script src=>`
  inspection: GSAP, ScrollTrigger, Lenis, Locomotive, Three.js,
  Splide, Swiper. Pin versions where readable from the URL. Detect
  CSS-only motion patterns by scanning for `animation-timeline:`,
  `@keyframes`, `transition:`. Record:
  ```
  {
    libraries: [{ name, version?, role }],
    cssOnlyPatterns: ["animation-timeline: view(block)", ...],
    choreographies: [{ name, surface, mechanism, capturedFrom }]
  }
  ```
- **Component patterns** — detect repeating DOM signatures: card
  grid, banner, navigation anatomy, hero composition. Per
  `extract/reference/brand-surface.md` § System components. For
  each pattern, record `{ kind, shape, instanceCount, examples[] }`
  — the examples include enough markup snippet for direct to
  understand the captured shape.
- **Voice samples** — the hero headline, first body paragraph, three
  representative CTAs, three navigation labels, the footer line.
  Same fields as extract's voice block; the difference is voice is
  per-sample here (not aggregated cross-sample, since samples may
  represent different registers).
- **Asset inventory** — fonts (`@font-face` declarations + their
  `src` URLs), images (with intrinsic dimensions), inline SVGs.
  Per-sample; 
Files: 3
Size: 27.8 KB
Complexity: 53/100
Category: Design

Related in Design