visual-slides
Skill27 starsChanged 8 months agoMITView on GitHub
[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.
In this repository21 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- backlog-managerSkill
- disk-cleanerSkill
- doc-mindmapSkill
- file-masterSkill
- file-organizerSkill
- flow-mediaSkill
- generate-transcriptSkill
- jordan-peterson-perspectiveSkill
- loop-or-notSkill
- pdf-to-imagesSkill
- podcast-downloaderSkill
- ppt-classifySkill
- ppt-narrative-reviewSkill
- ppt-research-setupSkill
- srt-title-generatorSkill
- token-receiptSkill
- ttsSkill
- twitter-downloaderSkill
- visual-deckSkill
- youtube-downloaderSkill
The file
Files
⚠️ Deprecated as default deck skill (2026-05-14)
Use
visual-deckv1.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-deckis 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 batchUpdatepipeline produces wireframe-quality output regardless of how goodinject.pyis. 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 → 用
pptxskill,模板维护成本不值 - 视觉精度要求极高(字距、阴影、复杂图形) → 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.mdreplaceAllShapesWithImage拉的是 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)
- 在 Drive 新建 Slides 文档,按
- 每次生成:填 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 思路可以平移过来,反之亦然。
依赖
- gws CLI ≥ v1.0(从 googleworkspace/cli releases 装)
- gws 已 auth(
gws auth login) - Python 3.10+ +
Pillow(scrim_bake.py) - Nano Banana 出图通道(用户自己有)
快速开始
# 1. 装 gws + 登录(只做一次)
# 见 references/gws-cli-cheatsheet.md
# 2. 看最小例子
cd examples/minimal
cat README.md
# 3. 用最小例子跑一次
python ../../scripts/validate_plan.py content-plan.json
python ../../scripts/inject.py content-plan.json --dry-run # 看请求
python ../../scripts/inject.py content-plan.json # 真跑Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

