免费

捏个小伙伴

一个离线文件就是能用的捏人工具:48 种身体、一键实心眼吉祥物套装、11 种材质,导出 1024 透明图,不用生图模型。

安装

把“捏个小伙伴”技能安装到 ~/.claude/skills/clay-buddy。
下载下面每个文件,保存到这个文件夹:
https://skilllift.pages.dev/packs/clay-buddy/SKILL.zh.md → SKILL.md
https://skilllift.pages.dev/packs/clay-buddy/references/style.md → references/style.md
https://skilllift.pages.dev/packs/clay-buddy/assets/studio.html → assets/studio.html
https://skilllift.pages.dev/packs/clay-buddy/scripts/check.mjs → scripts/check.mjs
https://skilllift.pages.dev/packs/clay-buddy/scripts/lib.mjs → scripts/lib.mjs
https://skilllift.pages.dev/packs/clay-buddy/scripts/render.mjs → scripts/render.mjs
https://skilllift.pages.dev/packs/clay-buddy/scripts/contact.mjs → scripts/contact.mjs
https://skilllift.pages.dev/packs/clay-buddy/scripts/drive.mjs → scripts/drive.mjs
然后读一遍 SKILL.md,告诉我它是做什么的,并提醒我开一个新会话。

解压到 ~/.claude/skills

同一个技能,不同的需求

左边是预览。右边由另一个 Agent 按不同需求制作,它只有安装好的技能,没看过预览。

预览
预览
新需求,由另一个 Agent 制作
新需求,由另一个 Agent 制作

这是按虚构需求做的一次测试。系统字体不同时,字形可能略有差异。

交付一个能真正使用的捏人工具,只有一个离线网页文件。用户在浏览器里设计可爱角色(48 种身体,含一键实心眼吉祥物套装;11 种材质、五官、25 种配饰、配色、随机、撤销、本地陈列架、中英双语),下载 1024x1024 透明背景图。不需要生图模型,不花额度,不用三维库。适用于给产品、班级、社团或社区做吉祥物或头像工具;给工作台换品牌、改默认角色;新增形状或颜色;想要实心椭圆眼的简洁吉祥物;或者不用生图模型批量出原创角色图。

交付前必须通过

  • node scripts/check.mjs out.html --brand "名字" --real 退出码为 0;标明虚构的演示可不加 --real
  • 每一页总览图都按原尺寸打开,每一行都看过
  • 亲眼看过,总览图和每张交付图在 1024 和 96 像素下都不像已知角色,也没有难看的东西
  • node scripts/drive.mjs out.html shots/ 退出码为 0
  • 看过 1280 和 390 宽度、两种语言的截图
  • 亲手点过下载或读过脚本结果,图片放在深色背景上能透出来
  • 示例里的样例名字一个都没留下
  • 英文界面除切换按钮自己的名字外没有中文,中文界面除切换按钮自己的名字外没有英文
  • 所有假设都列给了用户
阅读完整 SKILL.md
---
name: clay-buddy
description: 交付一个能真正使用的捏人工具,只有一个离线网页文件。用户在浏览器里设计可爱角色(48 种身体,含一键实心眼吉祥物套装;11 种材质、五官、25 种配饰、配色、随机、撤销、本地陈列架、中英双语),下载 1024x1024 透明背景图。不需要生图模型,不花额度,不用三维库。适用于给产品、班级、社团或社区做吉祥物或头像工具;给工作台换品牌、改默认角色;新增形状或颜色;想要实心椭圆眼的简洁吉祥物;或者不用生图模型批量出原创角色图。
version: 1.0.0
---

# 捏个小伙伴

`assets/studio.html` 就是整个产品。每个像素都由 JavaScript 从高度图算出来,所以每种材质改变的是光照和纹理;同样的设置,在任何浏览器和 Node 里都得到同样的像素。你要做的是复制这个文件,改配置块,有时再加一个形状。不要重画工作台。

改任何视觉内容之前,先读 `references/style.md`。

## 需要问的信息

简报里没有的,一条消息问一次。每一项都有兜底,不会卡住工作。

1. 工作台给谁用:产品或团体的名字,需要中英文就都给。
2. 一句话说明大家在这里做什么。
3. 品牌色(如果有)。
4. 打开时第一眼看到的角色:形状、材质、颜色。
5. 必须有的形状,或者必须隐藏的形状。
6. 要放在陈列架上的现成角色(如果有)。

