DESIGN.md 设计哲学深度解析:为什么“文字叙述“才是视觉身份规范的核心
2026/9/10 23:33:33 网站建设 项目流程

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

DESIGN.md 是一种用于向编码 Agent 描述视觉身份的格式规范,而 PHILOSOPHY.md 记录了这套规范背后的核心设计哲学:设计的灵魂存在于文字叙述(prose)之中,设计令牌(tokens)只是支撑叙述的上下文。读完本文,你将理解为什么"一句具体的参照"胜过"一打精确的数值"、为什么负面约束(don'ts)能自动随引用而来,以及这个格式如何在不修改规范的前提下,通过用户自定义扩展生长出属于自己的设计语言——每一条结论都会结合本仓库的源码、测试与示例给出可验证的依据。

一句话抓住 DESIGN.md 的哲学核心

DESIGN.md captures how a design looks, feels, and behaves. The prose is where the design lives. Everything else in the document exists to support it.

翻译过来即:DESIGN.md 记录的是一个设计看起来、感觉起来、行为起来的样子;设计活在叙述文字里,文档中的其他一切(令牌、结构、规范)都只是为叙述服务

这句开宗明义的话直接决定了 PHILOSOPHY.md 全文的论述方向,也解释了为什么 DESIGN.md 会同时包含两种截然不同的内容层——机器可读的 YAML 令牌与人类(以及 Agent)可读的 Markdown 叙述。

哲学落地的最小示例:Technical Handout

原文档用一个极简示例展示了"叙述即设计"的含义:

--- name: Technical Handout --- ## Overview A graduate-level computer science lecture handout in the tradition of an old established university. The audience is graduate students and research engineers reading a printed handout distributed at the beginning of a seminar. The handout is austere, informationally dense, and proudly unconcerned with first impressions. The audience knows why they are there and the handout's job is to do work, not to seduce.

请注意这个示例的精妙之处:front matter 里只有一个name,没有任何颜色、字体、间距令牌。整份文档的设计意图完全由 Overview 中的三段叙述承载——"老牌大学研究生级别的课堂讲义""信息密集、毫不讨好第一印象"。"austere"(朴素克制)、"proudly unconcerned with first impressions"(骄傲地不关心第一印象)这些措辞,向 Agent 传递的是一种完整的态度,而非一组数值。

由此引出全文最重要的一句话:

生成设计质量的优劣,更多取决于"意图被描述得有多清晰",而非"数值有多精确"。

仓库层面的呼应:DESIGN.md 的双层结构

README.md 将这种哲学固化为格式本身:"A DESIGN.md file combines machine-readable design tokens (YAML front matter) with human-readable design rationale (markdown prose). Tokens give agents exact values. Prose tells themwhythose values exist and how to apply them."

而规范文档 docs/spec.md 中说得更直接:"The tokens are the normative values; the prose provides context for how to apply them."(令牌是规范性数值;叙述为如何应用它们提供上下文。)"normative / context" 的措辞与"价值观/为什么"的措辞一脉相承——数值负责精确,叙述负责意义,两者缺一不可。

Prose, not Tokens:叙述才是规范的主角

原文档明确划分了 DESIGN.md 的两大组成:tokensprose。规范存在的意义是"描述设计语境"——既要让设计在不同生成会话之间保持一致性,又要为创造性探索留出空间。而其中prose 是最关键的部分

一个完整的 Colors 对照示例

原文档给出了一个同时包含令牌与叙述的典型段落:

## Colors ```yaml # Tokens colors: paper: '#F4F0E4' ink: '#1E1A14' vermilion: '#C3402A' rule-gray: '#B8B0A2' ``` <!-- Prose --> A single-ink-plus-accent system. - **Paper** {colors.paper} is the canvas — warmed xerox stock, never pure white. - **Ink** {colors.ink} is graphite-warm and carries all typography, all rules, all diagram strokes; never pure black. - **Vermilion** {colors.vermilion} is the single accent and appears only inside diagrams and chart annotations — never on typography, never on page numerals, never on metadata of any kind. - **Rule gray** {colors.rule-gray} is reserved for hairline rules inside content (chart baselines, table dividers); never used as page-frame chrome.

注意这里出现了 DESIGN.md 特有的语法:{colors.paper}这样的花括号令牌引用,让叙述能够动态指向 front matter 中的精确值。同一段文字里,"warmed xerox stock, never pure white"(温暖的复印纸质感,绝非纯白)这类描述承载了#F4F0E4这个十六进制值背后的全部理由——为什么是它、它应该被用在什么场合、绝对不能用在什么场合。

在仓库的真实示例 examples/atmospheric-glass/DESIGN.md 中可以看到同样的结构:front matter 定义了全套 Material 风格的颜色令牌(surface-container-loweston-primaryerror-container等)与 Inter 字体排印令牌,正文则用 "vibrant-minimalist"、"frosted crystalline lenses"(磨砂水晶透镜)等叙述交代了玻璃拟态美学的完整意图。另一个测试夹具 packages/cli/src/linter/fixtures/ALPINE_OBSERVATORY.md 则展示了"Scientific Alpinism"(科学式阿尔卑斯登山)这种风格:#0a1325的深海军蓝被称为The Void(虚空),#f6bb81的古董黄铜被称为The Instrument(仪器)——数值与叙事互相锚定。

令牌是上下文,不是渲染指令

这是全文最容易被误解、也最值得强调的论点:

令牌值作为上下文存在,而非渲染指令。一般而言,规范并不要求也不建议你在规范里硬性规定令牌。

把令牌当作"叙述中引用的参考物",DESIGN.md 的职责就聚焦在"记录设计的本质"上,而不是去重复语言和工具生态早已耕耘几十年的工作——字体加载、颜色空间转换、间距计算这些事,交给 CSS、Tailwind、Figma 或设计令牌工具链去解决。本仓库恰好用代码证明了这种分工:packages/cli/src/linter/tailwind/v4/serialize.ts 与 packages/cli/src/linter/dtg/handler.ts 负责把令牌导出为 Tailwind v4 的@theme块或 W3C DTCGtokens.json——格式本身只负责定义与描述,真正的渲染由这些成熟的既有工具完成。

叙述语法的规范依据

从 docs/spec.md 可以看到这种"叙述为主、令牌为辅"的结构被固化为规范:

  • Color:任何合法 CSS 颜色字符串(Hex、命名色、rgb()/hsl()/hwb()、宽色域oklch()/oklab()/lch()/lab()、以及color-mix(in srgb, ...)混合);Hex#RRGGBB被推荐为默认写法。
  • Dimension:带单位后缀的字符串,正式支持的单位为pxemrem(见 packages/cli/src/linter/spec-config.yaml 中的units定义)。
  • TypographyfontFamilyfontSizefontWeightlineHeightletterSpacingfontFeaturefontVariation七个属性;lineHeight既可写24px这类 Dimension,也可写1.6这种无单位倍数。
  • Token Reference{path.to.token}花括号引用语法,在components内允许引用复合值(如{typography.label-md})。

一个具体参照,胜过一打形容词

原文档用一个尖锐的对比论证了"具体参照"的价值:

A design that references "A 1970s graduate lecture handout in the tradition of an old and established university" evokes a complete world: the one color of ink, the generous margins, the serif set at a reading size, and the absence of decoration. That single sentence carries more useful information than a dozen metric values. It carries the reasoning behind the values.

"一份 1970 年代老牌大学的研究生课堂讲义"这句话唤起的是一整个完整的世界:单一颜色的墨水、宽大的页边距、以阅读字号排版的衬线字体、以及完全没有装饰。这一句话携带的有用信息,超过一打度量值——因为它携带了数值背后的推理过程。

反过来:

"Modern, clean, trustworthy, premium" evokes nothing specific. A model creates something in the center of what those words describe, creating an output that is typically generic. Adjectives describe a region. A specific reference describes a point.

"现代、干净、可信、高级"这类形容词唤不起任何具体画面。模型会在这个词所描述的区域正中央生成一个东西——通常是平庸的、随大流的结果。形容词描述的是一个区域,具体参照描述的是一个点。

这个观点可以直接指导写作实践:与其罗列border-radius: 8pxbox-shadow参数,不如写"像一本学术期刊的版面";与其堆砌"优雅、极简、专业",不如写"像 1970 年代老牌大学的课堂讲义"。Agent 对具体参照的理解能力,本质上来自它对现实世界物体的海量训练知识——命名一个对象,就等于同时传递了它的全部隐含属性。

在 examples/paws-and-paths/DESIGN.md、examples/totality-festival/DESIGN.md 这些示例中可以看到同样的手法:每个设计系统都用一句"它是什么"来锚定全部后续决策,而不是用形容词清单。

负面约束:你省略掉的东西定义了性格

"一个清晰的设计参照会自动携带它的限制。"原文档的论证如下:

A model knows what a lecture handout is, and it knows what a lecture handout is not. It does not glow or use a gradient. You don't have to list these. Naming the object names them, the same way naming a dog tells the model that dogs don't meow.

模型知道课堂讲义是什么,也知道它不是什么——它不会发光、不会用渐变。这些根本不需要你列举。命名即命名:就像你说了"狗",模型自然知道狗不会喵喵叫。

由此得出两条实用结论:

  1. 当参照足够具体时,负面约束是免费附赠的。一个具体的参照("讲座讲义")本身就排除了大量的错误方向。
  2. 有意的"不要做"清单是有用的,冗长的流水账式清单往往是描述过于模糊的信号。如果你需要靠十几条禁令才能防止 Agent 跑偏,通常说明你的正面描述还不够具体。

两者的理想配合是:"一个强参照 + 一份有意为之的 Do's and Don'ts 清单"。

原文档的完整 Do's and Don'ts 示例

## Do's and Don'ts - **Don't** add a hero moment to the title page. A real handout title page is the first page of content, not a magazine cover. - **Don't** reach for an italic standfirst beneath a large title. That is the Substack register. - **Don't** add corner ornaments, chapter marks, or abstract glyphs in the margins. - **Don't** color the page numeral or any other piece of metadata. Vermilion lives in diagrams only. - **Don't** use a display-class serif. One family at four modest sizes. - **Don't** use Bold. Anywhere. - **Don't** use sans-serif for any role other than monospace metadata. - **Don't** introduce dark mode, gradients, glows, glass surfaces, drop shadows, or rounded corners. - **Do** treat the handout as a printed object. The screen is the substrate; the design is the page. - **Do** keep vermilion inside diagrams. Its scarcity outside is what makes its presence inside meaningful. - **Do** trust modest size differences. The section title is only ~1.9× body, not 5× body. - **Do** let pages have visible white space. A page that ends two-thirds of the way down is correct, not under-filled.

这份清单的每个条目都值得品味:它不是在罗列"不允许出现的 CSS 属性",而是在陈述性格——"标题页不是杂志封面""屏幕只是载体,设计是纸张本身""朱红色的稀缺性正是其内部出现时有意义的原因"。注意那些明确的参照点:"That is the Substack register"(那是 Substack 的腔调)、"One family at four modest sizes"(单一字体家族、四个克制的字号)、"~1.9× body"(正文的约 1.9 倍)。每条禁令都指向一个可被模型精确理解的参照物,而不是一个抽象形容词。

规范层面,docs/spec.md 将 "Do's and Don'ts" 列为八个标准小节中的最后一个(第 8 位),定位是"创建设计时的护栏(guardrails)";packages/cli/src/linter/spec-config.yaml 中的sections定义确认了它的规范名称与别名,而section-order这一条 lint 规则(见 packages/cli/src/linter/linter/rules/section-order.ts)会校验小节是否按规范顺序出现。

格式通过用户生长,而不是通过规范生长

结构最小主义:只标准化"通用到值得统一"的部分

原文档指出,规范定义的只是每一份 DESIGN.md 都共享的结构性最小集

  • 一个name
  • 一小撮足够通用、值得标准化的类别:colorstypographyspacingroundedcomponents

除此之外,一切都是你的自由。格式接受你的设计系统需要的任何键、任何小节、任何结构。

规范在"一致性有帮助的地方"做标准化,在"灵活性更有帮助的地方"保持开放。原文档特别点名了这些开放领域:motion(动效)、iconography(图标)、elevation(层级)、text casing(文字大小写)、paragraph measure(段落行长)

理由很实际:同一类令牌在不同团队里形态天差地别。一个团队的 motion 令牌是 CSS 动画曲线;另一个团队的则是以缓冲块(buffer blocks)为单位的音频域时间常数。正确的形态取决于每个系统自身,而格式本身已经允许你定义它。

Motion 扩展示例

原文档用"动效"这个自定义类别演示了如何不修改规范就完成扩展:

## Motion ```yaml motion: feedback: 120ms content: 250ms easing: 'cubic-bezier(0.2, 0, 0, 1)' ``` Transitions are quick and mechanical. Nothing bounces, nothing overshoots, nothing lingers. State changes should feel like a light switch, not a door closing. - Interactive feedback (hover, press, toggle): {motion.feedback}, always {motion.easing}. - Content transitions (page, panel, modal): {motion.content}, same curve. - Nothing in the UI animates longer than 300ms. If something takes longer, cut it. - Respect `prefers-reduced-motion`: all durations collapse to 0ms.

这个示例完美体现了全部哲学:motion不是规范预定义的键(规范只定义了 colors/typography/spacing/rounded/components 五个令牌组),但格式允许它存在;{motion.feedback}引用语法与规范内令牌完全一致;而叙述部分——"像电灯开关,而不是关门"、"任何动画超过 300ms 就砍掉"、"尊重prefers-reduced-motion"——才是这份设计真正有灵魂的地方。

源码证据:扩展如何被 linter 优雅地接受

"格式接受任何键"不是一句空话,仓库的 lint 规则实现给出了两条精妙的佐证:

1. 自定义键保持静默。packages/cli/src/linter/linter/rules/unknown-key.ts 中的unknown-key规则只对"长得像已知键拼写错误"的顶层键发出警告:它用莱文斯坦编辑距离(levenshtein,见 packages/cli/src/linter/linter/rules/levenshtein.ts)把未知键与colors/typography/spacing/rounded/components等 schema 键做相似度比对,距离阈值MAX_TYPO_DISTANCE = 2——colours:会被提示"是不是想写colors:?",而motion:iconography:这类真正的自定义扩展键不会被误报。这正是"格式生长于用户"在代码层的落地:有意的扩展零打扰,无意的拼写错误被温柔捕获。

2. 令牌样值兜底提醒。packages/cli/src/linter/linter/rules/token-like-ignored.ts 中的token-like-ignored规则更进一步:如果某个未知顶层键的值看起来像令牌映射(含 Hex 颜色、CSS 尺寸等"令牌样"叶子值),而它又不属于受支持的导出 schema,就警告它"会被export命令静默忽略",建议改名或移入受支持的区块——例如base_colors: { light: { ink: "#0B0F14" } }这种值会被识别出来。两条规则合在一起的效果是:格式开放,但不糊涂。

此外,packages/cli/src/linter/spec-config.ts 中定义了两个与"开放性"配套的保护性限制:MAX_TOKEN_NESTING_DEPTH = 20(令牌最大嵌套深度)与MAX_REFERENCE_DEPTH = 10(引用最大解析深度),防止恶意或病态结构导致解析器栈溢出——开放不等于无防护。

"Tokens are context" 在规范层的确证

回到 docs/spec.md 的 "Consumer Behavior for Unknown Content" 一节,可以看到 linter 与解析器对未知内容的既定态度:

场景行为
未知小节标题(如## Iconography保留,不报错
未知颜色令牌名(值合法即可)接受
未知排印令牌名作为合法排印接受
未知间距值接受;若非合法尺寸则以字符串存储
未知组件属性(如borderColor接受但给出警告
重复小节标题报错,拒绝该文件

这张表是对"格式通过用户生长"的最直接背书:除"重复小节"这一结构性错误外,其余一切未知内容都以"保留 + 接受"的方式温和对待。而整套 11 条 lint 规则的完整清单与各自严重级别,记录在 packages/cli/src/linter/linter/rules/index.ts(DEFAULT_RULE_DESCRIPTORS)与 README.md 的 Linting Rules 一节中——从broken-ref(断引用,error)到omitted-rulesomitted配置校验,info),每一条规则的职责边界都被明确固定。

给 Agent 与写作实践者的可操作结论

综合原文档的哲学论述与仓库的工程实现,可以提炼出四条落地准则:

  1. 先写叙述,再补令牌。用一句具体参照锚定整个设计("像 1970 年代老牌大学的讲义"),然后用{tokens}引用把精确值挂到叙述上;参照越具体,负面约束越免费。
  2. 形容词只描述区域,参照物才描述点。"现代、干净、可信"必然产出平庸的中间值;"像一份印刷的学术讲义"才能把设计推向精确的位置。
  3. 用有意的 Do's and Don'ts 收尾,而不是流水账。正面参照负责定调,负面清单负责守住边界,二者配合才是"sweet spot";如果禁令列表长得失控,优先回头打磨正面描述。
  4. 放心扩展格式,但不制造困惑。motioniconographyelevation等自定义键完全合法,linter 会静默接受;唯一要注意的是别把自定义键拼写成近似内置键(会触发unknown-key警告),也别让令牌样值的自定义键被export静默丢弃(token-like-ignored会提醒你)。

最终回到原文档的收尾语:"这份文档传达的是 DESIGN.md 的叙事与哲学,以厘清它解决什么问题、以及目前如何尝试解决这些问题。"这份哲学不是理论空谈——它被完整地编码进了规范(docs/spec.md)、规范配置(packages/cli/src/linter/spec-config.yaml)、lint 规则实现与三个实战示例(examples/atmospheric-glass/DESIGN.md、examples/paws-and-paths/DESIGN.md、examples/totality-festival/DESIGN.md)之中。理解这套哲学,你就理解了为什么一份 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

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询