agentleFS
crazynomadcrazynomad/skills/visual-slides/SKILL.md

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.

The file

Files
SKILL.md

⚠️ 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.pyPillow 把 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.mdV2 prompt 四段式不改
references/nano-banana-ratios.md出图比例约束不改
references/gws-cli-cheatsheet.mdgws 安装/登录 + skill 实际调用的命令不改
templates/content-plan.example.jsoncontent-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 的核心妙处。

标准执行流程

  1. 首次:用户准备母板 deck(只做一次)
    • 在 Drive 新建 Slides 文档,按 references/template-spec.md 设计版式
    • 每个文本占位符写 {{pN-xxx}},图片占位符写一个形状(rectangle)内含 {{pN-img-xxx}}
    • 记下 deck ID(URL 里 /d/<这段>/edit)
  2. 每次生成:填 content-plan.json
    • 从 templates/content-plan.example.json 复制
    • 填 templateDeckId + driveImageFolderId + 每页的 text/image 映射
  3. 生成 image prompts(V2 四段式)
    • 输出到 image-prompts.md,交给用户跑 Nano Banana
  4. scrim 烘焙
    • python scrim_bake.py images/bg-01.png 0.55 images/bg-02.png 0.65 ...
  5. lint plan
    • python validate_plan.py content-plan.json — 检查占位符是否全 deck 唯一、图片路径是否存在
  6. 干跑(推荐先做)
    • python inject.py content-plan.json --dry-run — 打印 batchUpdate 请求 JSON,不真改 Drive
  7. 真跑
    • 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-deckvisual-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              # 真跑

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.