---
name: multigrid-poster
description: "为商家生成小红书 2×2 四宫格 / 3×3 九宫格封面图。触发场景:做小红书封面 / 小红书首图 / 种草帖封面 / 爆款封面 / 四宫格 / 九宫格。一句话指令产出 1242×1660 成片,支持自然语言迭代(换版式 / 重抽某格 / 改文案)。本 skill 只生成封面图,搜索小红书笔记 / 分析博主请用 'xhs' skill。"
version: 1.0.0
owner_repo: Optima-Chat/optima-gen
---

# 小红书多宫格封面生成

帮电商商家用 AI 图 + 通用网格布局合成小红书封面。**一句话从意图到 1242×1660 成片**,支持 4 宫格 / 9 宫格两种版式。

## Global Rules

优先级高于任何 pipeline 步骤。

1. **User-facing 不出现模型名 / 服务名**
   status / 成本 / 进度统一用"封面生成中 / 素材生成中 / 合成封面中"。`gen image` 作为 CLI 字面值可以,但不要把整条命令原文回显给用户。

2. **花钱前必走 COST-GATE**
   任何 `gen image` 批量调用之前必走一次成本确认。**Fast-path、迭代、重试均无例外**。2×2 = 4 张,3×3 = 9 张,SKU 拉图 = 0 张。rate 按 `gen image` 每次 1 积分估。

3. **Per-post init 是任何 pipeline 第一步**
   出图 / 合成执行前先建目录 + cd。否则 write 写错位置。迭代场景用 `{旧id}-vN`。

4. **Anti-fabrication**
   未在本 skill 显式列出的命令 / flag / 参数,不允许凭印象拼。`gen image` / `commerce` / `compose.py` 子命令同样适用。

5. **不自动发帖**
   只产 PNG,**绝对不调用**任何自动登录 / 发帖 / 上传命令。完成后给路径,用户自己下载手动发。

## 工作目录

```
~/multigrid-poster/
├── preferences.md
├── history.md
└── posters/{post-id}/
    ├── intent.md             # 用户意图 + layout + 文案
    ├── cells/cell_0..N.png   # 4 或 9 张素材
    ├── cover.png             # 成片
    └── cost.md
```

整个 `~/multigrid-poster/` 是一个 git repo。每步完成后 `git add -A && git commit`。

## 启动流程

1. **首次** (`ls ~/multigrid-poster/preferences.md` 不存在) → `mkdir -p ~/multigrid-poster/posters && cd ~/multigrid-poster && git init -b main`,创建空的 `preferences.md` (字段:merchant_id / brand_name / category / xhs_account_id / default_layout) 和 `history.md` (表头:date | post-id | layout | title | parent | status)。`.gitignore` 加 `posters/**/cells/*.png` 和 `posters/**/cover.png`。
2. **扫未完成**:`posters/` 下有 `intent.md` 但无 `cover.png` 且 < 7 天 → 提一次"你有 N 个封面没完成"。
3. **读 preferences.md / history.md**,继续主流程。

## 主流程

### Step 1: 选 layout

| 用户原话 | layout | cells |
|---|---|---|
| 含"九宫格 / 9 格 / 9 张 / 清单 / N 款 / 礼物推荐 / 榜单" | **3×3** | 9 |
| 其他(包含"四宫格 / 4 格 / 4 张" 或没指定) | **2×2** | 4 |

### Step 2: Per-post init

```bash
# slug = 用户意图前 20 字内的 kebab-case
POST_ID="$(date +%Y%m%d-%H%M)-<slug>"
mkdir -p ~/multigrid-poster/posters/$POST_ID/cells
cd ~/multigrid-poster/posters/$POST_ID
```

迭代("换版式 / 重抽 / 改文案")时:轻迭代沿用旧目录,重迭代新建 `{旧id}-vN`。

### Step 3: 写文案

agent 自己写,不调外部生成器。约束:
- **title**:2 行 × 8-12 字 / 行(2×2 适合)或 2 行 × 6-10 字 / 行(3×3 标题挤)
- **caption**:2 行 × 15-20 字 / 行
- 硬禁:医疗 / 保健 / 绝对化用语(最 / 第一 / 唯一 / 100%)

写到 `intent.md`:

```markdown
# Intent
| 项目 | 值 |
|---|---|
| 用户原话 | <原话> |
| layout | 2x2 / 3x3 |
| title 行 1 | <8-12 字> |
| title 行 2 | <8-12 字> |
| caption 行 1 | <15-20 字> |
| caption 行 2 | <15-20 字> |
```

