uxskill
Star on GitHub
Language
English 简体中文 繁體中文 日本語 한국어 हिन्दी Bahasa Indonesia Tiếng Việt ไทย العربية Español Français Deutsch Português Русский Türkçe Italiano
Launch · v3.0.0 · 2026-05-28

# ux-skill v3.0 · 我们发布了 The Brain。品牌规范现在是训练数据,不是模板。

v2 从目录里挑,v3 从目录里蒸馏。同样的 160 份品牌规范,角色完全不同。原来的推荐器会对 1,243 条目录打分,返回最匹配的那一条。新的合成器把这些条目当作词汇来读,从一份 brief 编译出一种崭新的设计语言。每次调用,返回的都是那次调用之前不曾存在过的系统。

ux-skill 团队 · 12 分钟阅读 · MIT 开源许可

EN JA ZH-CN AR ES DE
品牌规范是训练数据,
不是模板。

## 用一段话讲清这次转向

v2 是一个推荐器。你给它一份 brief,它从精心整理的目录里,84 种风格、176 套调色板、160 份品牌规范、70 组字体搭配,返回最相近的一条。输出永远是数据库里的某一行。v3 保留了整份目录,但把它的角色翻转了:这 1,243 条条目现在是引擎用来蒸馏的词汇。一份 brief 不再是去命中一行,而是被编译成 7 个轴的数值,这些数值再合成出全新的 token。目录教会引擎"通透 + 企业"是什么形状;引擎据此生成一个全新的、未曾出现过的"通透 + 企业"系统。同样的数据,完全不同的角色。

## v2 里坏掉的、v3 修好的东西

三个真实的 bug,加上一个设计上的空洞。bug 不是那种喧哗的,而是安静的那种,引擎一直在返回看起来合理的输出,我们也一直在发布。直到坐下来写升级说明、被一次外部 review 逼着诚实地看一眼,我们才意识到。

### 1. 靠文件系统顺序的"伪"决定论

推荐器流水线里有几处排序,会按相似度给候选打分,用 Python 的 `os.listdir` 返回顺序来打破并列。macOS 上是字母序,Linux 上是文件系统日志里的插入顺序。新克隆和老克隆,打平后的结果就可能反过来。我们一直说引擎是确定性的。它在分数不打平的范围内确实是确定性的,一旦打平,就变成"操作系统恰好记得的那个顺序"。

v3 给每一次排序都加上了明确的并列处理,按品牌 id 的字母序。同一份 brief、同一组轴、同一份输出,跨机器、跨文件系统、跨 Python 版本都相同。有一个测试会在三个临时目录里把合成器跑 200 次,断言输出按字节完全一致。

### 2. 轴的冲突全靠"碰巧"解决

在 v2 中,如果 brief 同时含有两个相反方向的标签,比如 dense 和 corporate,推荐器的打分会被某个隐藏系数偏向其中一边,输出就会朝那一边倾斜。没有文档化的规则。事后能解释结果,事前没法预测。

v3 把这件事抬到了一个轴的相互作用矩阵里。每一处文档化的冲突都有明示的解决方式和理由。密度和正式度争抢 spacing,密集型 brief 让密度赢(彭博风),通透型 brief 让正式度赢(奢华风)。这套矩阵有测试,可读,提交在仓库里。

### 3. 评估器在批改合成器自己的作业

这一个最难为情。能发现还是因为 ChatGPT 在 v2.1 规范的外部 review 里指出来的,他们叫它自我参照漂移 (self-referential drift)。流程看上去很干净:合成器从 brief 编译出一套系统,然后 `score_tone_match` 评估这个系统和 brief 的语气是不是一致。问题在于,`score_tone_match` 用的是和合成器一模一样的逻辑,从 brief 推出一组轴,再把合成器的轴和自己推出的轴比对。比较的两边都过同一个函数。当然分数会很高。合成器是用自己的评分标准在批改自己。

v3 把两边解耦了。`score_tone_match` 现在通过一条独立的、绝不会碰到合成器轴逻辑的映射,直接把合成结果和 brief 的原始语气标签,`warm`、`bold`、`minimal` 这些字符串,做对比。两条路径再也抄不到对方了。这一观察归功于外部 review,我们在此公开承认。

