构建设计系统
词汇表位于 references/glossary.md,禁用规则和宽度默认值位于 references/taste.md。应用的外观是源头。不发明应用尚未拥有的颜色、字体、阴影、渐变或动效值,除非人员选择了设计来源并确认了样本。
脚本位于此技能的 scripts/ 目录。从仓库根目录使用 Node 运行,并先阅读 --help。scripts/capture.mjs 负责截图,该命令由 scripts/capture-guard.mjs 保护(它会阻止所有写入操作),scripts/pixdiff.mjs 用于比较截图。capture 和 pixdiff 需要 Playwright 和 Chromium,scripts/find-chromium.mjs 可以找到或说明如何安装它们。
步骤
-
框架搭建。 阅读 AGENTS.md 或 CLAUDE.md、清单和路由树。用人员自己的话写下其诉求、满足诉求的第一个可见变更,以及试点流程(诉求中命名的流程,否则选择包含最多组件族且包含具有错误状态的表单的流程)。将
.design-system/添加到.git/info/exclude,确保不会提交任何笔记、截图中或临时文件。使用人员命名的分支作为运行分支,或者新建一个分支并将启动时的分支名写入.design-system/start-branch(land.mjs会拒绝执行)。提供一次references/taste.md(禁用选项未选中),并将接受后的副本保存到.design-system/taste.md。不要问其他问题。如果人员未回答则采用默认值,记录为default (unanswered)并继续。 当诉求、试点流程、分支和已接受的 taste 文件记录完毕后,此步骤完成。 -
清单与基线。 列出每个界面、其状态以及是否写入数据。使用
scripts/check-system.mjs --no-allowlist --no-self-test --json统计原始值的出现次数(#fff、text-gray-500、p-[13px]),并将组件分组为组件族。在支持的最窄和最宽宽度(默认 390 和 1280)下,每种状态每个界面截图,每个宽度一次全新导航,在编辑之前完成。在应用运行时(此处端口 3000),将每个界面作为surface<TAB>route<TAB>states行写入.design-system/surfaces.tsv,并将应用发送的每个写入操作作为METHOD URL写入.design-system/writes.txt(从网络日志复制),然后运行node <此技能>/scripts/capture.mjs --base http://localhost:3000 --kind before --out .design-system/captures --surfaces .design-system/surfaces.tsv --writes .design-system/writes.txt。如果未提供--writes(或者对于不发送写入操作的应用,提供--no-backend),它会拒绝启动;在浏览器打开之前,它证明每个写操作已被阻止;保存每个截图的辅助功能树;如果任何截图缺失则退出 1。删除未使用的任何内容,并将其作为单独的提交。 当每个界面都有基线或已说明的not captured原因后,此步骤完成。 -
Token。 根据作用对原始值进行聚类,按目的命名 Token,并将每个界面与其前景色配对(
references/tokens.md)。运行token-mapping,直到每个原始值映射到一个角色、一个合并项或一个列出的例外。容差范围内的合并是决策。超出容差,每类打开一个门,其默认值为合并项。在所有路由上执行每个相同值的替换。 当token-mapping报告在例外列表外零差距,并且pixdiff.mjs在容差为 0 时报告受替换影响的每个界面差异为 0% 后,此步骤完成。 -
组件。 首先端到端构建使用最多的组件族(
references/components.md)。文本基元和文本小基元与 Button 一同在第一波中发布。使用component-docs为每个组件编写文档。在扩散之前向人员展示该组件族,因为在界面消费系统后发现的核心缺陷需要返工(例如,禁用的字段仍显示为红色、Combobox 比 Input 高 2 像素、面板操作未换行、文件拖放静默失败)。 当每个规范组件都有注册行和文档,并且其禁用、必填、错误和长文本状态在展示界面中截图并展示给人员后,此步骤完成。 -
检查。 将
scripts/check-system.mjs和scripts/oklch.mjs复制到仓库的scripts/目录,运行--init,然后运行--init-allowlist一次。一个规则只有在看到它失败时才会计数:在被扫描的文件夹中植入一个违规,运行--files <plant> --no-allowlist,看到命名该规则的退出码 1,然后删除该植入。Allowlist 和 ratchet 仅缩小。禁止规则与其检查规则在同一变更中发布。复制规则随其豁免项一起发布,范围为元素级,适用于必须保持原样的文本(引语、术语、版本字符串)以及机器或人员粘贴到其他位置的负载字符串(提示词、API 示例、剪贴板值),因为改写它们会改变其他人收到的内容。 当在干净克隆上检查退出码为 0,--self-test以 "all as expected" 结束,并且添加的每个规则在本会话中其植入上曾见到失败后,此步骤完成。 -
试点。 使用逐段读取的 codemod 迁移试点流程。使用与基线相同的命令、宽度、主题和数据截图,仅将
--kind改为after,然后使用pixdiff.mjs比较两个文件夹。未说明的差异被视为缺陷。用键盘遍历流程,强制其错误和加载状态,然后在 after 截图上运行ui-review。 当截图中的每个差异都可追溯到决策或门后,此步骤完成。渲染更改但无截图的情况报告为checks-only。 -
就绪性。 在迁移扩散之前,以下五项审计必须全部通过或持有已记录的豁免。
-
移交。 重新运行计数。用数字报告系统覆盖的内容,首先列出未回答的默认值,然后列出发现了但未修复的问题,按优先级排序。提供迁移及其规模。不要开始迁移。 当报告中的每个数字都指明了产生它的命令后,此步骤完成。
就绪审计
在界面已消费系统后发现缺陷需要返工。在发现缺陷之前发现则只需一行记录。在步骤 5 结束时和首次发布前运行这些审计。将每个结果写入 .design-system/readiness.md,并附上结论词。
- 插槽和属性一致性。 每个具有调用站点的遗留基元的每个属性在新基元上都有匹配的属性或一个差距行。
- 行为合约。 每个交互式基元的“触发什么”表格,每行一个测试(
references/components.md)。 - 色调一致性。 每个可按压基元和行基元与每个状态色调加上 muted 的交叉。每个空单元格是差距行或声明为不支持。
- 固定字符串。 每个按角色名称或文本进行的遗留测试查询在新基元上都有一个默认名称和一个标签覆盖。
- 最难渲染的界面。 每个组件族的一个最难调用站点在展示界面中渲染,并附带截图。
未就绪的组件族不会被迁移。其界面仍使用遗留组件。
切勿
- 推送、发布或部署,除非人员在本会话中要求。
- 在运行开始时所在的分支上提交。先创建运行分支。
- 在脏工作区中暂存或切换分支。脏工作区将运行分支放置在单独的工作树中(
git worktree add)。 - 删除其他包或公共 API 导出的任何内容。停止,并将其列为带有导入者的门。
- 静默跳过步骤。如果应用无法构建或运行,报告应说明
code-complete, not runtime-verified并指明未测试的内容。 - 称自己的工作为
verified。在无法启动其他代理的主机上,按顺序运行步骤,通过重新读取 diff 和截图中来检查每个步骤,并将这些结论标记为self-verified。
规则
- 原始值的可疑项包括
#fff、rgb(、text-gray-500、p-[13px]和style={{ padding: 12 }}。每个应映射到语义 Token 或列出的例外。 - 缺失的基元是一个差距行,绝不能是界面内的临时解决方案。
- 在 delta E OK 2 内的颜色合并和在 2px 内的间距合并是决策。边框宽度、字重和缓动没有容差。
- 仅添加语义(名称、角色、
aria-current)的变更是决策。删除或重组语义的变更是门。 - 错误:
{saving ? "Saving..." : "Save"}。正确:空闲标签保持不变,旋转器位于同一框内,设置aria-busy。 - 重复出现的修复应变成检查规则或脚本,而不是另一句话。
- 绝不能修改基线以使差异通过。标记正确代码的检查应在检查中修复,并带有证明修复的植入用例,绝不能通过修改代码来绕过。
- 没有脚本产生的计数,或从未见到失败的检查,不予报告。
完成
在干净克隆上检查退出码为 0(每个规则都曾见过失败),每条路由在生产构建上返回 200(capture.mjs --status),试点流程与其基线匹配(除列出的预期更改外),并且每个移交计数均来自脚本。
references/traps.md 按 ID 列出了行为陷阱。references/tokens.md 包含层级、名称、容差和动效预设。