# Sticker Pack Forge

> 把一张人物参考图变成一整套可直接在微信 / QQ / iMessage / Telegram 使用的表情包——透明九宫格母版、9 张独立静态素材、9 条循环透明 GIF、平台规格打包，可选延伸成桌面宠物。当用户说「做表情包」「生成我的表情包」「把我的照片做成表情」「meme 贴纸」「QQ/微信表情」「动态表情」「GIF 表情」「桌面宠物」「pet」时使用。支持本地安全变换与 AI 视频两条动效路线，内置 43 个风格 key（12 个家族：Q 版 8 个、手作、卡通、绘画、印刷、数字、萌系简笔 2 个、扁平图形 2 个、复古潮流 3 个、拼贴材质 3 个、**儿童涂鸦 4 个**、**高反差冲击 5 个**）、9 个动作模板、6 个平台档位。

- Skill: `gaoren7716-lab/sticker-pack-forge` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add gaoren7716-lab/sticker-pack-forge`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gaoren7716-lab/sticker-pack-forge/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: gaoren7716-lab (https://skillmd.com/u/gaoren7716-lab)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/gaoren7716-lab/sticker-pack-forge

---


# 表情包工坊

## 这是什么

输入 **一张人物参考图**（可选加一个风格词），输出：

- 一张带透明通道的 3×3 九宫格母版
- 9 张切好的独立透明 PNG（可直接导入微信静态表情）
- 9 条循环透明 GIF（默认本地生成，画布 240×240，微信友好）
- 按平台规格整理好的目录 + ZIP + 总览预览图 + 导入说明
- 一份质检报告：格子数、透明通道真实性、格缝是否干净、体积是否超限

可选延伸：把 9 条 GIF 按固定文件名整理，做成 ChatGPT 桌面端的自定义 Pet。

## 核心原则

1. **最小输入 = 一张参考图。** 用户给了图就直接跑，不要反问风格、数量、平台。
   风格没说 → 默认「大头小身体的夸张 Meme 风」（`style-registry.md` 的 `chibi-pop` 方向）。
   平台没说 → 默认 `wechat` 档位。
2. **透明和身份一致性优先级高于画风。** 任何时候都不为了追求风格牺牲
   "背景真透明、人物完整、九格互不粘连"。
3. **先本地、再模型。** 切图、抠像、动效、打包全部本地完成，可复现、不花额度。
   只有"母版生成"和"可选的视频动效"需要调生成模型。
4. **不做二次叠加。** 用户要求改风格时，**沿用同一张原图重出母版**，
   不要在已经风格化的图上再转一次（会累积失真、丢身份）。

## 输入解析

按顺序找参考图，找到即用：

1. 本轮用户消息里附带的图片路径（`<attached_files>` / 拖入路径）
2. 用户直接写的绝对路径
3. 本会话中用户最近一次提供的图片路径
4. 都没有 → 才问一句图在哪

**情绪 / 动作清单**：用户可以给 9 个（写入 `--labels`），
也可以只给一个主题，由你补全整套。补全时按"情绪光谱"铺开，
避免九张都是同一种情绪。可用的默认九宫格：

```
无语, 哭, 震惊, 得意, 白眼, 问号, 比心, 冲, 笑
```

按人设改写更好用，例如连载作者：
`催更, 收到, 真的假的, 我裂开了, 牛啊, 学废了, 别急, 马上来, 离谱`

## 执行流程

### 阶段 0：环境准备（每个会话第一次跑）

技能自带零依赖的引导脚本，会自动建本地 venv 并装好 Pillow（+ 可选 numpy）：

```bash
python scripts/setup_env.py          # 建 .venv 并装依赖；结尾会打印解释器路径
```

引导完成后，下文所有 `<PY>` 都指这个 venv 解释器：

- Windows：`.venv/Scripts/python.exe`
- macOS / Linux：`.venv/bin/python`

如果你已经有一个装好 Pillow 的 Python，把 `<PY>` 换成它即可，跳过引导。
（也可以跑 `python scripts/setup_env.py --check` 做体检，或 `--venv <已有venv路径>` 指定。）

确认环境就绪后跑自检：

```bash
<PY> scripts/run_selftest.py --workdir <输出根>/_selftest
```

44 项断言，全绿再开始。若报缺 Pillow / numpy / ffmpeg，见 `troubleshooting.md`。

### 阶段 1：建任务目录

通用规则（所有机器适用）：

1. 优先 `<当前工作区>/outputs/sticker-pack/<主题>-<MMDDHHMM>`；
2. 拿不到工作区时退回 `~/.sticker-pack/<主题>-<MMDDHHMM>`；
3. 两者都不确定 → 直接问用户存哪，不要猜盘符。

> 若技能同目录存在 `LOCAL.md`，里面的「输出根目录」覆盖约定优先于上面的通用规则
> （`LOCAL.md` 不进版本库，仅本机私有，见仓库 `.gitignore`）。

子目录固定：`01_sheet/`（母版）、`02_cells/`（静态素材）、`03_gifs/`（动效）、`04_pack/`（交付包）。

### 阶段 2：生成九宫格母版

**这一步消耗图像生成额度**（单张约 5–10 credits）。
每个会话第一次出图前用一句话说明消耗与张数，同一会话后续不再重复提示。

- 工具：任意支持「**图生图（image-to-image）** + **透明背景（alpha）** + **1:1 正方形**」
  三种能力的图像生成工具。不同宿主参数名不同，但能力需求一致：

  | 宿主 / 工具 | 原图字段 | 透明参数 | 尺寸 | 保真 / 参考强度 |
  | --- | --- | --- | --- | --- |
  | WorkBuddy `ImageGen` | `image1` | `background:"transparent"` | `size:"1024x1024"` | `input_fidelity:"high"` |
  | OpenAI Images API | `image[]` | `background:"transparent"` | `size:"1024x1024"` | `input_fidelity:"high"` |
  | Gemini / 其它图生图模型 | 各自 image 字段 | 透明通道 | 正方形 | 高参考强度（保身份） |

  - `input_fidelity` 之类字段不存在就不用传；关键是**保住人物身份、表情、姿势、人数、构图**，只换画风。
  - 若宿主**不支持透明背景**：仍按 `references/prompts.md` 出图，但把"背景透明"改成
    "纯色背景（如纯白 / 纯绿）"，出图后用 `key_out.py --bg <背景色>` 本地抠成透明
    （参见下方质量红线「无透明通道 / 棋盘格假透明」）。
- 提示词：取 `references/prompts.md` **第 2 节的生产版**。
  如果后面只做静态、不打算切图/做动效，可以用第 1 节基础版。
- 九格情绪：把用户的 9 个词替换进提示词里的 Emoji 位（或直接在"每个贴纸呈现不同的
  表情、姿势或反应"后列出）。

**出图后第一件事：验透明。** 很多模型即使传了「透明背景」参数，也会回一张
**画着灰白棋盘格**的 RGB 图来"冒充"透明。

- 先看 `mode` 是不是 RGBA，再数一下透明像素占比。
- 只要不是真 alpha（含"棋盘格假透明"），就先 `key_out.py --bg auto` 抠一遍。
  脚本会自动把棋盘格的**两三种颜色**都识别成背景一并删净，效果等同真 alpha。
- **不要**把棋盘格母版直接丢给 `slice_grid.py`：它检测不到格缝，会走
  `ALPHA_MISSING` 分支，切出来的格子带着棋盘格残底。

产出：真 alpha 直接落 `01_sheet/sheet.png`；否则先落 `sheet_raw.png`，
抠像后另存 `sheet.png`。

### 阶段 3：切分 + 质检

```bash
<PY> scripts/slice_grid.py \
    --input 01_sheet/sheet.png --outdir 02_cells \
    --labels "<九个名称>" --pad 6