### 4. 决策日志只写、从不读

v2 在每次 recommend 之后会向 `.ux/decisions.jsonl` 追加一行,但没有任何东西会再把它读回来。它只是我们自己调试用的日志,并不是反馈信号。推荐器第 1 次调用和第 1,000 次调用行为完全一样。没有学习,仓库有记忆,引擎选择忽略。

v3 把这个回路闭合了。账本有锁定的 schema (`_v: 1`),推荐器按同一个 `(industry, ui_type)` 桶里的过往胜者给候选重排,只有分数够高 + 用户真的发布了的决策才算进重排。脑终于长了眼睛看自己的历史。第 6 节是完整说明。

## 七轴合成器

v3 的中心是一个决定性函数,它把一份 brief 映射到 7 个数值轴,再把这 7 个轴映射到一套完整的设计系统。轴没什么神秘,每个都是一个有文档化值域的标准化标量,指向一组特定的 token。在轴上跑(而不是从目录里挑一行)的意义在于:空间里任何组合都可以触达,包括目录里实际品牌从未用过的组合。目录定义空间的形状,合成器可以落到其中任何位置。

轴 | 衡量什么 | 映射到
--- | --- | ---
warmth | 调色板的色温:从冷调炭黑到暖调赭色 | 调色板色相族,强调色饱和度曲线
contrast | 视觉响度:quiet / balanced / loud | 排版比例 (1.200 / 1.250 / 1.333)、阴影深度、强调色强度
density | 单屏信息密度:airy 到 dense | spacing 基数 (4/8/12/16px)、行高倍率
geometry | 边缘人格:sharp / balanced / soft | radius 尺度 (2/8/18px)、转角拓扑、描边粗细
formality | 语气定位:playful / balanced / corporate | 字重曲线、字距、从 caption 到 hero 的跨度
motion | 动效预算:restrained / balanced / cinematic | 持续时间梯度 (120/240/420ms)、缓动家族、滚动行为
type_personality | 字体的声音:humanist / neutral / geometric / expressive | display 字体家族、字重梯度、斜体策略

Python 的入口足够小,能塞进一个示例里。传一份 brief,得到一个合成系统,里面挂着轴的数值、选好的调色板、字体设置、spacing 尺度、radius 尺度、动效预设。

    # 从一份 brief 到一个系统,一次调用
    from engine.synthesizer import synthesize

    brief = Brief(
      industry="fintech-payments",
      tone=["bold", "serious"],
      audience=["merchants", "developers"],
    )

    sys = synthesize(brief)
    # sys.mode == "pure_synthesis"
    # sys.axes == {warmth: 0.32, contrast: 0.72, density: 0.58, ...}
    # sys.palette, sys.type, sys.spacing, sys.radius, sys.motion

同样的 brief 进来,同样的轴出来,同样的 token 出来。永远如此。合成器没有随机种子,因为没有可种的随机。

## 三种模式,一套判定逻辑

合成器根据 brief 自动路由到三种模式之一。大多数用法都不需要手动选模式,brief 的形状自己决定。逻辑刻意简单:是否指定了参考品牌、是否打了 strict 标志,这两件事就决定了路径。

strict_brand · 最快

#### 100% 指定品牌

`reference_brands=[stripe]` 加 `strict=True`,直接返回 Stripe 规范的原样。不解读、不混合、不合成。适合品牌已存在、规范有权威、brief 只想要 token 的场景。当你手上有一份 Figma 文件和一套写好的系统、需要不即兴的代码时,走这条路。

brand_anchor · 70 / 30

#### 以品牌为锚,按 brief 的轴做调适

`reference_brands=[stripe]` 但不带 `strict=True`,返回 70% 的 Stripe token 与按轴距挑选出的 4 个姐妹品牌 30% 的轴差融合。输出仍然一眼就是 Stripe,只是朝 brief 的语气微微弯曲,给消费者功能时是更俏皮一点的 Stripe,给企业级仪表盘时是更正式一点的 Stripe。锚定品牌在所有冲突里都胜出。

pure_synthesis · 无穷空间

#### 未指定品牌,每次调用都是新的语言

