baoyu-skills 是 Jim Liu 开源的一组 Claude 技能,用于内容创作(生成信息图、封面图、技术 diagram 等)。本文基于 v1.117.x 的实际使用和源码阅读,从前端工程师熟悉的概念出发,分析它的工程设计。源码:github.com/JimLiu/baoy…
一张让我说不清该怎么调的图
我想用 baoyu-infographic 给技术文章配讲解图——就是那种把复杂逻辑拆成手绘色块的信息图,像这样:
第一稿出来,风格是对的,但信息密度不够——五个 section 各占一行,留白太多,一屏看不到多少内容。
我想调,但不知道从哪里改起。这在以前是个问题。你只能重新描述一遍感觉,祈祷下一张更好。
但 baoyu-infographic 给了我一份参数清单:
Layout: linear-progression ← 问题在这里
Style: hand-drawn-edu
Aspect: portrait 9:16
我意识到问题不在描述词,在 layout 的选择——linear-progression 天生是"呼吸感"布局,每个 section 独占空间;想要高密度,要换 dense-modules,它的设计规则是「每个角落都要有信息,不留装饰性空白」。
我把 layout 改成 dense-modules,重写了 structured-content.md 里的分区结构,重跑 baoyu-image-gen。
第二张图出来,六个模块紧凑排列,信息量是第一张的两倍多。我花在"解释感觉"上的时间是零。
这个过程让我开始认真读 SKILL.md 的源码。
我以为这是一套工具集
baoyu-skills 是一组 Claude 技能,主要用于内容创作:生成信息图、封面图、制作 diagram、格式化文章……
我第一眼扫过去,以为这是一套自动化脚本的集合——每个 skill 解决一个具体任务,就像 npm 上的工具包,装上用就行。你需要封面图,就跑 baoyu-cover-image;你需要架构图,就跑 baoyu-diagram。每个 skill 是一个黑盒,输入需求,输出结果。
按这个理解,它就是一批精心调过的 prompt 的打包,用起来方便,但本质上和手写 prompt 没有区别——换个需求,还是要重新描述,还是没有结构可言。
但读进去之后,我的判断变了。
这不是工具集。它在做三件设计系统里很熟悉的事:
- 五维正交参数:把视觉感觉拆成独立维度,像 design token 一样命名和组合
- 优先级级联:配置的查找顺序和 CSS specificity cascade 是同一个不变量
- 不可变输出:prompt 文件是执行的 source,不是日志,改源头重新执行
模式一:五维参数 = Design Token
baoyu-cover-image 有一张表,定义了五个维度:
| 维度 | 值域 |
|---|---|
| Type | hero / conceptual / typography / metaphor / scene / minimal |
| Palette | warm / elegant / cool / dark / earth / vivid / pastel / mono / retro / duotone / macaron |
| Rendering | flat-vector / hand-drawn / painterly / digital / pixel / chalk / screen-print |
| Text | none / title-only / title-subtitle / text-rich |
| Mood | subtle / balanced / bold |
第一次看到这张表,我以为这是选项下拉列表——可以选 A 或 B 或 C。
但它不是。这五个维度是正交的,每个维度独立变化,互不耦合。Palette: dark 和 Rendering: hand-drawn 可以组合,Palette: warm 和 Rendering: flat-vector 也可以组合——这是笛卡尔积,不是有限选择。
这正是 design token 的核心思路:把视觉语言拆解成独立的轴,用显式的参数替代隐式的感觉。
写 CSS 的时候,你不会直接说"这个按钮要高级一点",你改的是 --color-button-primary 和 --border-radius-md。baoyu-skills 做的是同一件事,只是把这个逻辑搬到了 AI 内容生成的场景里。
在具体实现层,还有一个细节能说明这件事。baoyu-diagram 要求画同一个 box 两次:先画一个不透明矩形遮住背景,再画一个半透明矩形做样式层。原因是 SVG 用 painter's model 渲染,没有真正的 z-index 隔离——如果只画一个半透明 box,箭头线会从底下透上来。这是个隐性的经验陷阱,踩过一次才知道,不写出来就会重复踩。
SKILL.md 把它写成了一条所有 diagram 生成都必须遵守的层叠顺序。一个人的经验,变成了系统的规范——这正是 design token 在做的核心事情:把隐性的感觉判断和经验决策显性化,变成可以被所有人复用的约束。
有意思的是,把这套逻辑从 CSS 搬到 AI 生成场景之后,多出来一个原来没有的能力:参数可以被自动推断。baoyu-cover-image 会根据文章内容的信号(技术类、故事类、产品类……)自动推荐参数组合。你的 token 不会根据页面内容自动选颜色,但 skill 可以。
11 个 palette 不是拍脑袋,是一套受控词汇表
读完所有 palette 文件之后,我理解了这个数字背后的逻辑。
11 个 palette 覆盖的是情感领地,不是颜色区间:
| Palette | 情感语义 | 对应内容信号 |
|---|---|---|
| warm | 人情味,亲切 | 个人故事,生活方式 |
| elegant | 精致,克制 | 思考型,品牌,商业 |
| cool | 工程感,精确 | 技术,架构,API |
| dark | 电影质感,高级 | 夜间主题,娱乐,premium |
| earth | 自然,有机 | wellness,生态 |
| vivid | 能量,爆发 | 产品发布,游戏,促销 |
| pastel | 温柔,奇想 | 儿童,创意,轻内容 |
| mono | 专注,克制到极致 | 禅意,极简 |
| retro | 怀旧 | 历史,复古 |
| duotone | 戏剧性双色 | 电影海报,演出 |
| macaron | 马卡龙柔和 | 教程,知识普及 |
每个 palette 占据一块不重叠的情感领地。warm 和 pastel 都感觉柔和,但前者对应"个人真实故事",后者对应"奇幻轻盈"——用内容信号来区分,而不是用颜色来区分。
这个逻辑很清晰:11 个名字覆盖了内容创作者最常见的情感语境,相互之间不重叠,但也没有遗漏明显的空白地带。
Rendering 的逻辑又不一样——不是按情感,而是按艺术媒介传统——hand-drawn 是速写本,painterly 是水彩画,chalk 是粉笔黑板,screen-print 是 Mondo 限量海报……每一种都是有历史渊源的视觉语言,不是凭空造出来的风格名称。
这不是"拍脑袋选了 11 个",这是一套受控词汇表:在可能的视觉情感空间里,枚举出足够覆盖常见使用场景、彼此又不过于重叠的命名集合。
CSS 命名颜色做的是同一件事——不是枚举所有颜色,而是给那些有语义的颜色命名:tomato、steelblue、goldenrod。名字本身就携带了用途的暗示。
custom_palettes 暴露了这套系统真正的边界
这套词汇表有一条很有意思的边界——它告诉你哪里是开放的,哪里是封闭的。
EXTEND.md 支持 custom_palettes。看一下它的结构,就能理解这套系统开放了什么、封闭了什么:
custom_palettes:
- name: my-brand
description: "品牌主色调,科技感但偏暖"
colors:
primary: ["#FF6B35", "#2E86AB"]
background: "#FAFAFA"
accents: ["#F18F01"]
decorative_hints: "几何线条,带品牌圆角"
best_for: "品牌内容,产品介绍"
你能定义的是颜色、装饰提示、适用场景——也就是"这个 palette 长什么样、适合什么内容"。
但没有 custom_renderings。
这个不对称不是遗漏,是刻意的设计边界。Palette 可以扩展,Rendering 不行。
为什么?因为 rendering 描述的是艺术技法,而技法需要深度的 prompt 工程来实现——hand-drawn 背后是"略带颤抖的线条、笔触压力变化、纸张纹理",这些是嵌在提示词模板里的知识,不是简单地描述一下就能复现的。Palette 不一样,palette 的本质是颜色值加情感标签,这是开放的,用户完全可以自己定义。
用设计系统的语言来说:
- Palette 是 token 层,可以被 override 和扩展
- Rendering 是 primitive 层,是系统提供的原语,不对外开放修改
这条边界,和你在设计系统里区分"主题 token"和"组件基础样式"的判断,是同一种思维。
模式二:EXTEND.md = CSS 级联
baoyu-skills 有一个叫 EXTEND.md 的机制,用来保存用户偏好。它有三个查找路径:
① .baoyu-skills/(项目级) → 最高优先级
② ~/.config/baoyu-skills/(XDG) → 中间层
③ ~/.baoyu-skills/(用户主目录) → 兜底默认值
乍看像普通的配置文件层级,但注意这个方向:更具体的范围覆盖更通用的范围。
这和 CSS 的 specificity cascade 是同一个不变量:
inline style > author stylesheet > browser defaults
项目 EXTEND > 用户全局 EXTEND > skill 内置默认值
这不是巧合,而是同一个设计决策的两种表达:更靠近使用现场的配置,优先级更高。
我在设置 baoyu-cover-image 的时候,把默认比例设成了 2.35:1(微信公众号大封面标准)。这个配置放在用户级 EXTEND.md 里,全局生效,下次不用再选。但如果某个项目需要 16:9,在项目目录下加一个 EXTEND.md 就能覆盖,不影响其他项目。
和 CSS 主题 token 的 override 逻辑完全一致。
模式三:Prompt 文件 = Migration 文件
baoyu-cover-image 在生成图片之前,必须先把提示词完整写入一个 .md 文件:
cover-image/ai-skill-design-token/
├── prompts/
│ └── 01-cover-ai-skill-design-token.md ← 先写这个
└── cover.png ← 再生成这个
SKILL.md 里对这个文件有一句硬性说明:
"The file is the reproducibility record and lets you switch backends without regenerating prompts."
这是为什么呢?
我一开始以为这只是个日志文件,记录一下用了什么 prompt。但实际用起来才发现它的作用——v1 生成的图不满意,我需要改参数重跑。我不用重新描述,直接改这个文件里的几个字段,然后把文件传给 baoyu-image-gen。
它是执行的 source,不是执行的副本。
这和数据库 migration 文件的逻辑一样:先写 migration,再运行。文件本身就是那次变更的完整记录。改了文件,就是改了意图;执行文件,就是实现意图。两者是顺序关系,不是并行关系。
SKILL.md 里还有两条明确写出来的禁令:
⛔ Never substitute SVG/HTML for raster image generation. ⛔ Never repair text by painting over a bitmap.
这两条约束背后是同一件事:输出是不可变的,改源头,重新执行。
这不是操作建议,是约束。文字渲染错了,不能用脚本在图上涂改,必须从修正后的 prompt 文件重新生成。
这也是 design token 系统里的核心思路:token 改了,所有引用它的组件重新渲染;你不会去手动修改每个组件的像素。
想清楚了什么
我之前用 AI 生成图的方式是写 prompt,不满意就重写,直到满意为止。这个过程里,我的每次调整都是对"感觉"的重新描述,没有结构,无法复用。
baoyu-skills 把这个过程颠倒了。
它先把"可能的视觉感觉"分解成若干个正交维度,给每个维度命名,建立值域。然后用这些命名的参数来驱动生成,而不是用自由描述。
这和 design token 的本质是一样的:把隐式的感觉判断变成显式的参数契约。
不满意的时候,你知道是哪个维度出了问题,改那一个就够了。
这不是"更好用的 AI 工具",这是一种不同的工作方式:从感觉驱动,变成参数驱动。
当然,参数驱动也有它的代价——选错了参数,有时反而比自由描述更难发现问题,因为你会先去改参数,而不是重新审视需求本身。但至少,这个系统能让你知道是哪个维度出了问题,而不是在一团感觉里打转。
一个这篇文章本身就在验证的事
这篇文章的讲解图是用 baoyu-infographic 生成的,调了三轮。
第一轮用了 linear-progression,生成后发现信息密度不够,是 layout 选错了。
第二轮换成 dense-modules,重新把内容映射到六个模块原型(Scenario Comparison、Quick Reference、Warning Zone……),重跑 baoyu-image-gen。密度上来了,但模块编号出现重复、部分模块边界模糊。
第三轮强化了 prompt 里的模块标识——把数字编号改成字母 A-F,明确写出"EXACTLY 6 modules,不得重复",再跑一次。这一版模块边界清晰,内容全部进去了。
全程三轮,我没有重新描述过"感觉",每次改的都是具体参数:layout 名、模块数量约束、边界描述。
这本身是个不错的验证:当"感觉"被拆成可命名的维度,不满意的时候你知道是哪个维度出了问题。
这套参数体系目前只覆盖"图片该长什么样",还不涉及"内容该说什么"——那是 structured-content.md 中间层在做的事,结构上也有意思,有时间再拆。
本文基于 baoyu-skills v1.117.x | 源码:github.com/JimLiu/baoy…