```

**不要平均切。** 脚本用投影法找真实格缝，能处理格缝宽窄不一、九格不等宽高。

报告要读这几项：

| 项 | 含义 | 出现时怎么办 |
| --- | --- | --- |
| `ALPHA_REAL` | 母版有真实透明通道 | 正常 |
| `ALPHA_MISSING` | 没有透明通道（含模型画的棋盘格假透明） | 用 `key_out.py --bg auto` 抠底，多色背景会被一起删掉 |
| `FAKE_ALPHA_CHECKERBOARD` | 检测到多色背景 = 假透明棋盘格 | 属正常告警，已自动剔除；确认成品没有格纹残底即可 |
| `GAP_V_DIRTY` / `GAP_H_DIRTY` | 格缝里有残留内容 | 重出母版把缝留宽；先看成品有没有被截断 |
| `CELL_BLEED` | 某格内容贴到裁切边界 | 检查该格成品是否被切断 |
| `CELL_COUNT` 不足 9 | 模型没排出 3×3 | **重出**，不要用空格凑数 |

### 阶段 4：动效（可选，但大多数用户要）

两条路线，按用户偏好选。**没说就默认走本地**（稳、免费、透明干净）。

**路线 A — 本地安全变换（默认）**

```bash
<PY> scripts/animate.py \
    --input 02_cells --outdir 03_gifs --fps 12 --duration 1.0 --size 240
```

九张自动匹配不同动作模板，首尾严格对齐、循环无跳帧。
默认 `--scale-mode uniform`：九格共用同一个缩放比，避免"身体画得短"的那几格
被放大成大头（源图里九个头本来是一样大的）。`--scale-mode fit` 是逐格适配，
只在九格本来就等高时才用。
参数含义、9 个模板的手感、调参边界见 `references/motion-presets.md`。

**路线 B — AI 视频（效果更自然）**

```bash
# B1 铺纯色幕（自动避开主体主色）
<PY> scripts/matte.py --input 02_cells --outdir 04_pack/matte --grid