brief 里没有 `reference_brands` 时,合成器从 brief 给 7 个轴打分,在目录里按轴距找到 8 个最近的范例,蒸馏它们共有的结构,产出全新的 palette + type + spacing + radius + motion 一整套。不同 brief 落在同一空间的不同区域,每个输出都内部自洽、且具有可识别的自我。

从 CLI 看,三条路径是这样的:

    # strict: 100% 指定品牌
    $ uxskill synthesize --brand stripe --strict

    # anchor: 70/30
    $ uxskill synthesize --brand stripe

    # pure synthesis: 无品牌
    $ uxskill synthesize --industry fintech-payments --tone bold

一个合成器,一套判定逻辑,三种输出人格。用户不切换实现,brief 自己挑路径。

## 轴的相互作用矩阵

轴会争抢同一批 token。density 想要紧凑的 spacing,formality 在奢华语境里想要更宽裕的 spacing。geometry 为编辑感想要锐利的转角,formality 在金融仪表盘里想要柔和的转角。在 v2 里,谁的系数恰好更大谁就赢。在 v3 里,每一个文档化的冲突都有声明的结果,以及它指向的设计流派,名字都列出来了,你读了之后想反对完全可以。

四个典型案例,都作为测试 fixture 提交了:

dense + corporate
spacing 基数:4px

密度赢。彭博学派的答案。当 brief 要求在企业语境里塞密集的数据仪表盘,信息密度就是最高的美德,正式度在"密度下的可读性"面前让位。

airy + corporate
spacing 基数:12px

正式度赢。奢华金融的答案。airy + corporate 是给高净值银行、私人财富、高管仪表盘的 brief,元素之间的空气,本身就是"严肃"的信号。

sharp + corporate
radius 尺度:2px

几何赢。NYT 学派的答案。sharp + corporate 是编辑型 brief,直角加上 2px 的微小 radius,读起来是机构感、深思熟虑、对开报纸式的语气。

soft + playful
radius 尺度:18px

两个轴方向一致。Glossier 学派的答案。柔和几何加俏皮语气会收敛到宽裕的圆角,18px 是矩形开始读作"鹅卵石"的阈值。

为什么这件事要紧:v2 里,同一份 brief 这个月可能落 4px,下个月可能落 12px,看打分时哪个系数赢。v3 里,`dense + corporate` 永远是 4px,`airy + corporate` 永远是 12px。规则可读、可测、可争论。如果你不认同某个结论,可以对矩阵开 issue,讨论的是品味,而不是某个藏起来的常量。

## 脑会学习

这才是这次发布对项目而言真正新的部分:引擎会从你本地的决策里学习。机制小、确定、完全离线。没有遥测、没有账号、不会上云。你的安装从你的安装里学。不同的仓库会长出不同的脑。

### 账本

每一次 `/ux-recommend` 和 `/ux-synthesize` 调用,都会向 `.ux/decisions.jsonl` 写入一行。schema 锁定为 `_v: 1`:

    {
      "_v": 1,
      "ts": "2026-05-28T14:22:09Z",
      "frame": { "industry": "fintech-payments", "ui_type": "dashboard", ... },
      "system": { "style_id": "editorial-calm-dark", "palette_id": "charcoal-amber", ... },
      "axes": { "warmth": 0.31, "contrast": 0.72, ... },
      "lint_score": 88,
      "user_accepted": true
    }

### 重排

下一次调用时,推荐器会按 `(industry, ui_type)` 给历史记录分组。每个候选只要命中同桶里的一条先验,就拿到 +5 的加成。只有 `lint_score >= 80` 且 `user_accepted = true` 的先验才会被计算,被拒绝的输出不会进入学习。在任何重排发生之前,同一桶里至少需要 3 条合格先验,否则引擎按冷启动跑,行为和全新安装完全一致。

### 承诺

这里能给出的承诺很窄、值得说清楚。确定性保留。同一份 brief + 同一份账本永远产生同一份输出。+5 加成在任何 tie-break 之前应用,品牌 id 字母序的规则仍在下层把所有打平拆开。冷启动安全。新仓库的行为与其他所有新仓库相同。学习是本地的。你的决策从不离开你的机器。

你随时可以查看自己的安装学到了什么:

    $ uxskill stats --html
    [OK] Wrote .ux/stats.html
    [OK] Open in browser to see your install's learned priors

