extract-design-md

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Extract DESIGN.md from a site

从站点提取DESIGN.md

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
给定一个可访问的URL,生成一个
DESIGN.md
文件——包含YAML格式的设计令牌(颜色、排版、
rounded
spacing
components
)以及按标准章节顺序排列的文字说明,足以交给编码Agent构建与源站点风格一致的新UI。
核心思路(来自研究): 设计令牌与站点的CSS自定义属性和计算样式几乎是1:1对应的,因此主要工作由低成本的浏览器内提取完成,而非视觉识别。截图仅用于文字描述部分。官方linter作为免费的质量校验关卡。
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.md
    linter 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
.
本技能会调用三个外部工具——运行前请确保每个工具都可用:
  • playwright-cli 需在
    PATH
    中——浏览器内提取和截图都通过它运行。执行一次安装:
    npm install -g @playwright/cli@latest
    ,然后运行
    playwright-cli install --skills
    (需要Node.js 18+)。检查命令:
    which playwright-cli
  • 可访问的Firecrawl实例——用于页面发现(
    firecrawl map
    )和可选的文案抓取。托管API或自托管/本地实例均可;如果Firecrawl不可访问,本技能会回退到playwright链接发现(页面覆盖度较低)。运行前请确认你的实例可以正常响应。
  • npx
    (Node.js)——按需拉取官方
    @google/design.md
    linter用于质量校验。如果不可用,本技能仍会生成文件,并标注“lint已跳过”。
如果你的Agent对网络或文件系统访问做了沙箱限制,请在运行前允许本技能发起的出站调用(无头浏览、Firecrawl、
npx
)。
SKILL
为本技能的目录。选择一个稳定的playwright会话名称,例如
S=designmd

Flags

参数标志

FlagDefaultEffect
<url>
requiredEntry-point URL
--pages <n>
5Max pages to sample
--pages-list <paths>
autoPin exact pages (skips the confirm prompt)
--no-screenshots
shots ONSkip the feel pass; prose then leans on token names + copy
--theme <auto|light|dark|both>
auto
auto
detects;
both
forces dual;
light
/
dark
pin one
--out <dir>
.design_mds/<domain>-YYYYMMDD/
Output folder
--no-lint
lint ONSkip the linter (auto-skips if
npx
is unavailable)

参数标志默认值作用
<url>
必填入口URL
--pages <n>
5最大采样页面数
--pages-list <paths>
自动指定确切的页面(跳过确认提示)
--no-screenshots
开启截图跳过质感采集步骤;文字描述将依赖令牌名称+页面文案
--theme <auto|light|dark|both>
auto
auto
自动检测;
both
强制双主题;
light
/
dark
固定单一主题
--out <dir>
.design_mds/<domain>-YYYYMMDD/
输出文件夹
--no-lint
开启lint跳过linter校验(如果
npx
不可用会自动跳过)

Stage 1 — Discover pages

阶段1 — 发现页面

bash
firecrawl map "<url>" > "<out>/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
.
bash
firecrawl map "<url>" > "<out>/raw/map.json"
将返回的URL按页面类型分类,每个类别选取最佳匹配页面(始终包含首页),总数不超过
--pages
参数指定的数量(默认5个):
  • 首页(始终为输入的URL)——核心调色板+字体+首屏CTA
  • 定价/产品页——卡片、开关、表格
  • 认证/登录/注册/联系页——输入框、表单字段
  • 博客/文档/更新日志页——长文本排版
  • 品牌/关于/设计页——通常会明确说明颜色和字体;价值很高
爬取前展示自动选取的页面列表,支持添加/移除/替换(仅一次简洁提示;如果指定了
--pages-list
则跳过)。没有匹配页面的类别直接跳过——绝不强制采样。如果Firecrawl不可用,回退到playwright链接发现(
run-code
返回
[...document.links].map(a=>a.href)
)——详见
references/edge-cases.md

Stage 2 — Extract global tokens (the core)

阶段2 — 提取全局令牌(核心步骤)

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
<out>/raw/
so the two deliverables stay uncluttered at the folder root — see Output layout. Create the folders once:
bash
S=designmd
mkdir -p "<out>/raw/tokens" "<out>/raw/components" "<out>/raw/copy" "<out>/raw/logs" "<out>/screenshots"
playwright-cli -s=$S open "<homepage-url>"
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" > "<out>/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).
打开首页,等待页面稳定后,运行内置的提取器。提取器(
scripts/extract-tokens.js
)会读取经过噪声过滤的
:root
变量,对可见主内容元素的计算样式进行模式采样,标记突出的CTA和第一个输入框,并触发hover/focus状态——返回值及设计原因详见
references/extraction.md
中间产物存放在
<out>/raw/
目录下,这样两个最终交付物在文件夹根目录下保持整洁——详见输出结构。一次性创建所需文件夹:
bash
S=designmd
mkdir -p "<out>/raw/tokens" "<out>/raw/components" "<out>/raw/copy" "<out>/raw/logs" "<out>/screenshots"
playwright-cli -s=$S open "<homepage-url>"
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" > "<out>/raw/tokens/tokens.home.json"
slice-result.sh
会去除playwright-cli的markdown包装,得到干净的JSON。读取文件并对
varsTotal
/
vars
的数量进行合理性检查。如果
vars
数量很少(站点不是Tailwind风格的),使用
varsExtra
放宽过滤条件
——详见
references/edge-cases.md
(EC-FW.1 / 无设计系统)。

