brandmd

io.github.yuvrajangadsingh由 GitHub 账号 yuvrajangadsingh 发布v1.0.1更新于 Nov 14, 2026

Turn any website into a DESIGN.md: its colors, type and components, for your coding agent.

概览

AI 生成的概览

在无头 Chromium 中渲染网站,并把其设计系统以符合规范的 DESIGN.md 返回,供编码助手作为品牌上下文使用。

可以做什么
  • 从一个或多个页面网址提取网站设计系统,同一网站的多个页面会合并为一份规范。
  • 测量页面实际渲染的颜色、字体、间距、圆角和组件样式,可选提取深色模式。
  • 遇到拦截页、登录墙或内容过少的页面时拒绝输出,而不是猜测令牌。
  • 把 DESIGN.md 作为工具结果返回,警告放在单独区块,拒绝或失败则以工具错误形式报告。
适用场景
适合助手在编写或改版界面时需要现有网站真实颜色、字体和组件的情况,例如让页面贴合某个品牌。也适合会读取项目根目录 DESIGN.md 的编码助手工作流。
运行要求
通过 npx 以 stdio 在本地运行,需要 Node 20 或更高版本。必须安装 Playwright 的无头 Chromium,缺失时调用会失败并给出安装命令。默认提取不需要 API 密钥。单次调用最长 180 秒(可用 BRANDMD_MCP_TIMEOUT 调整),最多同时运行两个。
安装前请注意
该工具会从你的机器抓取并渲染任意公开网址,目标网站会看到该请求。它本身不写文件,但返回的内容通常会被保存为项目文件。提取结果来自实时页面测量,网站变化后结果也会变化。在 Windows 上,取消或超时的运行可能留下未关闭的浏览器。

安装

在 SourceWeft 中

  1. 打开 控制台中的 brandmd,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

brandmd

[npm version] [DESIGN.md lint: clean] [License: MIT]

Stop Claude Code, Cursor, and Gemini CLI from guessing your UI. brandmd extracts any website's design system into a spec-valid DESIGN.md that passes the official @google/design.md linter.

AI coding agents generate generic screens when they don't know your colors, fonts, spacing, components, and layout rules. Run one command, drop DESIGN.md in your project root, and your agent has brand context before it writes code. Output is the official DESIGN.md format: YAML frontmatter with machine-readable tokens plus canonical prose sections. Default extraction runs locally with no API key.

bash
npx brandmd https://stripe.com -o DESIGN.md

Every generated DESIGN.md validates clean:

bash
npx @google/design.md lint DESIGN.md   # 0 errors, 0 warnings

Pass multiple URLs to merge brand tokens across pages: npx brandmd https://site.com https://site.com/pricing https://site.com/docs -o DESIGN.md

Outputs to whatever your stack reads:

  • DESIGN.md (default): for Claude Code, Cursor, Gemini CLI, Codex, Stitch
  • --json: raw extracted tokens, in brandmd's internal shape (it can change in a 1.x release, see Stability)
  • --css: CSS custom properties, drop into any project
  • --tailwind: Tailwind v4 @theme block
  • --html: visual, shareable brand guide

Combine with:

  • --agent: also writes .cursor/rules/brand.mdc and SKILL.md to both .agents/skills/brand-style/ (the universal Agent Skills path used by skills.sh across 50+ agents) and .claude/skills/brand-style/ (backward-compat for direct Claude Code users). No manual wiring. Picked up automatically by Claude Code, Cursor, Codex, Gemini CLI, Kiro CLI, and the rest of the skills.sh ecosystem. Schema-compatible with Anthropic Claude Code Skills, google/skills, and vercel-labs/agent-skills.
  • --dark: also extract dark mode tokens
  • --vision: adds illustration style, photography mood, copywriting voice, and microcopy patterns from a screenshot. Requires GEMINI_API_KEY or GOOGLE_API_KEY (free at aistudio.google.com/apikey). Uses gemini-3.8-flash; set BRANDMD_VISION_MODEL to pick another model. If the screenshot or the vision call fails the CSS-only DESIGN.md is still written and the run exits 1.