这份 HTML 面板会显示每个桶下的决策数量、平均 lint 分、最常出现的调色板、轴的分布。这就是自我学习的可见证据,随着你不断发布,你的安装的"品味轮廓"会随时间变得更浓。没有任何东西在服务器上。一切都在你的仓库里:明文 JSONL 和生成的 HTML 视图。

## /ux-evolve 自动循环

v3 的新命令是 `/ux-evolve`。直到现在,打磨循环都是手动的:跑 lint、读结果、修、再 lint。Evolve 把这个循环关掉了。你把一份产物和一个目标分给它,它会跑 lint、应用 6 个幂等的打磨 pass、再 lint,要么停在目标、要么停在 plateau、要么停在 5 轮上限。

一轮的结构:

1. Lint:跨 A11y、内容、质量、排版的 145 条确定性正则规则。返回一个 0-100 的分数和一份 finding 列表。
2. Polish:6 个 pass,优先修复高严重度 finding。幂等:对已经打磨过的产物再跑一遍是 no-op。
3. Re-lint:给打磨后的产物重新打分。
4. Decide:新分数 ≥ 90,停;距上一轮的 delta 小于 5(plateau),停;到第 5 轮,停;否则继续循环。

质量门禁硬卡在 65。最终分数低于 65,引擎拒绝发布,除非传入 `--force`。理由是:65 以下的输出已经是能被识别出来的 AI slop,我们不允许自己的引擎安静地输出 slop。用户可以覆盖,但覆盖是显式的,并且会写进决策账本。

一个具体例子:一份金融科技仪表盘脚手架第一次 lint 拿了 72 分,大部分是焦点状态缺失、几个低对比度标签、一个"用 Inter 做 display"的 finding。第 1 轮把焦点状态打磨到 81 分,第 2 轮把对比度修到 86 分,第 3 轮把 Inter 换成 brief 实际指定的 display 字体并重新平衡 caption 尺寸,91 分,目标到达,循环结束。三轮,无拒绝,发布。

## 我们没有做的事(以及原因)

v2.1 极端化版本的规范里,有几样东西没进 v3。诚实地说出哪些没做、为什么没做,是讨论 scope 唯一靠谱的方式。

### 不让 LLM 进入回路

极端化方案里有一个由 LLM 判定的"主观美学轴","问问模型这是不是编辑风"。我们出于原则拒绝了。引擎的全部要点就是确定性:同一份 brief、同一份输出、明天早上不会有惊喜。一旦 LLM 进入合成器,每次调用都不可复现。v3 调用 LLM 零次。合成器是纯 Python 走 JSON,linter 是正则,评估器是规则驱动。

### 不做多候选遗传变异

方案里还有一个遗传算法步骤,每次调用产出 N 个候选,变异、打分、返回最优。我们在分支里试过,输出反而更差了,因为变异引入了噪声,打磨循环还要再清掉。v3 选择单候选合成 + 打磨循环。一个候选,六个幂等 pass。结果更好,代码面更小。

### 不改命令名

方案里把 `/ux-recommend` 改成 `/generate:ui`,把 `/ux-polish` 改成 `/mutate:ui`。我们保留了已有的全部 22 条命令的原名,把 `/ux-evolve` 作为第 23 条加进来。我们不希望一次从 v2 到 v3 的升级,把任何人的肌肉记忆或 shell alias 弄坏。

### 不"为了无穷空间烧掉目录"

最极端的版本认为目录是负担,合成器能独立到达整个设计空间,1,243 条条目应该删掉。我们把每一条都留下了。目录是教会合成器空间形状的东西,没有样本,轴就没有锚,输出就开始漂。v3 把目录当词汇来读,v3 需要这套词汇。

这些是品味判断,优先级不同的人会反对,没问题。把我们没做的事、为什么没做记录下来,这是我们对项目的本分。

## v3 时的数字

23
Commands
18
MCP tools
1,243
Entries
145
Anti-patterns
160
Brand specs
17
IDEs
17
Locales
223
Tests pass