## 步骤

1. 把 `assets/studio.html` 复制到输出路径。不要凭记忆重写。
2. 只改 `<script id="studio-config" ...>` 和 `</script>` 之间的 JSON,字段见下表。
3. 要加形状或颜色,按下面的“新增形状”“新增颜色”做。
4. 运行 `node scripts/check.mjs out.html --brand "名字" --real`。`--brand` 是宽松匹配,两种语言都算:写 `潮汐线` 时,品牌名含这三个字就通过。只有标明虚构的演示才去掉 `--real`。按报错修改后重跑,一次约 30 秒。
5. 运行 `node scripts/contact.mjs out.html sheets/`,用看图工具打开每一张总览图。`forms-by-wear-N.png` 是每个形状配每个配饰,每页 8 个形状。`forms-by-colour-N.png` 是每个形状在 16 种日常颜色、96 像素下的样子。`solid-set.png` 和 `solid-large.png` 是实心眼套装的鲜艳配色。`finishes.png` 是每种材质在 96 像素下的样子,`faces.png` 是最大的脸。每一页都按原尺寸打开。**检查脚本无法判断是否像某个已知角色,也分不出可爱和难看,只有你能判断。每张总览图、每张要交付的图,都要在 1024 和 96 像素下亲眼看这两点。**
6. 用 `npm install playwright` 安装 Playwright(需要时把 `NODE_PATH` 指向装有它的目录),再运行 `node scripts/drive.mjs out.html shots/`。它会在 1280 和 390 宽度、动效开和减弱、模拟触屏下全部跑一遍,并解码真实下载的图片、核对透明通道。约 3 分钟,浏览器由脚本自己关闭。
7. 打开 `shots/` 里的截图,两种宽度、两种语言都要看,每一张都要看。托盘缩略图在每次改动后稍等才重画。自己写脚本时,要等 `document.body.dataset.thumbs` 重新有值再截图,否则格子是空的,或者还是上一个角色。
8. 交付文件。双击就能运行,不需要服务器。

不开浏览器出图:`node scripts/render.mjs out.html pip.png '{"form":"owl","finish":"wood","body":"#7A5237"}'`。每张约一秒,像素和下载按钮完全相同。

## 实心眼套装

一套独立的吉祥物风格:18 个没有手脚的圆润轮廓(`squircle`、`pebble`、`blob`、`puffcloud`、`teardrop`、`clover`、`flower`、`shield`、`kidney`、`arch`、`heart`、`gem`、`pear`、`tulip`、`bellshape`、`scallop`、`pill`、`kite`),简单的实心椭圆眼,鲜艳的纯色,配 `vinyl`(搪胶)材质。

**用户怎么说。** 下面这些说法都按这个套装处理:“吉祥物风”“扁平吉祥物”“简单的小团子角色”“实心眼”“豆豆眼”“极简头像”“带脸的可爱形状”“贴纸风形状”“一组形状角色”。点名某个外部头像库时,只算想要这种风格:做我们自己的,不要照搬它的图,也不要在成品里写它的名字。

**在工作台里。** 点一下“实心眼套装:帮我挑一个”就得到完整角色。从套装外点某个轮廓,会带上整套风格;在套装内点轮廓,只换轮廓。只要角色是轮廓形状加实心眼,随机就留在套装里;换别的眼睛或非轮廓形状就离开套装。每个轮廓都能用所有眼睛、嘴巴、颜色、材质和配饰,导出同样的透明图。

**让工作台一打开就是这种风格,** 这样设置配置:

```json
"forms": ["squircle","pebble","blob","puffcloud","teardrop","clover","flower","shield","kidney","arch","heart","gem","pear","tulip","bellshape","scallop","pill","kite"],
"defaults": {"form":"squircle","finish":"vinyl","body":"#FF8A00","accent":"#FFF6E8","wear":"#00B8A9","eyes":"solid","mouth":"smile","hat":"none","face":"none","neck":"none","extra":"none","blush":0,"seed":1}
```