Or let your agent run it. brandmd mcp is an MCP server with one tool, extract_design_md, so Claude Code, Cursor, or any MCP client can pull a site's DESIGN.md in the middle of a task ("make this page look like linear.app"):

bash
claude mcp add brandmd -- npx -y brandmd mcp

For Cursor, Claude Desktop, and other clients that read an mcpServers config:

json
{ "mcpServers": { "brandmd": { "command": "npx", "args": ["-y", "brandmd", "mcp"] } } }

Or in one click, which adds that same config:

[Add to Cursor] [Install in VS Code]

It is also in the MCP Registry as io.github.yuvrajangadsingh/brandmd.

The tool takes one or more pages of a site (urls) and an optional dark flag, and refuses block pages and login walls the same way the CLI does. It renders pages in Playwright's headless Chromium; if that browser is missing, the call fails with the command that installs it.

A call runs for at most 180 seconds (set BRANDMD_MCP_TIMEOUT in seconds to change it), and at most two run at once (a third gets an error asking it to retry). Cancelling a call, or running out of time, stops it and closes its browser on macOS and Linux. On Windows the run is ended outright and the browser may be left open (untested).

Works as brand context for Claude Code, Cursor rules, Gemini CLI, Codex, Google Stitch, MCP servers, and any coding agent that reads markdown.

Real examples: Stripe · Linear · GitHub · Vercel · Notion · Cursor · Figma · Supabase · Raycast · +20 more in the gallery

[brandmd extracting Stripe into DESIGN.md for Claude Code, Cursor, and Google Stitch]

yaml
---version: alphaname: Stripecolors:  primary: "#533afd"  background: "#ffffff"  on-background: "#0a2540"typography:  headline-lg:    fontFamily: sohne-var    fontSize: 48px    fontWeight: 600components:  button-primary:    backgroundColor: "{colors.primary}"    textColor: "{colors.on-primary}"---
## Colors
- **Indigo** (`#533afd`): Accent background (accent)- **White** (`#ffffff`): Page background (dominant)
## Typography
**Primary font:** sohne-var

The YAML frontmatter is the machine-readable token layer; the prose sections carry the evidence-based rationale (tiered palette, confidence tags, observed component styles). brandmd gives Claude Code, Cursor, Gemini CLI, and Codex real design context: it extracts a live website's colors, typography, spacing, shadows, component patterns, and layout rules, so AI coding agents build on-brand UI instead of generic screens.

Installable example skills repo

If you want ready-made brand skills without running brandmd yourself, install yuvrajangadsingh/brand-skills directly:

bash
npx skills add yuvrajangadsingh/brand-skills

That installs 5 brandmd-generated skills (Tailwind CSS, shadcn/ui, Vercel, Mintlify, Anthropic) into your project's agent skills folder. Each skill is self-contained with a bundled references/DESIGN.md. Community examples generated from public marketing sites, not affiliated with the named brands.

Release notes
  • v1.0: Stable release. A stated 1.x contract (see Stability), bounded MCP calls, buttons read from the page's real call to action, a palette that no longer depends on colour order, and one refusal rule for every page and theme.
  • v0.14: Spec + truth release. Emits the official DESIGN.md format (YAML frontmatter + canonical sections) that passes @google/design.md lint clean. Fail-closed refusals with a distinct exit code (--allow-blocked to override), atomic writes, gradient-stop parsing, honest CTA/button selection, shadow values in DESIGN.md, and a fixed generate/parse/diff round trip.
  • v0.13: Detects block / access-denied pages (Akamai, PerimeterX, WAF 403s) and warns instead of emitting a garbage design system. Notes when a site uses motion (canvas, WebGL, Lottie, rAF).
  • v0.12: Trust-repair: evidence-based visual character, tiered palette, HSL color naming, no more scientific-notation radii, clustered type scale.
  • v0.11: diff subcommand and the hosted example gallery.
  • v0.10: Universal .agents/ skills path.
  • v0.9: --agent flag writes Cursor rule + Claude Code skill alongside DESIGN.md. CI switched to npm Trusted Publishing.
  • v0.8: More accurate primary font detection across display, heading, body, and global text roles.
  • v0.7: Cloudflare-protected sites handled by waiting up to 20s for the JS challenge.
  • v0.6: Optional --vision adds illustration style, photography mood, copywriting voice, and microcopy notes. Requires a free Gemini API key.