Theme detection (decision 8)

主题检测(决策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
<html>
, 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:
  1. click the site's own theme switch, else
  2. set the class/attribute directly, e.g.
    run-code
    doing
    document.documentElement.classList.add('dark')
    (or
    setAttribute('data-theme','dark')
    ), else
  3. 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).
检查JSON中的
themeSignal
字段。如果站点提供明/暗主题切换——即
<html>
标签上有
.dark
类或
data-theme
属性,或对
prefers-color-scheme
有响应——则该站点为双主题。当存在两个主题且
--theme
参数为
auto
/
both
时,每个主题各提取一次:切换主题,等待页面重新稳定,重新运行提取器,输出到第二个文件(
raw/tokens/tokens.home.dark.json
)。主题切换的优先顺序:
  1. 点击站点自身的主题切换按钮,若不行则
  2. 直接设置类/属性,例如通过
    run-code
    执行
    document.documentElement.classList.add('dark')
    (或
    setAttribute('data-theme','dark')
    ),若不行则
  3. 模拟
    prefers-color-scheme
切换后再次
sleep 2
。如果无法可靠触发另一个主题,则仅采集已加载的主题,生成一个
DESIGN.md
文件,并在报告中说明。即使是双主题站点,
--theme light|dark
也会固定使用单一主题。详细说明:
references/edge-cases.md
(EC-TH)。

Stage 3 — Harvest components + states (pages 2–N)