`forms` 保持 `"all"` 就同时保留其他形状。命令行出图:`node scripts/render.mjs out.html a.png '{"form":"clover","finish":"vinyl","eyes":"solid","body":"#7A4DFF","blush":0}'`。

**新增轮廓:** 设 `group:'solid'`,只用一个身体:`sil('key',function(){return ctrl([[x,y],...],4);})`。`ctrl` 画一条穿过控制点的平滑闭合轮廓,`radial(cx,cy,function(deg){return radius;},n)` 用半径函数画轮廓,点数很少的列表加 `{r:72}` 得到圆角多边形。`key` 不能重复。眼睛放高一些,轮廓要和其他轮廓有足够差别:任何两个轮廓在 96 像素下重合超过 88%,检查就失败。

**这个套装尤其要防撞脸,** 因为简单形状配椭圆眼离很多知名角色都很近。`RISKY` 也覆盖了这个套装:黄星星、红或橙的花、白云配椭圆眼;粉色圆形;丁香色小团子配小眼睛;黄色圆形配笑脸;黄色圆方块配大门牙或领结;黄色胶囊配眼镜;红、粉、白色拱门;绿色拱门;蓝水滴;黄、红、橙色贝壳(接近某知名标志);棕色软团。这些搭配会换色并提示。**检查脚本同样无法判断这个套装是否撞脸,必须由你亲眼看。**

## 配置字段

每个文字字段都有 `en` 和 `zh` 两个值。英文里不出现中文,中文里不出现拉丁字母:把“PNG”写成“透明图”,品牌名要给出中文译名。用户只给了一种语言时问一次;没人回答,就用同样的意思写另一种语言,并列为推断项。

| 字段 | 含义 | 上限 | 简报信息不足时 |
|---|---|---|---|
| `brand` | 页头和标签页上的名字 | 英文 28,中文 14 字 | 用给定的名字。没有名字就保留模板自带的品牌名,它们能通过检查,并告知用户 |
| `tagline` | 一句话说明做什么 | 英文 70,中文 36 字 | 复述用户自己的话,不编受众和卖点。什么都没给就保留默认句 |
| `footnote` | 页脚小字 | 英文 120,中文 60 字 | 保留默认的隐私说明,它对这个文件是真实的。不要添加客户、数字或奖项 |
| `fictional` | 为 `true` 时页头显示标签 | 布尔值 | 真实项目填 `false`,只有虚构演示填 `true` |
| `fictionalLabel` | 标签文字 | 英文 24,中文 12 字;`fictional` 为真时必须在两种语言里都写明虚构,检查会核对 | 保留默认 |
| `lang` | 首次打开的语言 | `en` 或 `zh` | 跟简报的语言一致 |
| `theme.accent` | 托盘标签和下载按钮的颜色 | `#RRGGBB`,与 `accent-ink` 对比度至少 4.5:1 | 用品牌色。没有就保留 `#B5391F` |
| `theme.accent-ink` | 强调色上的文字颜色 | `#RRGGBB`,与强调色对比度至少 4.5:1 | 在 `#FFF6E9` 和 `#2C1F14` 中选能达到 4.5:1 的那个。看比值,不要靠眼睛:`#F26A1B` 这样的亮橙看着很重,却要配深色。检查会告诉你哪个能过 |
| `theme.mat` | 角色背后的切割垫 | `#RRGGBB`,与 `#EAF6EE` 对比度至少 4.5:1 | 保留 `#1E5A50`,或用第二品牌色的深色版 |
| `forms` | `"all"` 或要显示的形状编号列表 | 编号必须存在 | `"all"` |
| `palette` | `[]` 用默认 24 色(16 种日常色、8 种鲜艳色),或 `{hex,en,zh}` 列表;实心眼套装可选用的颜色加 `"vivid":1` | 8 到 24 色,中英文名都要 | `[]` |
| `defaults` | 第一眼看到的角色 | 编号有效、颜色为 `#RRGGBB`,见 `references/style.md` | 保留默认,或换成品牌色 |
| `defaultName` | 用户没起名时用的名字。它跟随语言切换,陈列架和文件名也一样;用户自己输入的名字保持原样 | 英文 24,中文 12 字 | 留空,自动用内置名字 |
| `brandmark` | 页头小角色的设置;`null` 表示沿用 `defaults` | 同 `defaults` | `null` |
| `starters` | 陈列架上的现成角色,每个是 `{name:{en,zh},settings}` | 0 到 8 个;名字英文 24,中文 12 字 | `[]`。用户要的角色放在这里;没给名字就按角色职责起名,比如“甲板水手”。没人要的角色不要加 |