# B2 把 04_pack/matte/sheet_matte.png 交给视频模型（提示词见 prompts.md 第 6 节）

# B3 视频拆格 + 逐帧抠像 + 出 GIF
<PY> scripts/video_split.py \
    --input <产出的视频> --outdir 03_gifs --rows 3 --cols 3 --size 240 --fps 12
```

B 路线**不要**在视频提示词里写"背景保持透明"——输入已经是色幕，
且视频工具基本不输出 alpha，透明留到 B3 本地做更干净。

用户想两条都要 → 都跑，然后在报告里分别标注来源。

**换风格时**：回阶段 2 用**同一张原图**重出，不要在已风格化的图上二次转换。

**Q 版家族（8 个）比例底座一致，差异在材质语言**。首选用 `chibi-pop`；
想要一眼是风格化贴纸再换：
软糖糖果 → `chibi-gummy`；毛绒布偶 → `chibi-fuzzy`；机甲盒蛋 → `chibi-mecha`；
国潮剪纸 → `chibi-papercut`；随手速写 → `chibi-sketch`；通用 emoji → `chibi-emoji3d`；
积木拼装 → `chibi-toy-brick`。
已知易漂移的：`chibi-fuzzy`（头可能变熊脸）、`chibi-papercut`（可能被理解成贴纸边框）
——这两个的 body 已经显式加了**身份锁定硬约束**，使用时请保留该段或照抄。

风格查 / 拼提示词：
```bash
<PY> scripts/style_registry.py list                          # 看全部
<PY> scripts/style_registry.py resolve "毛绒绒"              # 用户说法 -> key
<PY> scripts/style_registry.py compose --style chibi-gummy \
    --identity "中国男性，黑色短寸平头，..." --labels "催更,收到,..."
```

### 阶段 5：平台适配 + 打包

```bash
<PY> scripts/pack.py \
    --cells 02_cells --gifs 03_gifs --outdir 04_pack --platform wechat --zip