展示给用户:"标题'XXX / YYY',副标题'AAA / BBB'。OK 吗?"
- Fast-path(意图明确):告知,用户喊停才停
- 意图模糊:必须等确认

### Step 4: COST-GATE

**生成前必做**(包括 Fast-path / 迭代 / 重试):

> 即将生成封面(布局: 2x2 / 3x3),预计:
> - 素材调用: N 次(2×2=4 / 3×3=9 / SKU 拉图=0)
> - 预估耗时: ~X 分钟
> - 预估成本: ~Y 积分
>
> 继续?

用户说"继续 / 好" → 执行。"太贵 / 换便宜的" → 提议降级 (3×3 → 2×2,或 SKU 拉图)。不回应 → 等。

### Step 5: 出图

**默认走 AI 生图**。每个 cell 并行调一次:

```bash
# 2×2: cell 尺寸 621×830;3×3: cell 尺寸 414×420
gen image "<subprompt>" -W <W> -H <H> -o ./cells/cell_<i>.png -s <seed> -f png
```

`<subprompt>` 由 agent 根据用户意图为每格独立设计(不同视角 / 不同 step / 不同场景 / 不同 SKU 等)。`<seed>` 用确定性 hash(POST_ID + cell_index),迭代复用同格 seed。

**SKU 拉图模式**(用户明确说"用我店里商品图"做 listicle):

```bash
commerce product list --limit 9
```

下载到 `./cells/cell_0..8.png`。商品 < 9 → 降级 2×2 取前 4。商品 < 4 → 报错。

**失败容忍**:单格生图失败 → 重试 1 次(换 seed)。两次失败 → 用 `${CLAUDE_SKILL_DIR}/scripts/placeholder.png` 占位,告知用户"第 N 格失败,先占位,要重抽直接说"。

### Step 6: 合成

```bash
python3 $CLAUDE_SKILL_DIR/scripts/compose.py \
  --layout $CLAUDE_SKILL_DIR/layouts/2x2.json \
  --cells ./cells/cell_0.png ./cells/cell_1.png ... \
  --title-line "<title 行 1>" \
  --title-line "<title 行 2>" \
  --caption-line "<caption 行 1>" \
  --caption-line "<caption 行 2>" \
  --output ./cover.png
```

依赖:Pillow(容器自带)。失败常见原因:

| 错误 | 处理 |
|---|---|
| `cell 数量不对` | layout 要求 4 / 9,检查 `--cells` 参数 |
| `font not found` | 检查 `$CLAUDE_SKILL_DIR/shared/fonts/` 完整 |
| 中文显示方块 | 同上,字体没加载 |

### Step 7: 交付

写 `cost.md`,追加 `~/multigrid-poster/history.md` 一行,告知用户:

> 封面在 `~/multigrid-poster/posters/<POST_ID>/cover.png`,可以下载发帖了。
> 换版式 / 改文案 / 重抽某格直接告诉我。

用户说"好 / 完美" → preferences.md `Learned` 追加一条 → commit。

## 迭代

| 类型 | 重跑步骤 | 新目录 | 成本 |
|---|---|---|---|
| 换 layout(2×2 ↔ 3×3) | 文案 → 出图 → 合成 | 是(`-vN`) | 全成本 |
| 重抽全部 | 出图 → 合成 | 是 | 全素材 |
| 重抽单格 N | 出图(单格) → 合成 | 否 | 1 素材 |
| 改文案 | 合成 | 否 | 0 |

**每次迭代也走 COST-GATE**,即使 0 积分。

## 错误处理

| 故障 | 处理 |
|---|---|
| `gen image` 返回 failed | 重试 1 次换 seed → 仍失败用占位图 |
| 超配额 / 余额不足 | 告知用户,不自动降级 |
| `commerce product list` < 9 | 降级 2×2 取前 4 |
| 会话关闭 | 状态在文件系统 + git,下次接续 |

## 相关工具

- `gen image` — 文生图(详见 `gen` skill)
- `commerce merchant get` / `commerce product list` — 商家档案 / 商品(详见 `merchant` skill 和 `product` skill)
- `compose.py` — 本 skill 自带的 Pillow 渲染器

## 流程偏好

- **信息够就直接做(Fast-path)**
- **`intent.md` 是可追溯产物**
- **每步完成立刻 git commit**
- **生成过程零打扰**
- **迭代用 `-vN` 不覆盖**
- **新会话有未完成先告知一次**
