plugins/stardust/skills/distill/SKILL.md
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.
npx skillsauth add adobe/skills distillInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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:
samples/trait-matrix.json — structured per-sample + cross-sample
trait data (type system, color, spacing, motion, component
patterns, voice, assets).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).
<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.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:
npx playwright. If neither is
available and --from-static was not passed, stop and tell the
user how to install Playwright.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)
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.For each subdirectory of samples/static/:
index.html if present, otherwise
the largest .html file by size).<style> +
linked <link rel="stylesheet"> resolved relative to the sample
dir, both samples/static/<sample>/... and any sibling
assets/ directory).{ 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.If live/urls.json exists and --from-static was not passed:
{ url, slug?, role? }. Auto-
generate slug from the URL hostname + path if missing.--cap):
live/snapshots/<slug>.html + .png exist and
--refresh was not passed, skip the fetch and use the cached
pair.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.live/snapshots/<slug>.html (rendered DOM)live/snapshots/<slug>.png (full-page screenshot)live/snapshots/<slug>.log (one-line provenance:
{ url, fetchedAt, waitMs, status }){ slug, kind: "live", url, snapshotHtml, snapshotPng, snapshotLog, role? }.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:
--*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-*,
--*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"]).--*space-*,
--*spacing-*, --*pad-*, --*gap-*. Detect density tier
(compact / balanced / packed) by clustering section padding
values per intent-dimensions.md § 4.--*radius-*, --*shadow-*, --*ease-*, --*duration-*,
--*motion-*.<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 }]
}
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.@font-face declarations + their
src URLs), images (with intrinsic dimensions), inline SVGs.
Per-sample; cached locally if accessible.Save the per-sample data into the trait matrix's samples[] array.
Walk the per-sample data and produce the sharedTokens block. A
token is "shared" if at least ceil(N/2) samples carry the same
value (after near-duplicate clustering for colors). Otherwise it
goes into divergentTraits with a per-sample breakdown.
Aggregate:
sharedTokens.type — type families, weights, scale that recur.sharedTokens.color — neutrals + brand + surface tokens that
recur; reservations are union'd (one sample's reservation is
enough to honor).sharedTokens.spacing — section padding and grid that recur.sharedTokens.radius / shadow / easing / duration — modal values.sharedTokens.motionStack — libraries loaded by ≥1 sample (motion
is opt-in, not majority-rule).divergentTraits — anything that didn't reach the majority
threshold. Direct reads this to know which traits to amplify
in the B/C/... variants (the "captured trait amplified" role).SAMPLES.md is the load-bearing artifact direct reads under Mode B.
Format per reference/samples-brief-format.md:
writtenBy,
writtenAt, readArtifacts, samples, stardustRole.direct/reference/direction-format.md
§ Brand-faithful inversions).Author directly — distillation does not need impeccable's authoring
ceremony. SAMPLES.md is consumed by direct as factual input, not
as design opinion.
After all phases succeed:
stardust/state.json (add a samples block if absent):
"samples": {
"distilledAt": "<ISO-8601>",
"samplesDir": "samples/",
"brief": "samples/SAMPLES.md",
"traitMatrix": "samples/trait-matrix.json",
"inventory": [
{ "slug": "bizpro-hub", "kind": "static", "role": "business" },
{ "slug": "sr-homepage", "kind": "live", "url": "...", "role": "consumer-creative" },
...
]
}
Distilled 3 samples (2 static, 1 live)
samples/
SAMPLES.md (8 sections, 4 motion choreographies named)
trait-matrix.json (12 shared tokens, 4 divergent traits)
live/snapshots/ (1 file)
Per-sample evidence:
slug kind role typeFam motion-libs
bizpro-hub static business adobe-clean-display Lenis 1.x, GSAP 3
plan-page static pricing adobe-clean-display Lenis 1.x
sr-homepage live consumer-creative adobe-clean-display Lenis 1.x, GSAP 3
Shared tokens: type (12), color (8), spacing (10), motion (2 libs)
Divergent traits (amplification candidates):
- scroll-driven choreography (bizpro-hub strongest)
- photography-led tile vocabulary (sr-homepage strongest)
- pricing-tier card density (plan-page strongest)
Next: $stardust direct "<phrase referencing SAMPLES.md>" --variants 3
Distill is optional. Three common scenarios:
$stardust extract →
$stardust direct directly. Mode A (brand-faithful) handles the
common case — palette and type are pinned to the captured site,
variants explore expressive / density / motion axes within the
captured surface. Distill is not invoked.direct "<phrase referencing SAMPLES.md>".
Mode B's anchor-reference precedence (per direct/SKILL.md
§ Mode B) reads SAMPLES.md as the resolved anchor set; Mode A's
palette + type inheritance still applies because the captured
brand wins on those axes. Distillation contributes the non-brand
axes: motion stack, component shapes, density tier, choreography
names.direct --rebrand "<phrase>". Distillation supplies the entire palette
Distill consumes a directory the user assembles by hand. Common sources for samples:
samples/live/urls.json; distill fetches them.Distill does not curate samples for the user; it does not invent sample sources; it does not fetch arbitrary URLs the user didn't list. If the samples are wrong, the brief will be wrong; this is intentional — distill is a faithful descriptor, not a curator.
Every artifact distill writes carries a provenance block with at
minimum: writtenBy: stardust:distill, writtenAt: <ISO-8601>,
readArtifacts: [...] (every sample file consumed),
consumedBy: "stardust:direct — Mode B anchor resolution".
reference/samples-brief-format.md — the narrative-brief format the SAMPLES.md output follows.reference/trait-matrix-schema.md — the per-sample and cross-sample schema the trait-matrix.json output follows.tools
Use the run-workflow MCP to discover, compose, execute, publish, and save Adobe Firefly workflows. TRIGGER when: user asks what actions are available, what the MCP can do, how to process images/video/3D via workflow, wants to build/run/save/publish a workflow, OR pastes any workflow/batch/execution ID. BARE ID (UUID/workflowId/batchId) = INSPECT ONLY — call inspect_run, NEVER run_workflow_submit. ALWAYS call list_actions first for capability/discovery questions. DO NOT TRIGGER for direct Firefly API calls without MCP (use firefly-api-specs).
tools
Run predefined featured workflows via run-workflow MCP. TRIGGER when user names a featured workflow (retargeting, banners at scale, localization, packaging, banner advertising, etc.) or asks to run a known marketing/production workflow. Requires run-workflow MCP. ALWAYS call get_featured_workflow before compose_workflow. DO NOT TRIGGER for custom one-off workflows with no named template — use run-workflow skill.
tools
Migrate an Adobe Commerce App Builder project from the Integration Starter Kit or Checkout Starter Kit to the new App Management approach. Run from the root of the App Builder project to be migrated. Pass --auto to skip confirmation prompts (suitable for CI or batch use) — auto mode prints a summary of all Q&A questions answered with their defaults. Pass --doc-scan-only to scan README.md and env.dist for outdated content without modifying any files. Use when the user wants to migrate an App Builder project from the Integration Starter Kit or Checkout Starter Kit to the App Management approach, or mentions upgrading their Adobe Commerce extension architecture.
development
Add or modify webhook interceptors in an Adobe Commerce app. Use when the user wants to intercept Commerce operations to validate input, append data, or modify behavior — before or after execution. Requires a base app initialized with commerce-app-init.