22 条已有的斜杠命令名字保持不动,新增的第 23 条是 `/ux-evolve`。15 个 MCP 工具保持不动,新增三个,`ux_synthesize`、`ux_decisions_query`、`ux_decisions_stats`,给想驱动合成器、或想查询脑学到了什么的 agent 使用。目录和 linter 不动。17 个 IDE 的安装器不动。17 份本地化首页和 README 也不变。v3 在表层是加法,在内核是改写。

> v2 是从目录里挑的推荐器。v3 是从目录里蒸馏的编译器。同样的数据,在做相反的工作。

## 60 秒安装

v3 走和 v2 一样的三条发布路径,pip、npm、IDE 插件市场。init 步骤会自动检测你的 IDE,把正确的配置文件写到正确的位置。synthesize 步骤接受一份 brief 或一组 industry + tone,产出一套完整的设计系统到当前仓库的 `.ux/last-system.json`。

    $ pip install uxskill
    $ uxskill init                     # 自动检测你的 IDE
    $ uxskill synthesize --industry fintech-payments --tone bold

    [OK] Mode: pure_synthesis
    [OK] Axes: warmth=0.31, contrast=0.74, density=0.58, geometry=0.42, ...
    [OK] Wrote .ux/last-system.json (palette, type, spacing, radius, motion)
    [OK] Wrote .ux/decisions.jsonl (1 entry, schema _v: 1)

所有支持的 IDE 都是同一条安装路径:Claude Code、Cursor、Windsurf、GitHub Copilot、Gemini CLI、Codex、Kiro、Cline、Continue、Aider、Zed、JetBrains AI、Pieces、Tabby、Tabnine、CodeWhisperer、Roo Cline。MCP stdio 服务器是所有 IDE 的唯一真源。

坦白边界

#### v3 是地基,不是终点。

七轴合成器是我们已经放出证据的工作。第 8、第 9 个轴 (saturation_strategy、surface_depth) 草案在,未发布,它们会让 dark / light 分流和渐变策略更深一层。决策账本目前只被推荐器的重排消费,我们预计 v3.1 会让评估器和 lint 打分也开始读它。我们拒掉的那份极端化方案并没有消失,当我们能证明某些点确实有帮助时,它们会在以后慢慢进来。

如果你发现某份 brief 的输出让你不满意,或者矩阵里某个结论和你的品味打架,请开 issue。矩阵在仓库里,测试在仓库里,脑也在你的仓库里。从现在起,争论都发生在一个你可以读得到的基底上。

## 这对你意味着什么变化

在 v2 的人:什么都不会坏。你已经在用的 22 条命令行为不变。lint 还是一样的速度。MCP 服务器用原名暴露 18 个工具里的 15 个,再加三个新工具。如果你升级后从不调用 `/ux-synthesize` 或 `/ux-evolve`,你的日常工作流毫无变化。

一直在等引擎从推荐走到生成的人:v3 就是这一步。合成器是新的中心,`/ux-recommend` 还在,而且现在会读你的账本来重排;`/ux-evolve` 关上了打磨循环。品牌规范是训练数据,不是模板。同样的 1,243 条条目,在做完全不同的工作。

我们把 v3 叫做 The Brain,是因为做出来的就是这个东西,一个带闭合反馈回路的、受约束的生成式设计编译器。完全离线,LLM 调用 0 次。同 brief 同轴同输出,异 brief 异区域,无穷输出。你的安装从你的仓库里学,不同仓库长出不同的脑。整个东西是 MIT 协议、普通机器上 sub-300ms、pip 可装。

找一份你真正在意的 brief 跑一下,看返回的是什么。如果输出和你的品味打架,开 issue,冲突进矩阵,规则会被命名,下一次安装就会表现得更好。这就是脑的复利方式。

在你的项目上跑一下

## 一个引擎,三条安装路径。

驱动 v3 的合成器和 linter、recommender 在同一个包里发布。145 条反模式。160 份品牌规范。1,243 条条目。17 个 IDE。MIT 协议、无遥测、无账号。

$ /plugin marketplace add Laith0003/ux-skill
$ /plugin install ux@ux-skill
· 或 ·
$ pip install uxskill
· 或 ·
$ npx uxskill@latest init

GitHub 源码:Laith0003/ux-skill · npm:uxskill · PyPI:uxskill · 文档:uxskill.laithjunaidy.com