| name | visual-slides |
| description | [DEPRECATED — narrow use only] Inject content into a pre-existing hand-authored Google Slides master template via gws CLI batchUpdate (replaceAllText + replaceAllShapesWithImage). Use ONLY when (1) a polished Slides master template already exists on Drive and (2) you need to batch-fill it with N variants of content. For all other "make a visual deck" use cases (general drafting, ep-style content decks, first-time deck), use the visual-deck skill instead — it ships better visual fidelity via open-slide and no template wall. |
⚠️ Deprecated as default deck skill (2026-05-14)
Use visual-deck v1.0 (open-slide based) for general deck authoring. This skill (visual-slides) survives only for one narrow scenario:
- You already have a polished Slides master template authored by hand on Drive
- You need to inject N different content sets into that template (e.g. monthly report, client brief variants)
If you're starting fresh, want production-quality visual fidelity, or don't have an existing template — visual-deck is the right tool, not this one.
Why deprecated: 2026-05-14 ep10 NVIDIA Moat experiment proved that without a pre-existing hand-authored template, the gws slides batchUpdate pipeline produces wireframe-quality output regardless of how good inject.py is. The skill works correctly; the path is just wrong for "single-shot visual deck" — which is 90% of what we author. Kept alive for the 10% batch-fill case.
Long-term plan: PPTX export will be contributed to open-slide upstream. Drive-collab decks will likely consolidate to "open-slide → Drive sync" rather than this gws-injection path.
visual-slides — 视觉版 Google Slides 注入器(narrow-use)
visual-deck 的"亲戚":同一套视觉设计语言(安全区、V2 image prompt、Nano Banana 暗罩),但输出目标从本地文件换成线上 Google Slides 文档。技术路线:不走渲染,走"人工模板 + gws slides batchUpdate 注入"。
何时触发
适用:
- 最终交付必须是 Google Slides URL(协作评论、版本历史、内嵌网页)
- 同一份模板要重复填不同数据(月报、客户方案的 N 个版本、Newsletter)
- 团队里至少有一个人愿意手工维护 Drive 上的母板 deck
不适用:
- 离线 PPT 文件交付 → 用
visual-deck
- 一次性、不复用的 deck → 用
pptx skill,模板维护成本不值
- 视觉精度要求极高(字距、阴影、复杂图形) → Slides API 表现力弱,选
visual-deck
- 母板没人维护 → 这个 skill 等于"没有图纸的注入器",拒做
三条硬约束(从 visual-deck 继承)
这三条不变,踩过的坑同样适用:
1. 文字只进安全区,溢出走 speaker notes
- 每张 slide 都有图像安全区(暗罩区/留白区),占位符必须在安全区内
- 装不下时:不许缩字号,把溢出灌进
{{pN-notes}}(对应该页演讲者备注)
- 安全区比例见
references/safe-zone-spec.md
2. Image prompt 必须 V2 四段式
- 描述 / Composition / Style / Do not include 四段齐全
- 安全区写死在 Composition 段
- 色彩 token + hex 双写
- 详见
references/image-prompts-v2.md
3. Nano Banana 比例有限
- 16:9 / 4:3 / 1:1 / 3:4 / 9:16,不支持 21:9
- Slides 默认页 16:9,绝大多数情况固定 16:9 出图就行
- 见
references/nano-banana-ratios.md
第四条硬约束(Slides 特有)
4. 占位符必须全 deck 唯一,图片必须 Drive 共享可读
replaceAllText 是全 deck 扫描——两页都写 {{title}} 会被同时替换。占位符必须编号:{{p1-title}} / {{p2-title}},见 references/placeholder-naming.md
replaceAllShapesWithImage 拉的是 image URL——Slides 服务端去 fetch,所以图片在 Drive 里必须设置 anyone with link can view。inject.py 会自动加这个权限,完成后不会撤销。私密内容请用专用 Drive 文件夹隔离
完整 Pipeline
┌─── 母板 Slides deck (Drive) ────┐
│ 含 {{pN-title}} / {{pN-img-X}} │
└────────────┬────────────────────┘
│
content-plan.json ── 内容 + 模板 ID
│
image-prompts.md │
│ │
▼ (Nano Banana) │
images/*.png │
│ │
▼ (scrim_bake.py) │
images/*-scrimmed.png │
│ │
▼ ▼
└───────► inject.py ──────────► 线上 Slides deck
│
├─ gws drive files copy (复制母板)
├─ gws drive files create (上传图片 × N)
├─ gws drive permissions create (公开可读)
└─ gws slides presentations batchUpdate
(replaceAllText + replaceAllShapesWithImage)
文件角色
| 文件 | 作用 | 是否改 |
|---|
scripts/inject.py | 主编排器:复制模板→上传图→batchUpdate→输出 URL | 不改 |
scripts/scrim_bake.py | Pillow 把 scrim 暗罩烘进 PNG(Slides 不渲染 gradient) | 不改 |
scripts/validate_plan.py | 在 inject 前校验 content-plan.json 的占位符/路径 | 不改 |
references/template-spec.md | 必读 · 如何在 Slides UI 里手工做母板 | 不改 |
references/placeholder-naming.md | 必读 · {{pN-...}} 占位符语法 | 不改 |
references/safe-zone-spec.md | 安全区%(同 visual-deck,加 Slides EMU 备注) | 不改 |
references/image-prompts-v2.md | V2 prompt 四段式 | 不改 |
references/nano-banana-ratios.md | 出图比例约束 | 不改 |
references/gws-cli-cheatsheet.md | gws 安装/登录 + skill 实际调用的命令 | 不改 |
templates/content-plan.example.json | content-plan 的标准 schema | 复制后填 |
examples/minimal/ | 2 页可跑的最小例子 | 参考 |
占位符约定(核心)
| 类型 | 写法 | 替换机制 |
|---|
| 文本 | {{p1-title}} / {{p3-bullet-2}} | replaceAllText |
| 图片 | 在形状里写 {{p1-img-hero}} | replaceAllShapesWithImage(整形状被替换成图) |
| 备注 | {{p1-notes}}(放在 speaker notes 区域) | replaceAllText(scope: NOTES) |
为什么不用 objectId? 因为 objectId 在复制模板时不稳定(Slides 会重新生成),而文字匹配在复制后依然成立——母板里写什么,副本里就还是什么。这是路线 B 的核心妙处。
标准执行流程
-
首次:用户准备母板 deck(只做一次)
- 在 Drive 新建 Slides 文档,按
references/template-spec.md 设计版式
- 每个文本占位符写
{{pN-xxx}},图片占位符写一个形状(rectangle)内含 {{pN-img-xxx}}
- 记下 deck ID(URL 里
/d/<这段>/edit)
-
每次生成:填 content-plan.json
- 从
templates/content-plan.example.json 复制
- 填
templateDeckId + driveImageFolderId + 每页的 text/image 映射
-
生成 image prompts(V2 四段式)
- 输出到
image-prompts.md,交给用户跑 Nano Banana
-
scrim 烘焙
python scrim_bake.py images/bg-01.png 0.55 images/bg-02.png 0.65 ...
-
lint plan
python validate_plan.py content-plan.json — 检查占位符是否全 deck 唯一、图片路径是否存在
-
干跑(推荐先做)
python inject.py content-plan.json --dry-run — 打印 batchUpdate 请求 JSON,不真改 Drive
-
真跑
python inject.py content-plan.json
- 输出最终
https://docs.google.com/presentation/d/... URL
关键陷阱(Claude 自己最容易犯的)
占位符相关:
- ❌ 全 deck 写
{{title}} —— replaceAllText 会把所有页同时替换。必须 {{p1-title}} / {{p2-title}}
- ❌ 占位符里带中文 ——
replaceAllText 走 UTF-8 没问题,但中文 + 空格 + 标点很容易拼错。坚持 ASCII kebab-case
- ❌ 在母板里把占位符做了花字效果 —— 替换后样式保留,中文/数字会被强行套上原占位符的字体。占位符必须用 deck 默认正文样式
图片相关:
- ❌ 用 base64 data URL —— Slides API 不接受
- ❌ 私人 Drive 文件直接拉 —— Slides 服务器 fetch 不到,replaceAllShapesWithImage 报 INVALID_ARGUMENT。inject.py 会自动改成
anyone with link can view,但要意识到这个安全副作用
- ❌ 图形状里写多行文字占位符 —— Slides 把整个形状看作占位,
{{p1-img-hero}} 必须独占一个形状,周围不能有其他文字
模板相关:
- ❌ 用 Slides "新建空白演示文稿"的母板 —— 它自带 placeholder layout,跟我们的
{{}} 系统打架。建议直接 新建 → 空白,自己摆所有元素
- ❌ 模板改了字号/位置 → 立即触发 inject —— 模板改动后先复制一次空跑,确认占位符还能被找到再批量跑生产
gws 相关:
- ❌ 没装 gws / 没登录 —— inject.py 第一步会探测,但记得
references/gws-cli-cheatsheet.md 里有 gws auth login 步骤
- ❌ 把
templateDeckId 写成 URL 而不是 ID —— Drive 文件 ID 是 URL 里 /d/<ID>/ 那一段,不是整个 URL
与 visual-deck 的关系
| visual-deck | visual-slides |
|---|
| 输出 | 本地 .pptx | 线上 Google Slides URL |
| 渲染 | HTML→PPTX(pptxgenjs) | Slides API batchUpdate |
| 模板 | templates/layouts/*.html(代码资产) | Drive 上手工 deck(非代码资产) |
| 协作 | 文件传输 | 实时协作 / 评论 |
| 一次性 | ✅ 快 | ❌ 模板维护成本 |
| 重复填充 | ❌ 每次重新跑 build | ✅ 模板一份多用 |
| 视觉精度 | 高 | 中 |
| 复用的资产 | — | image-prompts-v2 / safe-zone / nano-banana-ratios / scrim-bake |
选哪个的口诀:一次性、高精度、要离线文件 → visual-deck;要协作、可复用、要 URL → visual-slides。两者共用同一套设计语言,所以从 visual-deck 出过的 deck 思路可以平移过来,反之亦然。
依赖
快速开始
cd examples/minimal
cat README.md
python ../../scripts/validate_plan.py content-plan.json
python ../../scripts/inject.py content-plan.json --dry-run
python ../../scripts/inject.py content-plan.json