`{{BRAND}}`、`TODO`、`your brand` 这类占位内容,以及示例里的任何样例名字,都过不了检查。需要中性的替代内容时,用模板自带的值,它们能通过。

## 新增形状

在引擎 `SLOT:forms` 和 `END SLOT:forms` 之间的 `FORMS` 数组末尾追加一条记录。

| 字段 | 含义 | 规则 |
|---|---|---|
| `id` | 配方里用的编号 | 小写字母和数字,不重复,不能含 `~` |
| `group` | 所在托盘分区 | `round`、`animal` 或 `fantasy` |
| `en`、`zh` | 显示名字 | 英文不超过 16,中文不超过 6 字 |
| `head` | 在 1000 x 1000 坐标(y 向下)里头骨的椭圆 `{x,y,rx,ry}` | 帽子和耳机只靠它就位,必须和看到的头一致,不算耳朵 |
| `eyes` | `{y,gap,r}`,可选 `x` | 眼线高度、两眼间距的一半、半径约 30 到 40。两只眼都要落在身体上,140% 大小时也一样 |
| `mouth` | `{y,w}`,可选 `x` | 嘴的高度和宽度,0.5 到 1.5 |
| `neck` | `{y}` | 围巾和项圈读取这条线上身体的真实宽度,所以这条线要穿过身体 |
| `parts()` | 返回造型部件,按顺序绘制 | 工具见下表。`tag:'top'` 的部件戴帽子时隐藏 |
| `deco(c)` | 可选的表面标记,在部件之后绘制 | `ink` 和 `line`,用 `c.surf(x,y)` 定位 |

### 绘制工具

坐标是 1000 x 1000,y 向下。`z` 朝向观看者,身体正面大约在 `z` 150 到 220。选项放在最后一个参数:`m` 材料,`z` 深度,`rz` 厚度,`rot` 角度,`k` 和相邻身体部件的融合半径(`k:0` 是硬边),`tag`。

| 工具 | 画什么 | 用在哪里 |
|---|---|---|
| `E(x,y,rx,ry,o)` | 椭球 | 头、身体、耳朵、脚 |
| `S(x,y,rx,ry,o)` | 圆角方块 | 方形身体、面板 |
| `curve([[x,y,r,z],...],o,steps)` | 平滑的渐细管,每个点半径为 `r`,`z` 可省略 | 尾巴、角、象鼻、头身一体 |
| `T([[x,y,r,z],...],o)` | 同样的管子,不做平滑 | 短而直的尖刺 |
| `P([[x,y],...],o)` | 柔软多边形;`r` 圆角,`w` 从边缘隆起的距离,`rz` 高度 | 尖耳朵、翅膀、叶子 |
| `band(y,h,o)` | **画在已有部件上的干净条纹。** `y` 中线,`h` 总高度,`sag` 中间下垂量(默认 18),`m` 颜色(默认 `stripe`,自动选对比色),`on` 覆盖哪种材料(默认 `body`),`lift` 凸起量(默认 5),`x0`、`x1` 可缩短 | 条纹、腰带、衬衫、救生圈。写在它要覆盖的部件之后。它正好停在轮廓线上,所以不要用一排 `line` 堆条纹:1024 下会有横纹和锯齿边 |
| `both(fn)` 配 `sx(s,dx)` | 分别调用 `fn(1)` 和 `fn(-1)`;`sx` 把到中线的距离做镜像 | 成对的耳朵、手臂、脚 |
| `chibi(o)`、`feetOnly(y,gap,m)` | 现成的小身体(含手脚),或者只有脚 | 大头动物 |
| `line([[x,y,r],...],c,r,m,lift)` | 只用于 `deco`:贴着表面的细管,每点半径可选;`m` 可用 `ink`、`shade` 或任何材料 | 胡须、羽毛纹。不要用来铺大面积 |
| `ink(x,y,rx,ry,c,lift,rot,m)` | 只用于 `deco`:贴在表面的小块;`ink` 在深色身体上会自动变浅 | 鼻子、鼻孔、按钮 |