```

`--platform` 可选 `wechat` / `qq` / `imessage` / `telegram` / `discord` /
`generic` / `all`。用户提到多个平台就传 `all`。

产出：分平台目录、`preview_static.png`、`preview_animated.png`、
`manifest.json`、`导入说明.md`、`<任务名>.zip`。

**体积超标**时按这个顺序降级，不要一上来就压画质：
帧率 12→10→8 → 尺寸 240→200→160 → 时长 1.0→0.8→0.6。

### 阶段 6：交付

1. 把**成品图**和 **ZIP** 交付给用户（不要只报路径）。
   若宿主有"文件呈现 / 预览"工具就直接用；没有则在回复里附上绝对路径 + 关键指标。
   优先呈现：`preview_static.png`（一眼看到九格结果）、`preview_animated.png`、
   一条代表性 GIF、`04_pack/<任务名>.zip`。
2. 回复只写四样：匹配到的风格、九格名称、生成方式（本地/视频/两者）、
   成品文件与体积是否达标。
3. 在输出根目录追加一行到 `ledger.md`：
   `时间 | 原图文件名 | 风格 | 静态/动态 | 平台 | 输出路径`
4. **不要**把整段提示词贴进对话污染阅读，除非用户问。

### 阶段 7：桌面宠物（可选延伸）

用户说"做成桌面宠物 / pet / 挂在桌面上"时：
把 9 条 GIF 按固定文件名（`idle.gif` / `running-right.gif` / …）整理到一个目录，
文件名的映射表和提示词见 `references/prompts.md` 第 8 节。
官方入口是 ChatGPT 桌面端 **Settings → Pets → Create your own pet**。

## 产出铁律（违反即重做）

这三条是用户明确提过的要求，优先于任何风格描述：

1. **画面里不许有任何数字。** 九宫格是 3×3 排列，但**绝不许给格子编号**。
   `compose()` 已不再拼 `1 2 3…`，并强制带 `【画面纯净——不要任何文字与编号】` 段。
   自检 T11.13 / T11.14 守着这条，改提示词模板时别把它删了。
2. **产物里不许出现原图。** 原图只作为出图时的参考（`image1`），
   九格必须**全部**是同一套画风，不许留一格"真实照片抠像版"。
   `references/prompts.md` 里那个"中间第 5 格放原图"的旧模板已废弃。
   交付目录里也不要顺手把参考图复制进去。
3. **本地画出来的图上也不许有数字**（v1.4.1 补）。
   素材文件名形如 `01_催更.png`，`slice_grid` 按阅读顺序编号——
   但**预览图上的标签必须剥掉这个序号前缀**，只显示"催更"。
   曾经 `pack.py::build_preview` 把文件名原样印上去，用户看到预览图
   以为"表情包被画上了数字"，实际是本地脚本写的。
   现在统一走 `pack.display_name()`，自检 T10.2 / T10.3 守着。
   **以后任何往图上画字的地方，都要先过 `display_name()`。**

## 质量红线

交付前逐条自查，有硬伤就重出/重跑，并向用户说明改了什么：

- **母版不是真透明** → 提示词里加重"背景透明、人物直接置于透明背景上"，
  或确认工具的透明背景参数真的传了。
- **人物边缘有白边/黑边** → 说明用了基础版提示词。换生产版。
- **九格被连成一幅连续画** → 提示词缺少 `【表情包适配要求】` 段。
- **不同格子像不同的人** → 加重身份约束 + 把图生图保真度调到高。
- **有格子是空的 / 不足 9 格** → 重出母版，不做凑数。
- **抠像把白衬衫、浅发、同色道具打洞** → 用 `--mode border-connected`，
  绝不用全局色键。
- **母版没有 alpha、背景是"画出来的灰白棋盘格"** → 用 `key_out.py --bg auto`，
  它会把多色背景一并删净。别把它当成"已经有透明通道"直接切图。
- **九格里有的头明显比别的大** → 逐格自动适配造成的假象。`animate.py` / `pack.py`
  默认已改成九格共用缩放比，不要回退成 `--scale-mode fit`。
- **打包后 GIF 看着几乎不动** → `reencode_gif` 被写成逐帧重新居中/贴底，
  位移类动作被整体抵消。必须对整段帧序列用**同一套仿射参数**。
- **成品里多出一条莫名其妙的预览图或报告** → 素材目录里放了 `_` 开头的内部文件。
  `list_media` 已统一过滤，不要绕过它自己写 `os.listdir`。
- **个别 GIF 总时长比别的长（比如 1280ms vs 960ms）** → 重编码时在 `seek`
  循环**之后**才读 `duration`，把最后一帧的时长套给了所有帧。
  逐帧时长必须在循环里收，见 `references/motion-presets.md` 第 4 条。
- **GIF 有拖尾** → 确认 `disposal=2`。
- **人物颜色不对但透明正常** → `paste(mask=)` 遮罩方向反了，见 `troubleshooting.md`。
- **单一 GIF 超平台上限** → 按降级顺序调，`pack.py` 会点名是哪个文件。

## 脚本清单

全部在 `scripts/`，只用 Pillow（必需）+ numpy（可选加速）+ ffmpeg（仅视频路线）。

| 脚本 | 作用 |
| --- | --- |
| `common.py` | 公共工具：遮罩、投影、画布归一化、报告 |
| `slice_grid.py` | 九宫格母版 → 9 张透明素材 + 质检 |
| `matte.py` | 透明素材 → 纯色幕 + 九宫格重排（自动避让主体主色） |
| `key_out.py` | 边缘连通抠像（含 alpha 反混合与去溢色）；支持**多色背景**，能处理模型画的"假透明棋盘格" |
| `animate.py` | 本地安全变换 → 循环透明 GIF / WebP / APNG |
| `video_split.py` | 宫格动作视频 → 9 段透明 GIF |
| `pack.py` | 平台规格适配 + 预览图 + manifest + ZIP |
| `run_selftest.py` | 44 项自检，不消耗额度，全绿再开工 |
| `make_test_sheet.py` | 开发用：合成"不完美"九宫格母版 |
| `make_test_video.py` | 开发用：合成 3×3 色幕视频供往返测试 |

## 参考文件

- `references/prompts.md` — 八段可直接复用的提示词（母版两版、风格化、切图、
  视频动效、拆格需求、桌面宠物）
- `references/style-registry.md` — 43 个风格 key（12 家族）+ 别名表 + 编译硬规则。
  **本文件由 `scripts/style_registry.py` 自动生成**，请改脚本再 `render-md`。
- `scripts/style_registry.py` — 风格单一数据源 + CLI：
  `list / show / resolve / compose / validate / render-md / stats`。
- `references/motion-presets.md` — 9 个动作模板参数表、两条动效路线对比、
  平台规格、GIF 透明硬限制
- `references/troubleshooting.md` — 按「现象 → 原因 → 处理」组织的排错手册

## 授权与来源

工作流与提示词整理自公开的公开分享（DA / @zhidawang219555 的表情包系列教程），
本地实现、脚本、质检体系为原创。风格描述为原创特征描述，
不使用在世艺术家姓名或具体作品名作风格锚点，不声称复刻任何现成作品。
用户上传的肖像图仅用于生成用户自己的表情包，处理后不用于训练或再分发。

