design-md-chrome-extractor
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesedesign-md-chrome-extractor
design-md-chrome-extractor
Overview
概述
The TypeUI DESIGN.md Extractor is a Chrome extension that analyzes any website and extracts its design system (typography, colors, spacing, radius, shadows, motion) to generate standardized or files. These files follow the open-source TypeUI format and can be used with AI coding tools like Claude Code, Google Stitch, Codex, and Cursor to replicate design systems.
DESIGN.mdSKILL.mdKey capabilities:
- Auto-extract design tokens from any webpage
- Generate DESIGN.md (design system documentation)
- Generate SKILL.md (AI agent-ready skills)
- Download extracted files for immediate use
- Refresh extraction on page state changes
TypeUI DESIGN.md提取器是一款Chrome扩展程序,可分析任意网站并提取其设计系统(排版、颜色、间距、圆角、阴影、动效),生成标准化的或文件。这些文件遵循开源的TypeUI格式,可与Claude Code、Google Stitch、Codex和Cursor等AI编码工具配合使用,以复刻设计系统。
DESIGN.mdSKILL.md核心功能:
- 自动从任意网页提取设计令牌
- 生成DESIGN.md(设计系统文档)
- 生成SKILL.md(适配AI Agent的技能文件)
- 下载提取后的文件以便立即使用
- 页面状态变化时重新提取
Installation
安装
From Chrome Web Store
从Chrome应用商店安装
Local Development Installation
本地开发安装
- Clone the repository:
bash
git clone https://github.com/bergside/design-md-chrome.git
cd design-md-chrome-
Load in Chrome:
- Open
chrome://extensions - Enable Developer mode (toggle in top-right)
- Click Load unpacked
- Select the project folder
design-md-chrome
- Open
-
Verify installation:
- Extension icon should appear in Chrome toolbar
- Pin it for easy access
- 克隆仓库:
bash
git clone https://github.com/bergside/design-md-chrome.git
cd design-md-chrome-
在Chrome中加载扩展:
- 打开
chrome://extensions - 启用开发者模式(右上角开关)
- 点击加载已解压的扩展程序
- 选择项目文件夹
design-md-chrome
- 打开
-
验证安装:
- 扩展图标应出现在Chrome工具栏中
- 固定图标以便快速访问
Usage Patterns
使用模式
Basic Extraction Workflow
基础提取流程
- Navigate to target website (e.g., )
https://stripe.com - Click the extension icon in toolbar
- Click "Auto-extract" button
- Review extracted design tokens in popup
- Generate DESIGN.md or SKILL.md
- Download the file
- 导航至目标网站(例如:)
https://stripe.com - 点击工具栏中的扩展图标
- 点击“自动提取”按钮
- 查看弹出窗口中提取的设计令牌
- 生成DESIGN.md或SKILL.md文件
- 下载文件
Programmatic Extraction (Content Script)
程序化提取(内容脚本)
The extension injects which performs extraction:
content.jsjavascript
// Core extraction happens via message passing
chrome.runtime.sendMessage({
action: 'extract',
url: window.location.href
}, (response) => {
console.log('Extracted tokens:', response.tokens);
});扩展会注入来执行提取操作:
content.jsjavascript
// 核心提取通过消息传递完成
chrome.runtime.sendMessage({
action: 'extract',
url: window.location.href
}, (response) => {
console.log('Extracted tokens:', response.tokens);
});Style Token Structure
样式令牌结构
Extracted tokens follow this structure:
javascript
{
typography: {
fontFamilies: ['Inter', 'system-ui', 'sans-serif'],
fontSizes: ['12px', '14px', '16px', '20px', '24px', '32px'],
fontWeights: ['400', '500', '600', '700'],
lineHeights: ['1.2', '1.5', '1.6']
},
colors: {
primary: ['#635BFF', '#0A2540'],
neutral: ['#FFFFFF', '#F6F9FC', '#E3E8EE'],
semantic: {
success: '#00D924',
error: '#DF1B41',
warning: '#FFC043'
}
},
spacing: ['4px', '8px', '12px', '16px', '24px', '32px', '48px', '64px'],
radius: ['0px', '4px', '8px', '12px', '16px', '9999px'],
shadows: [
'0 1px 3px rgba(0,0,0,0.1)',
'0 4px 6px rgba(0,0,0,0.1)',
'0 10px 40px rgba(0,0,0,0.15)'
],
motion: {
durations: ['150ms', '200ms', '300ms', '500ms'],
easings: ['ease', 'ease-in-out', 'cubic-bezier(0.4,0,0.2,1)']
}
}提取的令牌遵循以下结构:
javascript
{
typography: {
fontFamilies: ['Inter', 'system-ui', 'sans-serif'],
fontSizes: ['12px', '14px', '16px', '20px', '24px', '32px'],
fontWeights: ['400', '500', '600', '700'],
lineHeights: ['1.2', '1.5', '1.6']
},
colors: {
primary: ['#635BFF', '#0A2540'],
neutral: ['#FFFFFF', '#F6F9FC', '#E3E8EE'],
semantic: {
success: '#00D924',
error: '#DF1B41',
warning: '#FFC043'
}
},
spacing: ['4px', '8px', '12px', '16px', '24px', '32px', '48px', '64px'],
radius: ['0px', '4px', '8px', '12px', '16px', '9999px'],
shadows: [
'0 1px 3px rgba(0,0,0,0.1)',
'0 4px 6px rgba(0,0,0,0.1)',
'0 10px 40px rgba(0,0,0,0.15)'
],
motion: {
durations: ['150ms', '200ms', '300ms', '500ms'],
easings: ['ease', 'ease-in-out', 'cubic-bezier(0.4,0,0.2,1)']
}
}Generated File Structure
生成文件结构
DESIGN.md Format
DESIGN.md格式
markdown
undefinedmarkdown
undefined[Site Name] Design System
[站点名称] 设计系统
Mission
目标
Define and maintain consistent visual language for [product].
为[产品]定义并维护一致的视觉语言。
Brand
品牌
- URL: https://example.com
- Audience: [Developers/Designers/General]
- Surface: Web application
- URL: https://example.com
- 受众: [开发者/设计师/普通用户]
- 应用场景: Web应用
Style Foundations
样式基础
Typography
排版
- Font families: Inter, system-ui
- Sizes: 12px, 14px, 16px, 20px, 24px, 32px
- Weights: 400 (regular), 500 (medium), 600 (semibold), 700 (bold)
- Line heights: 1.2 (tight), 1.5 (base), 1.6 (relaxed)
- 字体家族: Inter, system-ui
- 字号: 12px, 14px, 16px, 20px, 24px, 32px
- 字重: 400(常规), 500(中等), 600(半粗体), 700(粗体)
- 行高: 1.2(紧凑), 1.5(基准), 1.6(宽松)
Colors
颜色
Primary
- - Brand primary
#635BFF - - Dark navy
#0A2540
Neutral
- - White
#FFFFFF - - Light gray
#F6F9FC - - Medium gray
#E3E8EE
主色
- - 品牌主色
#635BFF - - 深海军蓝
#0A2540
中性色
- - 白色
#FFFFFF - - 浅灰色
#F6F9FC - - 中灰色
#E3E8EE
Spacing
间距
Scale: 4px, 8px, 12px, 16px, 24px, 32px, 48px, 64px
刻度: 4px, 8px, 12px, 16px, 24px, 32px, 48px, 64px
Radius
圆角
Values: 0px, 4px, 8px, 12px, 16px, 9999px (pill)
取值: 0px, 4px, 8px, 12px, 16px, 9999px(胶囊形)
Accessibility
无障碍
- WCAG 2.2 AA compliance required
- Minimum contrast ratio 4.5:1 for text
- Focus indicators required on all interactive elements
undefined- 需符合WCAG 2.2 AA标准
- 文本最小对比度为4.5:1
- 所有交互元素必须有焦点指示器
undefinedSKILL.md Format
SKILL.md格式
Similar structure but optimized for AI agent consumption with additional sections:
- Component Rule Expectations: State, interaction, accessibility requirements
- Quality Gates: Testable validation criteria
- Guideline Authoring Workflow: Step-by-step implementation process
结构与DESIGN.md类似,但针对AI Agent的使用进行了优化,增加了以下章节:
- 组件规则预期: 状态、交互、无障碍要求
- 质量门: 可测试的验证标准
- 指南编写流程: 分步实现过程
Extension Architecture
扩展架构
Manifest (manifest.json)
清单文件(manifest.json)
json
{
"manifest_version": 3,
"name": "DESIGN.MD Style Extractor",
"version": "1.0.0",
"permissions": ["activeTab", "scripting"],
"action": {
"default_popup": "popup.html"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"]
}]
}json
{
"manifest_version": 3,
"name": "DESIGN.MD Style Extractor",
"version": "1.0.0",
"permissions": ["activeTab", "scripting"],
"action": {
"default_popup": "popup.html"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"]
}]
}Message Passing Pattern
消息传递模式
Popup → Content Script:
javascript
// popup.js
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {
action: 'extractStyles'
}, (response) => {
displayTokens(response.tokens);
});
});Content Script → Background:
javascript
// content.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'extractStyles') {
const tokens = extractDesignTokens();
sendResponse({tokens});
}
});弹出窗口 → 内容脚本:
javascript
// popup.js
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {
action: 'extractStyles'
}, (response) => {
displayTokens(response.tokens);
});
});内容脚本 → 后台:
javascript
// content.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'extractStyles') {
const tokens = extractDesignTokens();
sendResponse({tokens});
}
});API Reference
API参考
Extension Actions
扩展操作
| Action | Description | Response |
|---|---|---|
| Scan page for design tokens | |
| Create DESIGN.md content | |
| Create SKILL.md content | |
| Re-run extraction | |
| Trigger file download | |
| 操作 | 描述 | 响应 |
|---|---|---|
| 扫描页面提取设计令牌 | |
| 创建DESIGN.md内容 | |
| 创建SKILL.md内容 | |
| 重新执行提取 | |
| 触发文件下载 | |
Core Extraction Functions
核心提取函数
javascript
// Extract all computed styles from page
function extractDesignTokens() {
const allElements = document.querySelectorAll('*');
const tokens = {
typography: new Set(),
colors: new Set(),
spacing: new Set(),
radius: new Set(),
shadows: new Set()
};
allElements.forEach(el => {
const computed = window.getComputedStyle(el);
// Extract typography
tokens.typography.add(computed.fontFamily);
tokens.typography.add(computed.fontSize);
tokens.typography.add(computed.fontWeight);
// Extract colors
if (computed.color !== 'rgba(0, 0, 0, 0)') {
tokens.colors.add(computed.color);
}
if (computed.backgroundColor !== 'rgba(0, 0, 0, 0)') {
tokens.colors.add(computed.backgroundColor);
}
// Extract spacing
['margin', 'padding'].forEach(prop => {
['Top', 'Right', 'Bottom', 'Left'].forEach(side => {
const value = computed[prop + side];
if (value !== '0px') tokens.spacing.add(value);
});
});
// Extract border radius
if (computed.borderRadius !== '0px') {
tokens.radius.add(computed.borderRadius);
}
// Extract box shadows
if (computed.boxShadow !== 'none') {
tokens.shadows.add(computed.boxShadow);
}
});
return normalizeTokens(tokens);
}
// Normalize and deduplicate tokens
function normalizeTokens(rawTokens) {
return {
typography: {
fontFamilies: Array.from(rawTokens.typography).filter(isFontFamily),
fontSizes: Array.from(rawTokens.typography).filter(isFontSize).sort(),
fontWeights: Array.from(rawTokens.typography).filter(isFontWeight).sort()
},
colors: Array.from(rawTokens.colors).map(normalizeColor),
spacing: Array.from(rawTokens.spacing).sort(numericalSort),
radius: Array.from(rawTokens.radius).sort(numericalSort),
shadows: Array.from(rawTokens.shadows)
};
}javascript
// 提取页面所有计算样式
function extractDesignTokens() {
const allElements = document.querySelectorAll('*');
const tokens = {
typography: new Set(),
colors: new Set(),
spacing: new Set(),
radius: new Set(),
shadows: new Set()
};
allElements.forEach(el => {
const computed = window.getComputedStyle(el);
// 提取排版信息
tokens.typography.add(computed.fontFamily);
tokens.typography.add(computed.fontSize);
tokens.typography.add(computed.fontWeight);
// 提取颜色
if (computed.color !== 'rgba(0, 0, 0, 0)') {
tokens.colors.add(computed.color);
}
if (computed.backgroundColor !== 'rgba(0, 0, 0, 0)') {
tokens.colors.add(computed.backgroundColor);
}
// 提取间距
['margin', 'padding'].forEach(prop => {
['Top', 'Right', 'Bottom', 'Left'].forEach(side => {
const value = computed[prop + side];
if (value !== '0px') tokens.spacing.add(value);
});
});
// 提取圆角
if (computed.borderRadius !== '0px') {
tokens.radius.add(computed.borderRadius);
}
// 提取阴影
if (computed.boxShadow !== 'none') {
tokens.shadows.add(computed.boxShadow);
}
});
return normalizeTokens(tokens);
}
// 标准化并去重令牌
function normalizeTokens(rawTokens) {
return {
typography: {
fontFamilies: Array.from(rawTokens.typography).filter(isFontFamily),
fontSizes: Array.from(rawTokens.typography).filter(isFontSize).sort(),
fontWeights: Array.from(rawTokens.typography).filter(isFontWeight).sort()
},
colors: Array.from(rawTokens.colors).map(normalizeColor),
spacing: Array.from(rawTokens.spacing).sort(numericalSort),
radius: Array.from(rawTokens.radius).sort(numericalSort),
shadows: Array.from(rawTokens.shadows)
};
}Testing
测试
Run the test suite:
bash
node tests/run-tests.mjsTest coverage includes:
- Token extraction accuracy
- Markdown generation validity
- Color normalization (rgb → hex)
- Spacing scale deduplication
运行测试套件:
bash
node tests/run-tests.mjs测试覆盖范围包括:
- 令牌提取准确性
- Markdown生成有效性
- 颜色标准化(rgb → hex)
- 间距刻度去重
Common Patterns
常见模式
Extract and Save Workflow
提取并保存流程
javascript
async function extractAndSave(format = 'DESIGN') {
// 1. Extract tokens
const tokens = await extractDesignTokens();
// 2. Generate markdown
const markdown = format === 'DESIGN'
? generateDesignMD(tokens)
: generateSkillMD(tokens);
// 3. Download file
const blob = new Blob([markdown], {type: 'text/markdown'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${format}.md`;
a.click();
}javascript
async function extractAndSave(format = 'DESIGN') {
// 1. 提取令牌
const tokens = await extractDesignTokens();
// 2. 生成Markdown
const markdown = format === 'DESIGN'
? generateDesignMD(tokens)
: generateSkillMD(tokens);
// 3. 下载文件
const blob = new Blob([markdown], {type: 'text/markdown'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${format}.md`;
a.click();
}Custom Token Filtering
自定义令牌过滤
javascript
// Filter extracted colors by frequency
function filterFrequentColors(colors, minOccurrences = 5) {
const colorMap = new Map();
colors.forEach(color => {
const normalized = normalizeColor(color);
colorMap.set(normalized, (colorMap.get(normalized) || 0) + 1);
});
return Array.from(colorMap.entries())
.filter(([_, count]) => count >= minOccurrences)
.map(([color, _]) => color);
}javascript
// 按频率过滤提取的颜色
function filterFrequentColors(colors, minOccurrences = 5) {
const colorMap = new Map();
colors.forEach(color => {
const normalized = normalizeColor(color);
colorMap.set(normalized, (colorMap.get(normalized) || 0) + 1);
});
return Array.from(colorMap.entries())
.filter(([_, count]) => count >= minOccurrences)
.map(([color, _]) => color);
}Merge Multiple Extractions
合并多次提取结果
javascript
// Combine tokens from multiple pages
function mergeTokens(tokensArray) {
return {
typography: {
fontFamilies: [...new Set(tokensArray.flatMap(t => t.typography.fontFamilies))],
fontSizes: [...new Set(tokensArray.flatMap(t => t.typography.fontSizes))].sort(),
fontWeights: [...new Set(tokensArray.flatMap(t => t.typography.fontWeights))].sort()
},
colors: [...new Set(tokensArray.flatMap(t => t.colors))],
spacing: [...new Set(tokensArray.flatMap(t => t.spacing))].sort(numericalSort),
radius: [...new Set(tokensArray.flatMap(t => t.radius))].sort(numericalSort),
shadows: [...new Set(tokensArray.flatMap(t => t.shadows))]
};
}javascript
// 合并多个页面的令牌
function mergeTokens(tokensArray) {
return {
typography: {
fontFamilies: [...new Set(tokensArray.flatMap(t => t.typography.fontFamilies))],
fontSizes: [...new Set(tokensArray.flatMap(t => t.typography.fontSizes))].sort(),
fontWeights: [...new Set(tokensArray.flatMap(t => t.typography.fontWeights))].sort()
},
colors: [...new Set(tokensArray.flatMap(t => t.colors))],
spacing: [...new Set(tokensArray.flatMap(t => t.spacing))].sort(numericalSort),
radius: [...new Set(tokensArray.flatMap(t => t.radius))].sort(numericalSort),
shadows: [...new Set(tokensArray.flatMap(t => t.shadows))]
};
}Troubleshooting
故障排除
Extension Not Detecting Styles
扩展无法检测到样式
Issue: Extracted tokens are empty or incomplete.
Solutions:
- Wait for page to fully load (including dynamic content)
- Refresh extraction after SPA navigation
- Check if styles are in Shadow DOM (requires additional traversal)
- Verify content script has injected: → Inspect views
chrome://extensions
问题:提取的令牌为空或不完整。
解决方案:
- 等待页面完全加载(包括动态内容)
- SPA导航后重新提取
- 检查样式是否在Shadow DOM中(需要额外遍历)
- 验证内容脚本已注入:→ 检查视图
chrome://extensions
Download Not Working
下载功能失效
Issue: Generated file doesn't download.
Solutions:
javascript
// Ensure proper blob MIME type
const blob = new Blob([content], {type: 'text/markdown;charset=utf-8'});
// Add fallback for different browsers
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
} else {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}问题:生成的文件无法下载。
解决方案:
javascript
// 确保Blob的MIME类型正确
const blob = new Blob([content], {type: 'text/markdown;charset=utf-8'});
// 为不同浏览器添加兼容方案
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
} else {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}Duplicate Tokens
令牌重复
Issue: Multiple similar values extracted (e.g., and ).
16px16.5pxSolution:
javascript
// Round to nearest whole pixel
function roundPixels(value) {
const num = parseFloat(value);
return Math.round(num) + 'px';
}
// Apply tolerance-based deduplication
function deduplicateWithTolerance(values, tolerance = 1) {
return values.reduce((acc, val) => {
const num = parseFloat(val);
if (!acc.some(existing => Math.abs(parseFloat(existing) - num) < tolerance)) {
acc.push(val);
}
return acc;
}, []);
}问题:提取到多个相似值(例如:和)。
16px16.5px解决方案:
javascript
// 四舍五入到最接近的整数像素
function roundPixels(value) {
const num = parseFloat(value);
return Math.round(num) + 'px';
}
// 基于容差的去重
function deduplicateWithTolerance(values, tolerance = 1) {
return values.reduce((acc, val) => {
const num = parseFloat(val);
if (!acc.some(existing => Math.abs(parseFloat(existing) - num) < tolerance)) {
acc.push(val);
}
return acc;
}, []);
}Cross-Origin Restrictions
跨域限制
Issue: Cannot extract from iframe with different origin.
Solution: Extension permissions already include , but iframes require explicit traversal:
<all_urls>javascript
function extractFromIframes() {
const iframes = document.querySelectorAll('iframe');
iframes.forEach(iframe => {
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
// Extract from iframe document
extractDesignTokens(iframeDoc);
} catch (e) {
console.warn('Cannot access iframe:', e);
}
});
}问题:无法提取不同源iframe中的样式。
解决方案:扩展权限已包含,但iframe需要显式遍历:
<all_urls>javascript
function extractFromIframes() {
const iframes = document.querySelectorAll('iframe');
iframes.forEach(iframe => {
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
// 从iframe文档提取
extractDesignTokens(iframeDoc);
} catch (e) {
console.warn('无法访问iframe:', e);
}
});
}Integration with AI Coding Tools
与AI编码工具集成
Using Extracted DESIGN.md with Claude Code
将提取的DESIGN.md与Claude Code配合使用
bash
undefinedbash
undefinedAdd to project context
添加到项目上下文
cp DESIGN.md .claude/
cp DESIGN.md .claude/
Reference in prompts
在提示词中引用
"Build a button component following DESIGN.md spacing and color tokens"
undefined"按照DESIGN.md中的间距和颜色令牌构建一个按钮组件"
undefinedUsing with Cursor
与Cursor配合使用
bash
undefinedbash
undefinedAdd to .cursorrules
添加到.cursorrules
cp DESIGN.md .cursorrules/design-system.md
cp DESIGN.md .cursorrules/design-system.md
Reference in code
在代码中引用
// Uses spacing-4 (16px) from DESIGN.md
<div className="p-4">
```// 使用DESIGN.md中的spacing-4(16px)
<div className="p-4">
```Using with Google Stitch
与Google Stitch配合使用
Upload as a custom skill to enable design-system-aware code generation.
SKILL.md上传作为自定义技能,启用支持设计系统的代码生成。
SKILL.mdResources
资源
- Chrome Web Store: https://chromewebstore.google.com/detail/designmd-style-extractor/ogpdnchdjiibhobphelbbkemnnemkfma
- TypeUI Format Spec: https://www.typeui.sh/design-md
- Curated Skills: https://www.typeui.sh/design-skills
- GitHub Repository: https://github.com/bergside/design-md-chrome