用 DESIGN.md 打造「制图师图鉴」深色编辑社论风设计系统:完整范例与源码级拆解
【免费下载链接】design.mdA format specification for describing a visual identity to coding agents. DESIGN.md gives agents a persistent, structured understanding of a design system.项目地址: https://gitcode.com/GitHub_Trending/de/design.md
导读:The Cartographer's Atlas(制图师图鉴)是本仓库packages/cli中一个完整的 DESIGN.md 示例文档,它用 YAML 设计 token 与 Markdown 说明正文的双层结构,完整描述了一套「18 世纪航海制图 × 21 世纪数据可视化」的高端深色编辑社论风设计系统。本文以该文档为骨架,逐字段解析其 frontmatter 与八个正文章节的写法,并结合解析器、模型校验、lint 规则与多格式导出源码,说明这份文档从「设计描述」到「可被 Agent 执行的规范」的完整链路。读完你将掌握:如何用 DESIGN.md 结构化的颜色/字体/间距 token 承载设计决策,如何用 prose 传达品牌气质,以及如何用lint/export命令验证并转换这套设计系统。
一、这是什么:一个被当作「验收样例」的完整设计系统
The Cartographer's Atlas位于 packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md,是 linter 测试目录下的一组 fixture 之一。同目录还包含DESIGN-test.md、ALPINE_OBSERVATORY.md、HERITAGE.md等其他样例(见 fixtures 目录),它们共同构成了 DESIGN.md 格式的「真实世界样本集」——每份文档都必须能被 lint.ts 正常解析、建模、校验并导出。
这份文档的目标很清晰:建立一套连接 18 世纪海事导航与当代数据可视化的高端编辑氛围。品牌人格被定义为「权威、神秘、精确」(authoritative, mysterious, precise),目标受众是学者、分析师与长文数字叙事的爱好者。其风格是Minimalism(极简主义)与 Modern Editorial(现代社论)的混合体——依靠纪念碑式的排版和极端的明暗对比,而非装饰性修饰。原文档用一句极富画面感的话定义了审美响应:「如同在昏暗的书房里展开一张厚重的稀有纸地图:安静、克制、广袤。」
从格式规范(docs/spec.md)看,任何 DESIGN.md 都由两部分组成:
- 可选的 YAML frontmatter——机器可读的设计 token(
---定界符包裹); - Markdown 正文——按规范顺序排列的
##章节,提供人类可读的设计理由与使用指引。
token 是规范性数值(normative values),prose 则提供「为什么这样设计」的上下文。这正是「制图师图鉴」同时写好两者的原因:它有 40+ 个颜色 token、7 个文字层级和 4 个间距 token 支撑精确实现,又有 8 个章节解释每个决策背后的制图学隐喻。
二、YAML Frontmatter 逐块拆解
2.1 顶层结构:name 与四类 token 组
frontmatter 位于 CARTOGRAPHERS_ATLAS.md 第 1-99 行,顶层键遵循 parser/spec.ts 中定义的 SCHEMA_KEYS(version、name、description、omitted、colors、typography、rounded、spacing、components):
name: The Cartographer's Atlas colors: { ... } # 40+ 个颜色 token typography: { ... } # 7 个文字层级 spacing: { ... } # 4 个间距 token注意此文档没有声明version(当前格式版本为alpha,见 spec-config.yaml),也没有rounded与components组——这不是遗漏,而是与正文「Shapes 严格 0px 圆角」「组件以 prose 描述」的决策自洽。从 ModelHandler 的建模逻辑看,缺失的组会以空 Map 进入模型,随后由 lint 规则给出提示(见下文第六节)。
2.2 colors:一套 Material 3 风格的深色表面系统
colors 组是这份文档信息密度最高的部分,采用surface/on-surface/primary-container等语义化命名(类似 Material Design 3 的 tonal palette 思路),完整列表如下:
| 分组 | Token |
|---|---|
| 表面层级 | surface: #0f131c、surface-dim: #0f131c、surface-bright: #353942、surface-container-lowest: #0a0e16、surface-container-low: #181c24、surface-container: #1c2028、surface-container-high: #262a33、surface-container-highest: #31353e |
| 表面文字 | on-surface: #dfe2ee、on-surface-variant: #c7c6cc |
| 反转色 | inverse-surface: #dfe2ee、inverse-on-surface: #2c3039 |
| 描边 | outline: #909096、outline-variant: #46464c |
| 主色系 | surface-tint: #c3c6d7、primary: #c3c6d7、on-primary: #2c303d、primary-container: #0a0e1a、on-primary-container: #777b8a、inverse-primary: #5a5e6d |
| 次色系 | secondary: #b9c8dc、on-secondary: #233241、secondary-container: #3c4a5b、on-secondary-container: #abbacd |
| 强调色 | tertiary: #ecc246、on-tertiary: #3d2e00、tertiary-container: #150e00、on-tertiary-container: #987700 |
| 错误色 | error: #ffb4ab、on-error: #690005、error-container: #93000a、on-error-container: #ffdad6 |
| fixed 变体 | primary-fixed: #dfe2f3、primary-fixed-dim: #c3c6d7、on-primary-fixed: #171b28、on-primary-fixed-variant: #434654,以及secondary-fixed*、tertiary-fixed*各四枚 |
| 背景 | background: #0f131c、on-background: #dfe2ee、surface-variant: #31353e |
从实现层面看,这些 token 会被 color-parser.ts 解析:它支持#RGB、#RGBA、#RRGGBB、#RRGGBBAA十六进制、CSS 命名色、rgb()/rgba()/hsl()/hsla()/hwb()、宽色域oklch()/oklab()/lch()/lab()以及color-mix(),并统一换算为 sRGB 计算 WCAG 相对亮度(luminance),用于后续对比度校验(parseCssColor 入口)。规范建议默认使用#RRGGBB简写,本文档全部采用该格式,是规范推荐写法的直接示范。
与正文 Colors 章节的四角色调对照(见第四节),prose 中的Neutral / Primary / Secondary / Tertiary是叙事层概念,而 frontmatter 中的 token 是精确数值层——两者通过一致的色相家族互相印证:正文的#C9A227金色对应 token 层的tertiary: #ecc246这一「Compass Rose」强调色家族。
2.3 typography:三种字体的七级文字系统
typography 组定义了 7 个文字层级,构成「字体 × 字号 × 字重 × 行高 × 字距」的完整矩阵:
| Token | fontFamily | fontSize | fontWeight | lineHeight | letterSpacing |
|---|---|---|---|---|---|
display-hero | Newsreader | 84px | 300 | 1.1 | 0.05em |
headline-xl | Newsreader | 48px | 400 | 1.2 | 0.02em |
headline-md | Newsreader | 32px | 400 | 1.3 | 0.02em |
body-lg | Manrope | 18px | 400 | 1.7 | 0.01em |
body-md | Manrope | 16px | 400 | 1.7 | 0.01em |
label-caps | Work Sans | 12px | 600 | 1.0 | 0.25em |
coordinate | Work Sans | 10px | 400 | 1.0 | 0.1em |
这些属性均在 spec-config.yaml 的 typography_properties 中定义:fontFamily(string)、fontSize(Dimension)、fontWeight(number,YAML 中裸数字或引号字符串等价)、lineHeight(Dimension 或 unitless 数字,unitless 表示 fontSize 的倍数)、letterSpacing(Dimension),以及扩展项fontFeature/fontVariation。文档中的fontWeight: '300'使用带引号字符串,ModelHandler 的 parseTypography 会将其安全转为数值 300。
Dimension 只允许px、em、rem三种单位(spec-config.yaml 的 units),非法单位会被标记为 error。这里所有字号用 px、行高用 unitless 倍数、字距用 em,正是规范推荐的「CSS 实践」写法。
2.4 spacing:四个叙事性间距 token
spacing: unit: 4px gutter: 24px margin: 64px section-gap: 128px与常见的xs/sm/md/lg递进刻度不同,这份文档用语义命名表达制图学式的宽幅节奏:unit是基础单位 4px,gutter栏间距 24px,margin页边距 64px,section-gap章节间距高达 128px——后者直接对应正文「用巨大的纵向间距分隔叙事节拍」的设计决策。从 ModelHandler 看,spacing 接受 Dimension 或 unitless 数字,且宽松处理(非合法维度会以字符串存储),因此未来想表达「12 列」这类纯数字刻度也是允许的。
三、正文章节骨架:符合规范顺序的八个决策载体
格式规范在 docs/spec.md 的 Sections 一节 规定:所有章节使用##标题,可省略但出现时必须按规范顺序排列。The Cartographer's Atlas的正文(第 101 行起)提供了其中七个章节的示范写法,顺序与规范完全一致,且每个章节都践行「token 给精确值、prose 给理由」的分工。
四、正文逐章解读:制图学隐喻如何落到每个设计决策
4.1 Brand & Style:品牌人格的「总开关」
「Brand & Style」是规范中 Overview 章节的别名(spec-config.yaml 的 sections 定义)。这节的职责是给出产品整体观感:品牌人格、目标受众、UI 应唤起的情感反应。文档在此明确了三层信息:
- 风格定位:Minimalism × Modern Editorial 的混合;
- 审美隐喻:「昏暗书房中展开的厚重纸地图」;
- 情感目标:quiet(安静)、intentional(克制)、vast(广袤)。
规范指出(docs/spec.md Overview 章节),当某条具体规则或 token 未定义时,Agent 会依靠本节做高层风格决策——所以它是 Agent 生成 UI 时的「默认裁判」。
4.2 Colors:Obsidian Canvas 与四角色调
正文 Colors 章节(第 107-114 行)把整套 token 归纳为四个叙事角色:
- Neutral(#080C14):主背景 / 虚空,提供无限深度;
- Primary(#0A0E1A):结构面板、卡片与内嵌表面;与 Neutral 的对比微妙,制造深度而不产生生硬线条;
- Secondary(#2C3A4A):极细分隔线或结构参考线,仅在色调对比不足时使用,必须极度克制;
- Tertiary / Accent(#C9A227):UI 的「罗盘玫瑰」金色,每个视图只允许出现一次——通常是主操作或唯一的数据焦点。
这与规范对 Colors 章节的要求吻合:至少定义primary,可定义多套调色板并按primary → secondary → tertiary → neutral的顺序命名(docs/spec.md Colors 章节)。值得注意的细节是正文给每套调色板的使用约束(「每视图仅一次」「极端克制」),这类语义在 token 数值里表达不了,正是 prose 存在的意义。
4.3 Typography:排版即美学载体
正文 Typography 章节(第 116-122 行)把「Cartographer 美学」的核心压在排版上,三字体分工如下:
- Headlines → Newsreader:高对比度传统衬线,display 尺寸用细字重 + 宽松字距,营造纪念碑式的轻盈感——对应
display-hero(84px / 300 字重 / 0.05em)与headline-*层级; - Body → Manrope:保证可读性,1.7 行高是强制值,以在深色背景上维持「开放」的社论感——对应
body-lg/body-md; - Labels & Annotations → Work Sans:全大写 + 宽字距,模仿海图上的技术坐标——对应
label-caps(0.25em 字距)与coordinate层级。
三者的组合逻辑(衬线叙事 + 无衬线正文 + 等宽感标签)在 frontmatter 与 prose 中互为印证,是「token 与 prose 双通道描述」的教科书案例。
4.4 Layout & Spacing:Fixed Grid 与稀疏节奏
Layout 章节(第 124-128 行)采用Fixed Grid模型:在 full-bleed 画布内,图片与背景面板可延伸至边缘,但排版内容必须落在严格的12 列网格 + 宽边距内。节奏被定义为「稀疏」:不鼓励高密度信息,用巨大的纵向间距(section-gap: 128px)分隔叙事节拍——「元素应像黑暗海洋中的孤岛」。
对比同目录的 DESIGN-test.md(Pacific Mint Dental 牙科诊所主题)会发现同一种格式如何表达不同哲学:那边是「1200px 容器 + 8px 基础单位 + 24px gutter + 48-64px 章节间距」的现代商业节奏,这边是「64px margin + 128px section-gap」的宏大叙事节奏——Layout 章节 + spacing token 的组合足以让 Agent 区分「信息密集的医疗界面」与「气定神闲的编辑长文」。
4.5 Elevation & Depth:用色调分层替代阴影
Elevation 章节(第 130-138 行)做出了一个反直觉但高度自洽的决策:整个系统没有任何阴影,深度完全靠 Tonal Layering(色调分层)与留白实现:
- Level 0(Background):#080C14,基础画布;
- Level 1(Panels):#0A0E1A,内容块或「浮动」地图片段;
- Level 2(Interaction):hover 态通过背景色轻微偏移或引入 #2C3A4A 发丝线边框。
并规定「避免堆叠超过两层深度」,界面应像铺在桌面上的实体地图一样平坦。规范对 Elevation 章节的要求正是「说明如何基于设计风格传达视觉层级;扁平设计必须解释替代手段(边框、对比度等)」——本节的 Level 0/1/2 分层 + 发丝线边框方案正是这一要求的完整回答。
4.6 Shapes:0px 圆角与「切纸感」
Shapes 章节(第 140-142 行)将形状语言严格定为Sharp(尖锐):按钮、卡片、输入框、图片一律0px 圆角,以强化制图学的精确性与档案纸的「切纸感」。
这是「用 prose 定义 Shapes、而不在 YAML 里写rounded」的典型场景。运行时,缺失的rounded组会触发missing-sections规则的 info 提示:「No 'rounded' section defined. Corner rounding will fall back to agent defaults.」(见 missing-sections.ts)。换言之,如果你想让「0px」成为强制而非 Agent 默认值,应通过roundedtoken 显式声明——例如rounded: { none: 0px },或像 DESIGN-test.md 那样定义完整的sm/md/lg/full刻度。若确实想声明「不采用圆角体系」,规范还提供omitted机制(docs/spec.md Omitted 一节),例如:
omitted: - section: rounded reason: "0px radius enforced by prose; no rounded scale defined in brand book"4.7 Components:六类组件的原子规范
Components 章节(第 144-151 行)用 prose 定义了六类组件,每一类都给出可执行的视觉规则:
- Buttons:大号矩形、0px 圆角。主 CTA 是唯一允许使用金色(#C9A227)背景配深色文字的元素;次级按钮为透明底 + 细 #2C3A4A 描边——与 4.2 节「金色每视图一次」的约束闭环;
- Cards:以对背景的色调变化(#0A0E1A)定义,除非可访问性需要否则不加边框;
- Inputs:极简下边框式,或纯 Primary 色块;字段标题用
label-caps字体; - Lists:宽垂直内边距的干净行,索引数字用
coordinate风格字体(如 001、002); - The Compass Rose:定制图标 / 导航元素,是构图中唯一的金色点缀,用于返回「北」(首页)或触发主叙事流;
- Data Points:小的尖锐方块或十字准星字形(Secondary 色),用于地图标注。
规范允许 Components 章节以 prose 或 token(components:组)两种方式书写。若要用 token 形式表达同一意图(组件级backgroundColor/textColor/rounded/padding等属性,见 docs/spec.md Component Property Tokens 一节),例如把「主按钮」精确化:
components: button-primary: backgroundColor: "{colors.tertiary}" textColor: "{colors.on-tertiary}" padding: 16px 32px button-secondary: backgroundColor: "{colors.surface}" textColor: "{colors.secondary}"五、从文档到模型:解析与建模的源码链路
要理解这份 fixture 为什么是「可执行规范」,需要看它被消费的完整管道,核心入口是 lint.ts:
- 解析(Parser):ParserHandler 用 unified + remark 解析 Markdown,识别 frontmatter 与 fenced yaml 代码块,提取所有
##章节标题与内容分区。它会检测「重复顶层键」(如两个colors组)并报DUPLICATE_SECTION错误,也会收集每个 token 的源位置(sourceMap); - 建模(Model):ModelHandler 分三阶段构建
DesignSystemState:先解析原始 token(颜色、排版、圆角、间距),再解析链式 token 引用({colors.primary},带环检测与最大深度限制),最后构建components的属性质表;所有解析都遵循「Never throws」原则,异常转为 findings; - 校验(Linter):runLinter 按序执行 11 条默认规则,产出按 error/warning/info 聚合的 findings;
- 导出(Emitter):同一模型可直接生成 Tailwind v3 / v4 主题、DTCG tokens.json 与 CSS 变量。
fixture 在测试中的角色可见于 fixture.test.ts:它读取DESIGN-test.md,断言designSystem.name、具体 token 的 hex 值与 fontSize 单位,并验证非法单位 error 数量为零——这证明 fixtures 不仅用于演示,还被作为端到端验收样本持续回归。
六、lint 会怎么评价这份文档:11 条规则逐一对照
从 rules/index.ts 的 DEFAULT_RULE_DESCRIPTORS 可见 11 条默认规则,我们逐一预演「制图师图鉴」会得到什么结论:
| 规则 | 严重度 | 对本文档的预期结论 |
|---|---|---|
broken-ref | error | 无components组,无从触发;若引入组件引用需保证{colors.tertiary}等路径可解析 |
missing-primary | warning | 定义了primarytoken,不触发 |
contrast-ratio | warning | 无组件级backgroundColor/textColor配对,不触发;但若把该设计实现为 token 组件,on-tertiary #3d2e00与tertiary #ecc246等高对比配对可被自动核验(阈值 4.5:1,见 contrast-ratio.ts) |
orphaned-tokens | warning | 定义了大量颜色 token 但无组件引用,会提示——这正是 prose 驱动系统的预期形态,可在文档中补充说明以消除疑虑 |
token-summary | info | 输出各组的 token 数量统计 |
missing-sections | info | 无spacing?不,已定义;无rounded会提示「圆角回退到 Agent 默认值」 |
missing-typography | warning | 已定义 typography,不触发 |
section-order | warning | 正文顺序与规范一致,不触发 |
unknown-key | warning | frontmatter 全部键名合法,不触发 |
token-like-ignored | warning | 无被忽略的 token 形态未知键,不触发 |
omitted-rules | info | 未使用omitted,不触发 |
七、实操:用 CLI 验证与导出这套设计系统
7.1 安装与 lint 验证
仓库的 README.md 说明了安装方式(本地仓库安装或npx直跑,Windows 下可用designmd别名规避.md后缀与文件关联的冲突)。对本仓库内的样例验证:
npx @google/design.md lint packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md输出为 JSON,含findings(每条含 severity / path / message)与summary(errors / warnings / infos 计数);存在 error 时退出码为 1(实现见 lint.ts 命令)。也可从 stdin 读取:cat ... | npx @google/design.md lint -。
7.2 多格式导出
export.ts 命令 支持五种格式,全部作用于同一份解析后的设计系统模型:
# Tailwind v3 theme.extend JSON npx @google/design.md export --format json-tailwind packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md # Tailwind v4 CSS @theme 块(CSS 自定义属性命名空间) npx @google/design.md export --format css-tailwind packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md # W3C Design Tokens(DTCG)tokens.json npx @google/design.md export --format dtcg packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md # CSS 自定义属性(可加 --prefix) npx @google/design.md export --format css-vars --prefix atlas packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md各发射器的映射逻辑可直接阅读源码:Tailwind v3 由 tailwind/handler.ts 生成theme.extend(colors → hex、fontFamily → 字体数组、fontSize →[size, {lineHeight, letterSpacing, fontWeight}]);Tailwind v4 由 tailwind/v4/serialize.ts 序列化为@theme块,按--color-*、--font-*、--text-*、--leading-*、--tracking-*、--font-weight-*、--radius-*、--spacing-*的固定顺序输出。
7.3 diff 与 spec
# 对比两版设计系统的 token 级变更与回归 npx @google/design.md diff packages/cli/src/linter/fixtures/CARTOGRAPHERS_ATLAS.md packages/cli/src/linter/fixtures/DESIGN-test.md # 输出格式规范全文(含 --rules 附加规则表),便于注入 Agent 提示词 npx @google/design.md spec八、与其他 fixture 对比:同一格式、两种美学谱系
将「制图师图鉴」与 DESIGN-test.md(Pacific Mint Dental)对照,可以直观看到 DESIGN.md 的「表达带宽」:
| 维度 | The Cartographer's Atlas | Pacific Mint Dental |
|---|---|---|
| 美学 | 深色编辑社论 / 航海制图 | 临床宁静 / 现代公司 |
| 表面色 | #0f131c系近黑 | #f9f9ff系近白 |
| 圆角 | prose 规定 0px,无 rounded token | sm: 0.25rem到full: 9999px完整刻度 |
| 容器 | 12 列全出血 + 64px margin | 1200px 固定容器 + 8px 基础单位 |
| 排版 | Newsreader/Manrope/Work Sans | Manrope/Inter |
| 组件 | prose 描述 6 类 | prose 描述 5 类(含签名组件 Calendar Widget) |
两份文档均能被同一管道解析、校验、导出,说明格式的「token 给数值、prose 给理由」约定不绑定任何特定设计哲学——深色扁平与浅色圆角只是同一格式的两个合法实例。
九、把这份范例用于你的项目的建议
- 先写 Brand & Style,再写 token:品牌人格决定后续所有决策;「每视图一次金色」「无阴影」「0px 圆角」这类约束必须落在 prose 里才不会被 Agent 忽略;
- 用语义化 token 名而非色板名:
surface-container-high比darkgray-3更能驱动实现;规范在 docs/spec.md Recommended Token Names 一节 给出了非强制性的推荐命名集(primary/secondary/tertiary/neutral/surface/on-surface/error等); - prose 约束与 token 数值双通道对齐:若 prose 规定「1.7 行高是强制值」,务必同步在
typography.body-md.lineHeight写入1.7,让 lint 与导出都拿到同一事实; - 对「故意缺失」的组显式声明:不打算定义圆角刻度或间距刻度时,用
omitted+reason记录原因,既消除missing-sections提示,也让 Agent 理解这是决策而非疏漏; - 把 fixture 当模板:需要快速生成新设计系统时,可以基于本文件的结构(colors 全量语义组 + typography 分级 + spacing 语义键 + 章节骨架)替换数值,再用
lint回归验证、用export落入工程配置。
这份CARTOGRAPHERS_ATLAS.md完整展示了 DESIGN.md 的核心价值:让一个「昏暗书房里的制图师」级审美,变成 Agent 能够精确复现的持久化、结构化规范。文档在 fixtures 目录 中与解析器、模型、lint 规则、发射器共同演进,既是演示样本,也是格式规范的活体测试。若想深入格式本身的细节,可直接阅读 docs/spec.md 与 spec-config.yaml——后者是规范生成器与 linter 共同读取的单一事实来源。
【免费下载链接】design.mdA format specification for describing a visual identity to coding agents. DESIGN.md gives agents a persistent, structured understanding of a design system.项目地址: https://gitcode.com/GitHub_Trending/de/design.md
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考