材料:`body`、`accent`、`wear`、`stripe`、`gold`、`beak`、`ink2`、`wing`。

完整例子:一只壳上有条纹的乌龟。内置的 `bee` 和 `person` 记录也用了 `band`。

```js
{id:'turtle',group:'animal',en:'...',zh:'小乌龟',head:{x:500,y:340,rx:170,ry:150},eyes:{y:340,gap:76,r:32},mouth:{y:415,w:.8},neck:{y:490},
 parts:function(){return [
   E(500,350,175,160,{rz:150}),                         // 头
   E(500,650,250,190,{z:10,rz:170,m:'accent',k:6}),     // 壳,和头相交,避免悬空
   band(620,44,{on:'accent',m:'wear',sag:20}),          // 只画在壳上的干净条纹
   band(720,44,{on:'accent',m:'wear',sag:20})
  ].concat(both(function(s){return [E(sx(s,232),800,74,44,{z:40,rz:50})];}));}},  // 脚
```

脸会自动放大到 96 像素下看得清,上限是表面能容纳的大小,所以眼睛和嘴的数值是位置和起始大小。

身体每个部件都必须和其余部分相连,否则检查会报告悬空。然后跑检查、看总览图:新形状在 96 像素下,橙色和炭黑色都要一眼认得出来。

**什么时候停:** 为了让形状认得出来,最多试两次,不行就走下面的兜底。认得出来以后,打磨粗糙处最多再做两轮,用 `band` 和 `curve`,不要堆管子,然后停下,把剩下的问题写进交付说明。

### 撞脸

所有形状都要原创、通用。不要照搬任何已知角色、吉祥物或品牌,也不要用预设拼出来。用户点名要某个角色时,这部分要拒绝,改提供通用形状。

普通预设也可能无意中拼成知名角色。测试时,一个天蓝色圆形配白色条纹和红色铃铛项圈就真的撞脸了,而且通过了所有自动检查。所以铃铛项圈已彻底移除,引擎里的 `RISKY` 列表按颜色系和特征拦住已发现的搭配:蓝色圆形配白色点缀和红色领口、白猫配红蝴蝶结、黄色尖耳动物配腮红、粉色圆形配竖椭圆眼、蓝色刺猬、绿青蛙配领巾、黄星星配竖椭圆眼、深棕色水滴等。被拦的搭配会换掉一个颜色并提示用户,在工作台、随机和 `render.mjs` 里都一样。

**检查脚本只能确认这些已列出的规则仍然有效,无法判断撞脸,必须由你亲眼看。** 在总览图或图片上看到眼熟的角色或难看的东西,就改掉这个角色,再往 `RISKY` 加一条规则(判断条件和改动最小的修正),并在 `check.mjs` 的 `RISK_CASES` 加一个用例。如果 `defaults` 或现成角色命中规则,检查会失败,否则它们会被悄悄换色而没人发现。

### 角色和职业

简报给的是职业或气质而不是具体生物时,从这里开始,并把选择列为推断项。

| 职业或气质 | 形状 | 穿戴 | 说明 |
|---|---|---|---|
| 船员、水手、港口 | `person`、`dog`、`penguin` | `sailor` 帽、`kerchief` | `person` 的条纹衫很合适 |
| 员工、团队成员、前台 | `person`、`bean`、`bear` | `lanyard`、`bowtie` | 工作牌不用制服也能表明身份 |
| 建筑、工地、维修 | `person`、`bear`、`robot` | `hardhat`、`lanyard` | |
| 厨师、烘焙、食堂 | `person`、`pig`、`loaf` | `chef` 帽、`kerchief` | |
| 图书馆员、老师、学生 | `owl`、`person`、`rabbit` | `round` 眼镜、`book`、`backpack` | |
| 旅行者、探险家 | `fox`、`dog`、`person` | `cap`、`scarf`、`backpack` | |
| 音乐、播客、游戏 | `cat`、`robot`、`imp` | `phones`、`shades` | |
| 魔法、奇幻、童话 | `dragon`、`unicorn`、`fairy`、`star` | `wizard`、`wand`、`cape` | |
| 庆祝、奖励 | `chick`、`bee`、`star` | `party`、`crown`、`bowtie` | |
| 亲切、可爱、没有职业 | `bear`、`puff`、`bean` | 不戴或 `scarf` | 用 `sparkle` 眼、`smile`、`rubber` 或 `felt` |
| 科技、产品、自动化 | `robot`、`bean` | `phones`、`lanyard` | |

