template-forge · git:20260810.5a10934 · 2026-08-10 · sha256 4248191f108e5a22
template-forge git:20260810.5a10934A
Immutable. This exact content never changes and is served at /api/v1/blob/4248191f108e5a22.
---
name: template-forge
description: >-
Create and register a brand-new Google Slides template (master) from a
design spec — brand colors, fonts, logo, footer — without touching the
Slides UI. The Slides API cannot create masters, so the engine
(scripts/build_template.py) copies a base (Google's default master, or a
registered template) and restyles its layout pages via batchUpdate, then
registers the result as templates/<id>.json with deterministic role
assignment, ready for google-slides-template to generate decks against.
Design input comes from interactive brand tokens, extraction from existing
material (site / logo / deck), or a bundled preset.
Triggers: "新しいテンプレートを作って", "ブランドに合わせたマスターを作成",
"会社カラーのテンプレート", "テンプレートをデザインして", "template-forge",
"design a new slide template", "create a new master", "brand the deck template".
Out of scope: hand-tuning an existing master's design (Slides UI),
PPTX/.potx templates (document-skills:pptx), and generating decks from a
template (google-slides-template).
---
# Template Forge — Create a New Slide Template (Master)
## Important
- **The Slides API cannot create or rename masters/layouts**
(`references/api-notes.md` §1). This skill therefore *derives*: it copies a
base and restyles the base's existing layout pages. Unused base layouts
remain in the file — unregistered and harmless. Role names live only in
`templates/<id>.json`'s alias table.
- **The base's colorScheme is immutable** — every color is written as
explicit RGB. The Slides UI color picker will still show the base's theme
palette; that is expected (same as `templates/corporate.json`).
- **Run every command from the slide-forge root as cwd** — `${CLAUDE_PLUGIN_ROOT}`
when running from an installed plugin, `/path/to/slide-forge` on a
local clone. Auth and the venv are shared at the repo root (`config/`, `.venv`).
- **Never hand the template over without visual verification.** Role
assignment is deterministic, but band/placeholder overlap, font rendering,
and contrast are judged only by eye: always run the layout catalog + the
`slide-qa` skill (Phase 5) before reporting done.
- **Fixes happen in the design spec.** On any defect, edit the spec and
rebuild with `--replace` (deletes the superseded master from Drive after a
successful rebuild). Never patch the generated master in the Slides UI —
that forks it from the spec.
- **Fonts must exist in the Slides font menu** (Google Fonts). Unknown names
fall back silently. Known-safe: Noto Sans JP, Noto Serif JP, M PLUS 1p,
Zen Maru Gothic, BIZ UDPGothic (Japanese); Montserrat, Roboto, Open Sans,
Lato, Source Sans Pro (Latin). Anything else: verify in the catalog deck.
## Quick Reference
| Task | Command |
|------|---------|
| Validate the design spec (offline, free) | `.venv/bin/python scripts/build_template.py --spec design.json --dry-run` |
| Build + auto-register | `.venv/bin/python scripts/build_template.py --spec design.json [--folder <URL/ID>]` |
| Rebuild after spec fixes (URL of json stays, old master deleted) | add `--replace` |
| Derive from a registered template instead of blank | `--base <template-id>` (or `"base"` in the spec) |
| Layout catalog for visual check | `.venv/bin/python scripts/layout_sample.py --template templates/<id>.json` |
| Presets (complete specs minus name/logo/footer) | `templates/presets/{navy-consulting,tech-dark,warm-minimal}.json` |
## Design-spec format
```jsonc
{
"name": "acme-2026", // [a-z0-9-], becomes templates/<name>.json
"displayName": "ACME Master Template",
"base": "blank", // "blank" (Google default) | template id | Slides URL/ID
"brand": {
"colors": { // all #RRGGBB, all 9 required
"primary": "#0B3D91", "primaryDark": "#062A66", "accent": "#F59E0B",
"background": "#FFFFFF", "backgroundAlt": "#F5F7FA",
"textTitle": "#0B1F3A", "textBody": "#1F2937",
"textMuted": "#666666", "textOnDark": "#FFFFFF"
},
"fonts": { "heading": "Montserrat", "body": "Noto Sans JP" },
"logo": { "source": "assets/acme.png", "onDark": "assets/acme-white.png" }, // optional
"footer": { "text": "© 2026 ACME Inc.", "fontSize": 7 } // optional
},
"style": {
"coverStyle": "band-bottom", // band-bottom | band-left | minimal
"sectionStyle": "dark", // dark (primary bg) | rule (light bg + accent rule)
"pageNumbers": true
},
"derive": { // only when base is a registered template
"colorMap": { "#1E3A5F": "primary" }, // base's explicit RGB -> semantic token
"deleteObjects": ["<objectId>"] // brand elements to remove from the base
}
}
```
Standard 6 roles are always produced: COVER / SECTION / CONTENT /
TITLE_ONLY / BLANK / CLOSING (on a blank base, CLOSING restyles the
MAIN_POINT layout).
## Workflow
### Phase 1: Intake (AskUserQuestion, interactive-intake.md manners)
Batch into one round; skip anything already specified:
| # | header | question | options |
|---|---|---|---|
| 1 | デザイン入力 | デザインは何から決めますか? | 対話で指定(色・フォントを聞く)/ 既存資料から抽出(サイト URL・ロゴ・既存デッキ)/ プリセット(3 種を配色の一言つきで提示) |
| 2 | ベース | どのマスターをベースにしますか? | blank — Google 既定(推奨・既定)/ `list_templates.py` の登録テンプレートから派生 |
| 3 | ロゴ | ロゴ画像はありますか? | ある(パスをもらう。濃色背景用があればそれも)/ ない(文字のみ) |
| 4 | フッター | フッター表記は? | © 表記を入れる(文言をもらう)/ 入れない |
Template name (`[a-z0-9-]`) is derived from the brand/company name; confirm
it in the outline, not as a separate question.
### Phase 2: Author the design spec
- **Interactive**: put the answers into the schema above. Check contrast as
you go: textBody on background and textOnDark on primary must be ≥ 4.5:1
(`colors.py` has helpers; eyeball via the catalog otherwise).
- **Extraction is agent judgment, not code**: for a site URL, WebFetch it and
read the brand colors from CSS variables / the logo; for a logo file, Read
the image and pick the dominant color (primary) plus a supporting accent;
for an existing deck, run `inspect_template.py <URL>` and lift its color
report. Merge onto the closest preset skeleton.
- **Preset**: copy `templates/presets/<preset>.json`, fill `name` /
`displayName` / `logo` / `footer.text`.
- Present the palette (hex + role), fonts, and style choices in one summary
block and get approval before building.
### Phase 3: Offline validation
```bash
.venv/bin/python scripts/build_template.py --spec out/<name>-design.json --dry-run
```
Fix any errors (missing colors, bad hex, missing logo file, unknown enums).
### Phase 4: Build and register
```bash
.venv/bin/python scripts/drive_folder.py create "<displayName>" # Drive folder rule
.venv/bin/python scripts/build_template.py --spec out/<name>-design.json --folder <FOLDER_ID>
```
This creates the styled master, registers `templates/<name>.json` with
deterministic roles + provenance (`derivedFrom`, dated notes), injects
page-number geometry, and prints the next steps. Upload the design spec to
the same folder (`drive_folder.py upload <FOLDER> out/<name>-design.json`).
### Phase 5: Catalog and visual QA (not optional)
```bash
.venv/bin/python scripts/layout_sample.py --template templates/<name>.json --folder <FOLDER_ID>
```
Then run the **slide-qa** skill on the catalog deck. Template-specific
checklist on top of the standard one:
- [ ] Bands/bars do not overlap any placeholder text
- [ ] Cover: title/subtitle legible, logo not stretched (aspect preserved)
- [ ] Section: title contrast on its background ≥ 4.5:1; accent rule sits under the title
- [ ] Content: body text is the body font (a silent font fallback means the name was wrong)
- [ ] Footer + page number both visible, not doubled, not clipped
- [ ] Closing: text and onDark logo legible on the dark background
### Phase 6: Fix loop
Edit the design spec → `--dry-run` → rebuild with `--replace` (the old
master is deleted from Drive after success; `templates/<name>.json` is
overwritten in place) → re-run Phase 5 on the affected layouts. Delete
superseded catalog decks from Drive.
### Phase 7: Report and hand off
Report: master URL, catalog deck URL, Drive folder URL, `templates/<name>.json`
path, and the palette summary. State that decks are generated with the
**google-slides-template** skill: the new id now appears in
`list_templates.py` and works with `build_deck.py --template templates/<name>.json`.
Run `cleanup_qa.py` for local thumbnails. If the logo could not be inserted
(org sharing policy), say so and point at the Slides UI for manual placement.
## Limitations (state them when relevant)
- Layout set is fixed to the base's — no adding, deleting, or renaming
layouts. Need more layout variety? Derive from a richer registered
template instead of blank.
- The theme color picker in the Slides UI keeps the base's palette
(colorScheme is API-immutable); all styling is explicit RGB.
- SLIDE_NUMBER placeholders cannot be created — page numbers are drawn by
`build_deck.py` at generation time using the geometry this skill injects.
- Logo insertion needs the image to be anonymously fetchable for a moment
(AssetStore uploads/shares/cleans up); org policies may block it — the
build then warns and continues without the logo.