ui-design-system-builder
当使用者说"帮我做个界面"、"这个页面太丑"、"看着像模板/像 AI 做的"、"给这个项目定个视觉风格"、"配色和字体你来定"、"把这几个页面统一一下"时使用。先从项目本身抠出一个具体意象,据此定出一版完整的 CSS 变量与排版尺度(不是"现代简洁"这种废话),再用这些 token 拼组件;每个非显然的取舍都在代码注释里写清理由、代价和怎么改回去。中文界面必须同时配 CJK 字体。不装 UI 框架
SKILL.mdskills/coding-helper/ui-design-system-builder/SKILL.md
GitHub定一套界面的视觉语言 / UI Design System Builder
给一个项目定出它自己的视觉语言:一版 token、一套排版尺度、几个用 token 拼出来的组件。
界面之所以像模板,不是因为审美差,是因为每个决定都取了默认值 ——
默认的 Inter、默认的 8px 圆角、默认的 0 4px 12px rgba(0,0,0,.1)。
这个技能要求每个决定能说出为什么是这个项目该用的。
何时使用 / When to use
- 项目要起前端,还没定视觉
- 已有界面能用但"像模板 / 像 AI 随手做的"
- 几个页面各写各的样式,想统一
- 要换字体、换配色、加暗色模式这类会波及全站的改动
不适用于 / Not for:
- 只改一个按钮的边距 —— 直接改,别起一套系统
- 已经有设计稿或设计规范 —— 那是照着实现,不是重新定
- 想直接套用 MaestrWave 那套现成的深色衬线视觉 —— 用
maestrwave-ui-system, 那边有可粘贴的global.css与组件层,不用从头推 - 组件库选型、状态管理、性能优化 —— 那是别的问题
一条主线:意象 → token → 组件
倒过来做就会失败。先挑组件、边写边配色,最后拼出来的一定是一堆互不相干的局部最优。
1. 从项目里抠一个具体意象
读 README 的项目定位和领域名词,只读这些,找一个能画出来的意象。
| 弱 | 强 |
|---|---|
| 现代、简洁、专业 | 月光下的水面(音频波形应用) |
| 科技感 | 老式示波器的荧光余晖 |
| 温暖友好 | 图书馆闭馆前那盏台灯 |
判据:这个意象能直接推出颜色和材质。"简洁"推不出任何具体值,"月光下的水面"能推出 暖炭黑基底 + 浅水蓝主色 + 低透明度的叠层波浪。
抠不出来就问一句,别自己编一个宏大的概念糊上去。
2. 直接写出一版完整 token
不要贴调色板让人挑。写出一份能直接粘进 global.css 的 :root,
包含背景层级、主色、状态色、文字色、描边色、字体栈,每一支都在注释里写为什么。
:root {
--bg: #15130f; /* 暖炭黑,不用纯黑:纯黑上任何颜色都发脏 */
--surface: #211c15;
--surface-2: #2c2519; /* 层级靠明度递增,不靠阴影 —— 深色界面里阴影几乎看不见 */
--accent: #7cb2e8; /* 浅水蓝,呼应波形主题 */
--wine: #b8453a; /* 状态色(录制/危险),和蓝形成一冷一暖 */
--ink: #f3eddd; /* 暖白,不用 #fff:和暖底搭配才不割裂 */
--line: rgba(243, 237, 221, 0.1);
}
要点:
- 层级用明度台阶(surface / surface-2 / surface-3),深色界面里阴影不出力
- 文字层级用
color-mix(in srgb, var(--ink) 55%, transparent),不另起一堆灰色 token - 状态色只留一支够用了,第二支状态色多半是没想清楚
- token 是唯一真相。canvas / SVG 也要读 token(
getComputedStyle取回来), 不然换主题时这些地方会被漏掉
3. 定尺度对比,而不是定一堆字号
一套排版系统的性格来自极端之间的落差,不是来自中间有多少档。
display-1 clamp(40px, 6vw, 64px) weight 600 line-height 0.98 letter-spacing -0.02em
display-2 clamp(24px, 3vw, 32px)
body 14px line-height 1.5
eyebrow 11px letter-spacing 0.14em uppercase 用主色
label 12px 透明度 55%
巨大的标题配 11px 的全大写小标签,这个对比本身就是设计。中间再加三档只会把它磨平。
把这套固化成一个 PageHeader 组件(eyebrow + 大标题 + 小号元信息),
每页都用它,不允许各页自己写标题样式。
4. 组件从 token 拼,样式分两层
- 跨页复用的排版类(
.display-1.eyebrow.label.mono-chip.field-label) →styles/global.css,全局可用 - 只属于某个页面/组件的布局 → 同目录的
X.module.css
判据很简单:第二个地方要用到了,就往 global 提。在页面里第二次复制粘贴同一段 标签样式时,就是该提的时候。
层级要换手法,不要同一手法调强度:一级导航用「描边 + 微亮底」,二级用「实心高亮」。 两级都用实心块的话,视线分不出主次,加大色差也救不回来。
5. 可用性底线,写完对一遍
@media (prefers-reduced-motion: reduce)全局把动效降到 0.001ms- 装饰层
aria-hidden="true"+pointer-events: none - 焦点统一:
border-color: var(--accent)+ 3px 的半透明 ring,不要outline: none了事 :disabled用opacity: 0.4+cursor: not-allowed- 数字(时间码、计数、图表刻度)加
font-variant-numeric: tabular-nums,否则会跳 - 动效只用来表达状态:加载中的呼吸、按下的
scale(0.98)。纯装饰的动画一律不加
6. 每个非显然的取舍留一段注释
这一步是这套方法真正省时间的地方。注释写三件事:为什么这么选、代价是什么、想改回去改哪一行。
/*
--font-mono 现在也是衬线体(按「UI 全部改 Serif」的要求)。代价是数字不再等宽,
图表刻度、时间码这些地方会参差 —— DOM 里靠 font-variant-numeric: tabular-nums
补救,canvas 里补救不了。
觉得不合适时把这一行改回 "IBM Plex Mono", ui-monospace, monospace 即可,
其余代码全都引用 token,不用动。
*/
半年后回来看,没有这段注释就只能重新试一遍。
反默认自查 / Anti-default check
写完对一遍。命中任何一条,说明那里取的是默认值,重挑:
- 配色是纯黑 + 荧光绿 / 暖白 + 赤陶 / 紫蓝渐变
- 字体是 Inter(或系统默认)配一个没指定的等宽
- 全站一个圆角值
- 阴影是
0 4px 12px rgba(0,0,0,0.1) - 主色是
#3b82f6或它的近邻 - 说不出任何一支颜色为什么是这个值
中文界面的字体 / CJK typography
界面以中文为主时,只换拉丁字体等于没换 —— 中文会掉到系统默认(macOS 上是黑体系), 一衬线一无衬线,界面立刻割裂。
- 拉丁与 CJK 成对引入,字体栈里 CJK 排在拉丁之后(浏览器按字形覆盖逐字回退)
- CJK 字重只引实际用到的两档。
@fontsource的中文包按 unicode-range 切成上百个分片, 每多一档,产物 CSS 就多几十 KB —— 而 CSS 阻塞渲染。中间档(500)交给浏览器回退到 400, 中文场合看不出差别 - 中文没有小型大写和真正的斜体,
text-transform: uppercase那套只对拉丁标签有效
输出格式 / Output
一次给完,别分三轮问:
**视觉主张**:<一句话,含那个具体意象>
**Token**(粘进 `styles/global.css` 的 `:root`)
```css
<完整的一版,每支带注释>
```
**排版尺度**
<表格:类名 / 字号 / 字重 / 字距 / 用在哪>
**示范组件**:<挑一个最能体现这套语言的,给完整代码>
**我替你定了的**
- <取舍 1 + 代价 + 怎么改回去>
- <取舍 2>
边界 / Boundaries
- 不装 UI 框架来跳过这一步。除非使用者明确要求,不要为了"快"引入 Tailwind / MUI / shadcn —— 那等于把视觉决定交给框架默认值,正好是这个技能要解决的问题。
- 不改业务逻辑。只动样式、类名和纯展示组件;发现逻辑问题就说出来,别顺手改。
- 不为了好看牺牲可读性。正文对比度不足、点击区小于 40px、焦点态看不见, 这些没有商量余地。
- 不编造品牌资产。项目已有 logo、图标或既定色时,围着它们定,不要另起一套。
- 不一次改完全站。先在一个页面上把这套语言坐实,跑起来看过,再铺开。
- 不写"现代、简洁、优雅"这类词当作设计说明 —— 说不出具体值就是还没想清楚。
Token 控制 / Token discipline
- 第一步只读 README 的项目定位段 + 现有
global.css+ 一个代表性页面, 不通读全部组件。视觉语言是从项目定位推出来的,不是从组件清单里归纳出来的。 - 需要 MaestrWave 的完整实例(token 表、层级手法、注释样例)时再读
references/maestrwave-example.md,别默认加载。 - 改定后只贴改动的那几行,不重贴整份 CSS。
变更记录 / Changelog
| 版本 | 日期 | 变更 | 类型 |
|---|---|---|---|
| 0.1.1 | 2026-09-26 | 参考实例里 .field-label 的 ink 比例随 maestrwave-ui-system 由 48% 改为 52%(48% 在 11px 时对比度不到 AA 4.5:1),两边保持逐项一致 |
patch |
| 0.1.0 | 2026-08-10 | 初始草稿,方法总结自 MaestrWave 前端 | minor |