See CHANGELOG.md for the full history.

Examples

See all 29 DESIGN.md examples in the gallery →

Flagship deep links (DESIGN.md):

Other output formats:

  • Vercel (CSS custom properties)
  • Linear (Tailwind v4 @theme)

Why

DESIGN.md is an open spec (Apache 2.0) for encoding a design system in a format LLMs can read: YAML frontmatter with typed tokens plus canonical prose sections. There's an official @google/design.md CLI that lints, diffs, and exports it. Problem is, nobody wants to write one from scratch.

brandmd does it from the terminal. Point it at any URL, get a spec-valid DESIGN.md back that passes @google/design.md lint clean. Drop it in your project root and your AI tools start generating on-brand UI.

Install

Needs Node 20 or newer (Playwright and the Gemini SDK both require it).

bash
# Run directly (no install). On a machine without Playwright's headless# Chromium it stops and prints the command that installs it. A bare Linux# box (CI, Docker) can also lack the system libraries Chromium needs; then# it prints the install-deps command for those instead.npx brandmd https://linear.app
# Install globallynpm i -g brandmd
# As an agent skill (Claude Code, Cursor, Gemini CLI, Copilot, Codex, 30+ platforms)npx skills add yuvrajangadsingh/brandmd

Usage

bash
# DESIGN.md (default)brandmd https://stripe.combrandmd https://stripe.com -o DESIGN.md
# Multiple pages (merges tokens)brandmd https://stripe.com https://stripe.com/pricing https://stripe.com/docs
# Dark mode extractionbrandmd https://github.com --dark
# Vision: capture illustration style, photography mood, copywriting voice# (CSS can't see these; Gemini reads the screenshot.)export GEMINI_API_KEY=your-key-here  # free: https://aistudio.google.com/apikeybrandmd https://linear.app --vision# Sites behind Cloudflare or AWS WAF: brandmd waits up to 20s for the JS# challenge to auto-resolve. If your site needs longer, pass --cf-wait-ms 30000.# If the challenge persists, brandmd refuses (exit 2) rather than writing garbage tokens.
# CSS custom propertiesbrandmd https://vercel.com --css
# Tailwind v4 @themebrandmd https://linear.app --tailwind
# HTML brand guide (visual, shareable)brandmd https://github.com --html
# Raw tokens as JSONbrandmd https://stripe.com --json
# Compare two extractionsbrandmd diff examples/stripe.md examples/vercel.md --out BRAND_DIFF.md

Refusals and exit codes

brandmd fails closed. If a page is a bot-block / access-denied page (a Cloudflare challenge that never clears included), a login / sign-in wall landing, or too thin to describe (no rendered text, empty palette), it refuses in every format and writes no artifact, so a bad capture can't silently overwrite a good DESIGN.md. A login wall means a password field on screen when the page loads, or sign-in copy on an auth page: a /login-style URL, or another host the request was sent to. A hidden or off-screen sign-up form, or a "Sign up free" headline on an ordinary page, is not one. A plain cross-origin redirect (say marketing -> app on another domain) doesn't refuse: it warns on stderr and is flagged in the output's provenance block, per page.

Every capture goes through the same gate, page by page. One refused page (a block page, a login wall, or a page with almost no text, even next to a rich one) refuses a multi-page run, and with --dark the dark capture is checked too. A page that fails to load (a timeout, a DNS error) is left out with a warning and the rest are merged; if none load, the run exits 1. --dark that gets no dark capture, like --vision that gets no vision result, still writes the light output and exits 1.