这里没有任何职业的真实制服。用户有这个预期时要说明,并建议用品牌色做 `wear`。

**用户要的形状不存在时:** 如果是能用上面的部件搭出来的通用生物,就加上。试两次还认不出来,或者是有名字的角色,就用中性形状 `puff`(绒绒球),告诉用户用了哪个形状、为什么,并列入假设清单。

## 新增颜色

把 `config.palette` 设为完整的颜色表,每项是 `{"hex":"#RRGGBB","en":"...","zh":"名字"}`。检查会用每种材质渲染每种颜色,脸部对比度不够就失败。脸、帽子和点缀色有自动保护:颜色太接近身体时会自动偏移,所以如果用户指定的配饰色和身体相同,要告诉他。光照和材质也会让颜色变化:陶泥偏土色,橡胶在大面积身体上会变深,所以角色身上的品牌色不会和色块完全一致。颜色要求严格时要说明。

## 新增或修改材质

在 `FINISHES` 加一条记录,并在 `renderRaw` 的两个 switch(高度图和光照)里各加一个 `case`。材质必须改变表面或光照,不能只换颜色。任何两种材质在 96 像素下太像,检查就失败。只能用 `+ - * / Math.sqrt Math.floor`:检查会拒绝 `Math.sin`、`pow`、`exp`、`log`、`atan` 和 `random`,因为它们会破坏跨浏览器的一致性。

## 没人能回答时

继续做。按表里的兜底填写,交付时用一份短清单列出所有推断的值。复述用户给的事实,不要编造客户、数字、评价或资质。

- **文案长度不同:** 按上限删减,不要缩小字号。
- **没有真实链接:** 这个工作台不需要链接,不要加。一定要留地址就以纯文字写进 `footnote`,因为检查不允许文件里出现 `http` 地址。
- **形状要多要少:** 用 `forms` 隐藏,或者新增记录。检查仍会测试文件里的每个形状,无论是否隐藏。

## 已知限制

- 用户自己输入的名字保持输入时的语言。翻译等于替他起名。
- 在 390 宽度下,垫子和工具栏固定在屏幕上,约占四成高度,这样挑选时能一直看到角色。很矮的手机屏会取消固定。
- 没有真人长相,也没有真实制服:`person` 是通用的玩偶小人。
- `check.mjs` 只覆盖已列出的高风险搭配,见上文。

## 交付物

- 一个网页文件,双击离线可用。
- 如有要求,附上从中导出的图片,每张 1024 x 1024、真透明,配方写在文件里。
- 一份推断值短清单。

## 交付前检查

- [ ] `node scripts/check.mjs out.html --brand "名字" --real` 退出码为 0;标明虚构的演示可不加 `--real`
- [ ] 每一页总览图都按原尺寸打开,每一行都看过
- [ ] 亲眼看过,总览图和每张交付图在 1024 和 96 像素下都不像已知角色,也没有难看的东西
- [ ] `node scripts/drive.mjs out.html shots/` 退出码为 0
- [ ] 看过 1280 和 390 宽度、两种语言的截图
- [ ] 亲手点过下载或读过脚本结果,图片放在深色背景上能透出来
- [ ] 示例里的样例名字一个都没留下
- [ ] 英文界面除切换按钮自己的名字外没有中文,中文界面除切换按钮自己的名字外没有英文
- [ ] 所有假设都列给了用户

## 不适用的情况

- 写实肖像或真人长相:这里只画风格化的玩偶。
- 复刻有名字的角色或授权吉祥物。
- 动画或视频:只输出静态图片。
- 超出这些部件能力的定制美术:请找插画师。

## 运行要求

工作台只需要任何较新的浏览器。脚本需要 Node 18 及以上,不依赖任何包;只有 `drive.mjs` 需要 Playwright。导出一张 1024 图在笔记本上不到一秒,`check.mjs` 约 10 秒。不需要网络、生图模型或账号。

用在这些流程里

相似技能