阶段3 — 采集组件与状态(第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:
bash
playwright-cli -s=$S goto "<page-2-url>"
sleep 2
playwright-cli -s=$S run-code "$(cat "$SKILL/scripts/extract-tokens.js")" \
  | bash "$SKILL/scripts/slice-result.sh" > "<out>/raw/tokens/tokens.<slug>.json"
Any bespoke per-page component captures (card/pill candidates, etc.) go to
<out>/raw/components/
; scraped copy to
<out>/raw/copy/
; per-step logs to
<out>/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.
对于每个额外的页面,不要重新导出全局变量(它们是共享的)——只采样该页面特有的组件(例如认证页的输入框、定价页的卡片/开关、博客页的文本排版)。复用同一个提取器;保留每个页面的JSON:
bash
playwright-cli -s=$S goto "<page-2-url>"
sleep 2
playwright-cli -s=$S run-code "$(cat "$SKILL/scripts/extract-tokens.js")" \
  | bash "$SKILL/scripts/slice-result.sh" > "<out>/raw/tokens/tokens.<slug>.json"
所有页面特有的定制化组件采集结果(如候选卡片/标签等)存放在
<out>/raw/components/
;抓取的文案存放在
<out>/raw/copy/
;每步的日志存放在
<out>/raw/logs/
提取器已经对CTA触发了
hover
状态,对第一个输入框触发了
focus
状态,并将差异返回到
states
字段中。合成时仅保留与基础状态不同的状态(FR-ST.3)。跨页面合并:合并所有CSS变量(核心调色板以首页为准,冲突处标记出来);累加组件,合并相同样式。

Stage 4 — Capture feel (optional, default ON)

阶段4 — 采集设计质感(可选,默认开启)

One viewport screenshot per sampled page (not full-page), into
screenshots/
:
bash
playwright-cli -s=$S screenshot --filename="<out>/screenshots/<slug>.png"
Optionally
firecrawl scrape --only-main-content "<url>"
the homepage + brand page for copy/tagline, saved to
<out>/raw/copy/
. Screenshots stay at
<out>/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.
每个采样页面截取一张视口截图(非整页),保存到
screenshots/
目录:
bash
playwright-cli -s=$S screenshot --filename="<out>/screenshots/<slug>.png"
可选地对首页和品牌页执行
firecrawl scrape --only-main-content "<url>"
以抓取文案/标语,保存到
<out>/raw/copy/
。截图存放在
<out>/screenshots/
(用于文字描述,用户也可以查看)。截图和文案仅用于文字描述部分(概述、注意事项)——绝不要从截图中读取令牌值。
--no-screenshots
参数会跳过此阶段。

Stage 5 — Synthesize the DESIGN file(s)

阶段5 — 合成DESIGN文件

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 inside
    components
    so 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.
读取合并后的
raw/tokens/*.json
文件,将其映射到DESIGN.md schema。完整schema、令牌到DESIGN的映射表以及标准文字章节顺序都在**
references/design-md-schema.md
中——写入文件前请先阅读。** 核心规则:
  • 主调色板的颜色需从计算得到的
    rgb(...)
    值转换为hex格式;保留原始CSS变量(
    lab()
    /
    color-mix()
    等)作为备用。绝不要虚构颜色。
  • 语义角色为颜色命名(
    --color-accent
    primary
    /
    accent
    );将较长的灰色阶折叠为有代表性的
    neutral
    集合——采集的是设计系统,而非每个色阶。
  • components
    中使用
    {path.to.token}
    引用,保持值的DRY原则,同时便于linter校验。
    primary
    颜色必须存在,否则linter会报错。
  • 仅采集页面实际存在的组件(决策10)——绝不要虚构不存在的
    card
    /
    chip
    组件。在报告中记录常见组件集(按钮、输入框、卡片、链接、标签)中哪些被找到、哪些缺失。
  • 仅在有实际依据时才输出文字章节,始终按标准顺序排列,绝不出现重复的
    ##
    标题。

Dual-theme output (decision 8)

双主题输出(决策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.
如果采集了两个主题,则输出**
DESIGN.light.md
+
DESIGN.dark.md
——每个都是完整的、通过lint校验的文件。
typography
rounded
spacing
共享的**;
colors
和所有依赖颜色的
components
按主题区分的。单主题站点输出一个
DESIGN.md
。文字描述中可以说明存在另一个主题。

Stage 6 — Validate (quality gate)

阶段6 — 验证(质量关卡)

Lint every generated file:
bash
npx -y @google/design.md lint "<out>/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.

每个生成的文件执行lint:
bash
npx -y @google/design.md lint "<out>/DESIGN.md"
  • 仅自动修复结构错误:章节顺序错误、
    {refs}
    引用失效、缺少
    primary
    /必填字段。
  • 在报告中标记值层面的问题(超出色域的颜色、不合理的尺寸)——绝不为了通过linter校验而静默删除已采集的令牌(决策12)。由用户决定如何处理标记的值。
  • 展示非致命警告(例如WCAG AA对比度问题),不阻塞流程。
  • 修复后重新执行lint;最终文件必须无错误。如果
    npx
    /linter不可用,仍生成文件,并在报告中警告“lint已跳过”。

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/<domain>-YYYYMMDD/        # <domain> = host with dots→hyphens
├── DESIGN.md                         # single-theme   (or DESIGN.light.md + DESIGN.dark.md)
├── screenshots/<slug>.png            # 1 desktop-viewport PNG per page (if enabled)
└── raw/                              # intermediate artifacts (audit trail + re-runs)
    ├── tokens/tokens.<slug>.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.
两个交付物位于文件夹根目录;所有中间产物都放在
raw/
目录下,这样输出目录一目了然,非常整洁。
.design_mds/<domain>-YYYYMMDD/        # <domain> = host with dots→hyphens
├── DESIGN.md                         # single-theme   (or DESIGN.light.md + DESIGN.dark.md)
├── screenshots/<slug>.png            # 1 desktop-viewport PNG per page (if enabled)
└── raw/                              # intermediate artifacts (audit trail + re-runs)
    ├── tokens/tokens.<slug>.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
raw/tokens/*.json
文件始终保留(决策9),这样无需重新爬取即可重新生成文字描述,且所有值都可追溯。冲突保护: 如果当日对应域名的文件夹已存在,询问用户(覆盖/添加
-2
后缀/中止)——绝不静默覆盖。

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 <html>)
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)
报告应简洁如实。说明采集了哪些内容,哪些组件被找到、哪些缺失,有哪些主题,以及linter的具体结果。如果某个阶段降级(无设计系统、Firecrawl不可用、lint跳过),要明确说明——不要暗示完全保真。
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 <html>)
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.
每当对映射关系或模糊选择的置信度低于95%时——比如两种颜色中哪个是“primary”,站点是否真的有设计系统,如何解决当日输出冲突——带着建议询问用户,而非猜测。至少要在报告中说明模糊之处。你生成的任何子Agent都必须顺序运行,绝不能并行,且必须遵守上述Firecrawl和沙箱规则。

Bundled files

内置文件

  • scripts/extract-tokens.js
    — the in-browser extractor for
    run-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.
  • scripts/extract-tokens.js
    ——用于
    run-code
    的浏览器内提取器(噪声过滤、模式采样、CTA/输入框检测、hover/focus触发)。经过验证的核心模块,已生产化。
  • scripts/slice-result.sh
    ——去除playwright-cli的markdown包装,输出干净的JSON。
  • references/extraction.md
    ——提取器返回的字段逐一说明,以及如何使用
    varsExtra
    放宽过滤条件。
  • references/design-md-schema.md
    ——DESIGN.md的YAML schema、令牌到DESIGN的映射表以及标准文字章节顺序。阶段5前必读。
  • references/edge-cases.md
    ——无设计系统、非Tailwind站点、双主题切换、合并冲突、爬取/加载失败、空结果等边缘情况。