Exit codeMeaning
0success
1operational or validation error (bad URL, bad flag, browser launch failure, no page loaded, --dark or --vision came back empty)
2refused: block page, insufficient evidence, or a login-wall landing, on any page or theme
3brandmd check only: the page drifted from the spec

Pass --allow-blocked to force output anyway; whatever the refusal was, the artifact carries a refused-source marker in every format (Markdown callout, CSS/Tailwind comment header, HTML banner, JSON blockLikely). Writes are transactional (temp file + rename with rollback), including the --agent set and brandmd diff, so a partial failure never truncates an existing file. Atomicity is per process: concurrent brandmd runs against the same output directory are not coordinated, though collision-safe temp/backup names mean one run can never eat another's files.

Gallery

See 4 real DESIGN.md snapshots in the browser (Stripe, Vercel, Linear, Mintlify), or scan the examples/ folder for all 29. Each snapshot is generated from a single public page visit and is observed, not canonical.

Check (drift detection in CI)

brandmd diff compares two brands. brandmd check asks a different question: has what we shipped drifted from the spec we agreed on?

bash
brandmd check https://staging.acme.com --against DESIGN.md
Design drift: 2 major, 1 minorhttps://staging.acme.com vs DESIGN.md
  major  color      role "secondary" repainted: #29227D -> #7F7DFC  major  color      role "on-secondary" repainted: #FFFFFF -> #1A1A1A  minor  theme      mood reads as "...vivid blue accents", spec says "...blue accents"

Colours are compared by role, not as a set of hexes. One hex legitimately fills several roles (#FFFFFF is often background and on-primary), so a set comparison silently misses the drift that matters: the hex behind primary changing while that hex still appears elsewhere.

What fails the build. Losing or repainting a role, and a changed primary or secondary font, are major. New roles, extra spacing steps and reworded theme descriptions are minor and pass by default, because they are usually a new component landing rather than a regression. Theme wording is brandmd's own interpretation, so it never fails a build on its own.

Flag
--against <file>the committed DESIGN.md (required)
--report <file>write the drift as JSON for CI annotations
--fail-on <level>major (default), any, or none
--allow-blockedcompare anyway if the page is refused (blocked, thin, or a login wall)
--cf-wait-ms <ms>how long to wait for a Cloudflare or AWS WAF challenge (default 20000)
--debugprint the raw error instead of a one-line remediation
--viewport <WxH>pin the viewport (default 1440x900)
--locale <tag>pin the browser locale
--reduced-motionrequest prefers-reduced-motion: reduce

Pin the viewport in CI. It decides which breakpoint renders, so an unpinned run can legitimately extract a different design system on a different machine and report drift that isn't there.

A blocked page, an evidence-thin page, or a login-wall landing refuses with exit 2 rather than reporting drift. Diffing a Cloudflare challenge against a real spec would flag every token as changed, and a check that cries wolf is one people turn off. An empty or truncated DESIGN.md exits 1, because a gate that silently stops gating is worse than no gate.

What check does not see

Worth knowing before you rely on it:

  • Component drift is reported but does not fail a build by default. Background, text colour and radius are compared on the machine-token components; height and padding are not. Components are the least certain part of an extraction (a button that fades in, or one that paints no fill at rest, is missed; see Known limits), so component drift is always minor. Opt in with --fail-on any.
  • secondaryFont is unreliable. The live side is round-tripped through the same generator and parser as a written DESIGN.md, which keeps both sides honestly comparable but drops fields the markdown does not carry cleanly. A secondary-font change can pass unnoticed.
  • Majors can flip on sites that change between visits. Each colour cluster is led by its most-used colour, so the order a page lists its colours in no longer changes the palette or the text roles, but rotating hero imagery or an A/B test that changes how often a colour is used can still repaint a role. On static marketing pages runs are byte-identical; on dynamic ones, re-run before believing a surprising major.

In GitHub Actions

yaml
- name: Check design drift  run: npx brandmd check "${{ steps.deploy.outputs.preview-url }}" \         --against DESIGN.md --report drift.json

Exit 3 fails the job on drift; 1 and 2 still mean the tool errored or refused, so a broken preview never reads as a design change. When drift is intentional, update DESIGN.md in the same PR and the check goes green.

Diff

bash
brandmd diff examples/stripe.md examples/vercel.md --out BRAND_DIFF.md

Compares two DESIGN.md files and writes a markdown diff: shared and unique colors, typography table, spacing and radii table, per-component property diff, and a "what to copy / what to avoid" synthesis. Local files only. See examples/diff-stripe-vs-vercel.md for the output format.

Output formats

DESIGN.md (default)

The official DESIGN.md format: YAML frontmatter (machine-readable colors, typography, rounded, spacing, components tokens) plus canonical sections (Overview, Colors, Typography, Layout, Elevation & Depth, Shapes, Components, Do's and Don'ts). Validates clean under @google/design.md lint. Drop it in your project root and AI coding agents use it to generate on-brand UI.

CSS custom properties (--css)

css
:root {  --color-accents-1: #FAFAFA;  --color-blue-600: #0075DE;  --font-primary: "Geist";  --space-1: 4px;  --radius-sm: 4px;  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);}

Tailwind v4 (--tailwind)

css
@import "tailwindcss";
@theme {  --color-primary: #0075DE;  --font-sans: "Geist", system-ui, sans-serif;  /* Spacing observed: 4px, 8px, 16px, 24px. Not written as --spacing-* keys. */  --radius-sm: 4px;}

HTML brand guide (--html)

A self-contained dark-themed HTML page with color swatches, font specimens, spacing visualization, and shadow examples. Open it in a browser or share it with stakeholders.

JSON (--json)

Raw extracted tokens for programmatic use. The shape is brandmd's internal one and can change in any 1.x release; see Stability.

Multi-page extraction

Pass multiple URLs to merge tokens from different pages into one DESIGN.md. Each page contributes equally regardless of length: token frequencies are normalized per page, and components carry a per-page weight, so a docs page with fifty buttons can't outvote a homepage with three. What that decides is on how many pages a pattern appears, not how many times it appears anywhere, which is the right question to ask of a brand pattern.

bash
brandmd https://stripe.com https://stripe.com/pricing https://stripe.com/docs

Failed pages are skipped with a warning. Mixed domains show a warning.

Dark mode

Extract dark theme tokens as a separate section:

bash
brandmd https://github.com --dark

Adds a "Dark Mode Overrides" section to the DESIGN.md with the dark color palette. Uses prefers-color-scheme: dark via Playwright, so it captures what users actually see in dark mode. Affects DESIGN.md and --json output (ignored for --css, --tailwind and --html).

What it extracts

  • CSS custom properties from :root and @media rules (uses actual variable names when available)
  • Colors with semantic roles (background, text, accent, border)
  • Typography with role-aware Primary detection (display > heading > body), per-role font breakdown, and a full "all detected fonts" frequency list. Skips monospace, default fallbacks, and icon fonts when picking Primary.
  • Spacing scale and base grid unit
  • Border radii and shadow styles
  • Component patterns (buttons, cards, inputs). A button is a <button>, a role="button", or a link classed or painted like one (a fill, a gradient or a border other than an underline, with a short visible label); hidden and off-page controls, skip links and controls inside a <table> (a sample email, a data grid) are left out, unless every control on the page sits in a table, and a control with no label text (an icon-only launcher, or only an icon font's glyphs) is never the primary button. The primary button is the most repeated fill with real colour (LCH chroma), unless that colour appears once and a neutral fill repeats more; then, as when every fill is neutral, it is the neutral that stands out most against the page. colors.primary is that button's fill as the page shows it (a translucent fill composited over the page, a gradient button's first stop); with no solid button, or one in the page's own colour, it falls back to the most vivid accent colour. The prose names the element each button was sampled from.

Known limits

  • A hero button that fades in as the page loads or scrolls can be missed. A headless capture may never run the page's reveal, so the button stays at opacity 0 and is left out, and the primary comes from the other buttons.
  • A page whose buttons paint no fill at rest (transparent until hovered) has no primary button to sample. Unless another accent colour stands out on the page, colors.primary falls back to the page colour and the output says it is low confidence. clerk.com is one in the gallery.

How it works

  1. Renders each page in a headless browser (Playwright)
  2. Scrolls through to trigger lazy-loaded content
  3. Dismisses cookie banners and overlays
  4. Extracts CSS custom properties from :root (recurses into @media rules)
  5. Extracts computed styles from every visible element
  6. Clusters similar colors, identifies the spacing scale
  7. Merges tokens across pages (normalized per page)
  8. Outputs in your chosen format

No LLM calls, no API keys, runs entirely on your machine.

Agent skill

brandmd ships as an Agent Skill that works across 30+ platforms including Claude Code, Cursor, VS Code/Copilot, Codex, and Gemini CLI.

bash
npx skills add yuvrajangadsingh/brandmd

Then tell your agent: "extract the design system from https://linear.app"

If brandmd saved you time, consider starring the repo.

Built by Yuvraj Angad Singh. Also: vibecheck (catch AI-generated code smells) and vemb (embeddings from the command line). Follow on GitHub for new dev-tool experiments.

Stability

From 1.0.0 brandmd follows semver for the parts below. A 1.x release can add to them (a flag, a section, a tool input); removing or changing one waits for 2.0.

Covered:

  • Commands and flags. brandmd <urls...>, brandmd diff, brandmd check and brandmd mcp, with every flag their --help lists: -o, --json, --css, --tailwind, --html, --dark, --vision, --agent, --allow-blocked, --debug, --cf-wait-ms, --viewport, --locale and --reduced-motion; diff --out; check --against, --report and --fail-on.
  • Exit codes. 0, 1, 2 and 3, as in the table above.
  • The DESIGN.md shape. The frontmatter keys version, name, description, colors, typography, rounded, spacing and components, and the sections Overview, Colors, Typography, Layout, Elevation & Depth, Shapes, Components and Do's and Don'ts, plus Dark Mode Overrides with --dark and Visual Identity Beyond CSS with --vision. The linter it is checked against is @google/[email protected]: CI fails on any error or warning it reports for generated test files, and every example in the gallery lints clean. A later linter version counts as supported once a brandmd release says so.
  • The MCP tool. extract_design_md, its urls and dark inputs, and its result: the DESIGN.md as the first text block, warnings as a second one, and refusals and failures as tool errors carrying the CLI's message.
  • Environment variables. GEMINI_API_KEY or GOOGLE_API_KEY and BRANDMD_VISION_MODEL for --vision, and BRANDMD_MCP_TIMEOUT for the MCP server.
  • Node 20 or newer.

Not covered, so any 1.x release can change them:

  • The values. brandmd measures a live page, so a site change or a better extraction changes colours, fonts and components. Pin the brandmd version and commit the DESIGN.md when you need the same file twice.
  • The JSON from --json and check --report. Both are internal JSON formats (--json prints the extracted tokens, --report the drift list), so field names and nesting can change. The MCP tool returns DESIGN.md, not this JSON. When a script needs something stable, read the DESIGN.md, or check's exit code.
  • What --css, --tailwind and --html print. The flags stay; the variable names and layout follow the page.
  • Wording. Prose sentences, warnings and error messages.
  • The MCP limits. Today a call runs for at most 180 seconds (BRANDMD_MCP_TIMEOUT), two run at once, and a cancelled or timed-out call stops its run and closes its browser on macOS and Linux. Every extraction's scroll pass stops after 50 screens and starts no new screen after 15 seconds. These numbers can be tuned.

License

MIT

来源:README.md,提交 12595eb

工具

1

extract_design_md

Render a website in headless Chromium and return its design system as a spec-valid DESIGN.md: colors, typography, spacing, radii and components, measured from the page. Several pages of one site merge into one design system. Refuses block pages, login walls and near-empty pages instead of guessing.

输入参数darkurls必填

版本历史

1
  1. v1.0.1最新Nov 14, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分
  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分