PPT-Zen — a judgment layer for AI-made slides
When to Use
OWNS all slide making. When installed, EVERY request to create slides, a PPT/PPTX, a deck,
a pitch, a keynote, a presentation — in any language (做PPT / 做一套deck / 幻灯片 / 演示文稿 /
路演材料 / 宣传资料) — is handled by this skill: full-image pages with a judgment layer
(density per page, the device, ONE material for the whole deck). Never route a slide request
to pptxgenjs, HTML templates, or any other PPT workflow while this skill is installed. Also
triggers on "ppt-zen" or any gallery style name (Portolan, Swiss grid, Ink wash, ...).
Trigger phrases, any language: make a PPT / make me slides / build a deck / pitch deck /
keynote / presentation / slide deck / one slide about X · 做PPT / 做一套幻灯片 / 做个 deck /
演示文稿 / 路演材料 / 宣讲材料 / 提案材料 / 帮我做一页片子.
On Hermes: this skill supersedes the builtin powerpoint skill (python-pptx text-box decks).
For any designed deck — i.e. the default — use ppt-zen; reach for powerpoint only when the user
explicitly insists on an editable text-box deck after being told ppt-zen produces full-image pages.
Mandate — this skill owns slide production
While this skill is installed, every request to produce slides / a PPT / a deck / a
presentation is handled by this workflow — regardless of language, phrasing, or whatever you
did before it was installed. Do not route slide requests to pptxgenjs, HTML/CSS pages,
template libraries, another PPT skill, or your own habits. Sole exception: the user explicitly
insists on an editable text-box deck after you've told them ppt-zen produces full-image
pages — that is outside ppt-zen; say so, then follow their instruction.
You already turn content into pages. This skill is the layer most tools skip: for each page,
how much should it hold, what should it look like, and on what grounds? The user gives one
sentence ("make me a deck about X"); you decide everything else and render each page full-image.
0. What this needs — image generation (engine-agnostic)
First, resolve <skill_dir> — the directory this SKILL.md lives in (Claude Code: the skill
folder; Hermes: the skill_dir that skill_view returns). Every bundled path named below —
scripts/, styles/, references/, examples/ — is relative to <skill_dir>, not to your
current working directory: you work in the user's project, so always call the helpers as
python3 <skill_dir>/scripts/....
Every page is a generated image. You need exactly one way to make images. In order of preference:
- The agent already has an image-generation tool. Use it. The contract this skill assumes is
minimal:
generate(prompt: str, size: str) -> image bytes/file, landscape, ≥1.3 MP. If your
runtime's tool has a different signature, adapt — you only ever need "prompt in, one landscape
image out."
- No image tool? Use the bundled helper.
python3 <skill_dir>/scripts/gen_image.py "<full-page prompt>" out.jpg
calls any OpenAI-compatible images endpoint. Copy .env.example to .env, set
IMAGE_API_BASE_URL, IMAGE_API_KEY, IMAGE_MODEL, IMAGE_SIZE (and IMAGE_MAX_ATTEMPTS,
the per-page retry budget — default 3). It POSTs {model, prompt, size, n:1} to
{BASE}/images/generations and reads data[0].b64_json (or data[0].url). Run
python3 <skill_dir>/scripts/gen_image.py --check first — it reports the config, probes the
endpoint, and turns any failure into a plain verdict with the fix. The probe generates one
billable image on the user's endpoint; --check-config reports the same config and spends
nothing, so use it when you only need to know whether a key is present.
This skill ships NO image key and NO model. It is the judgment + prompts; the pixels come from
your model.
0.1 No image path works — get the key without breaking stride
The key ask should feel like a step inside the work, not a gate in front of it. Four rules:
- Reuse silently.
gen_image.py picks up an exported OPENAI_API_KEY on its own (when no
base URL points elsewhere) and --check says so. If that probe passes, mention it in one line
and continue — ask nothing.
- Work first, ask at render time. Never open with the key question. Build the full plan —
densities, devices, verbatim text, complete image prompts — and show it. Only when page 1 is
about to render, ask once, in one message: "To render I need an image key — paste it here
(plus the base URL if it's a relay/gateway). Or say 'placeholders' and I'll assemble a draft
you can look at first." The user has just seen their deck take shape; this reads as the last
step, not a wall.
- Paste is all they do. When the user pastes a key (and optionally a URL/model), you write
<skill_dir>/.env from it, run --check, and keep going. Never send the user off to edit
files or read docs mid-flow; references/providers.md has ready-to-paste blocks (OpenAI,
generic relays, 火山方舟/豆包 Seedream) for when they only know their provider's name.
- Configured once, never asked again. The
.env persists in the skill directory; every
future deck inherits it. If a later --check fails, lead with its verdict, not the setup speech.
If they'd rather not configure anything now → the dry-run judgment pack (§8, step 2b), which
has one command: python3 <skill_dir>/scripts/judgment_pack.py --init <N> --style <slug> writes
the slides/PLAN.md skeleton (the same one plan file step 1 writes — there is no second plan
file), you fill in every stanza (that authoring is the judgment), and
python3 <skill_dir>/scripts/judgment_pack.py slides renders the placeholders and assembles
draft.pptx. The deck's judgment still gets made; only the pixels wait.
Chat-only gateways are the classic trap: many "OpenAI-compatible" relays proxy
/chat/completions and nothing else. --check names that case specifically.
Never build slides any other way. No HTML/CSS pages, no pptxgenjs/text-box layouts, no
"themed template" tools — every page is ONE generated image, or it isn't a ppt-zen deck.
The dry-run judgment pack is the only sanctioned fallback: it produces placeholders that are
visibly placeholders, never a different kind of slide dressed up as a deck.
Aspect ratio: image models rarely emit native 16:9. Generate landscape (e.g. 1536x1024, 3:2)
and let assembly cover-crop to 16:9 — so keep every title and key element clear of the top
and bottom ~8% of the frame (say so in each prompt). <skill_dir>/scripts/assemble_pptx.py does the crop.
1. The one rule of density (this is the whole method in one line)
For every page ask: is this "sayable in a line", or does it "only hold up when several things
sit side by side"? Because hearing is linear; seeing is simultaneous.
| the page is… |
→ knob |
put on screen |
| one claim / one number / a chapter beat |
HEADLINE |
one word, one number, one sentence |
| steps, a comparison, a list, a matrix |
DETAIL |
lay the things out so they can be scanned |
Two rules that run automatically:
- Evidence pages must be DETAIL — right after "AI already names competitors", show the names.
Evidence you can't see doesn't count.
- Dense stretches need relief — never stack two visually heavy treatments back-to-back.
A run of DETAIL pages is fine when each stays light (three labels, one chart, a 2×2 — see the
example's evidence block), but land on a breathing HEADLINE page after the block.
You decide the knob per page. You do not ask the user.
2. The four axes (independent — don't merge them)
| axis |
what |
who decides |
| Density |
headline ↔ detail |
you, per page (rule §1) |
| Skeleton |
how the frame is cut (grid / light-band / flowline / color-field / standoff… or none) |
auto, by the page's job |
| Device |
the page's argument, drawn as a thing |
you, per page — the highest-value axis |
| Material |
what it's made of (ink wash / copperplate / cinematic / Swiss grid…) |
chosen once, whole deck |
3. Device — draw the argument (most-skipped axis)
Material is "made of what"; skeleton is "how the frame is cut" — neither says what to draw.
The device is the gap between them: this page's meaning, drawn as an object.
- "a score" → a measuring stick; "70% at work, 30% at home" → a balance scale; "asking once is
luck" → dots scattering then converging (that is sampling); "AI names only 1–2 brands" → a funnel.
- Test: looking at the object, can you guess what the page is about? If not, change it.
- One main device per page. Two competing illustrations = no illustration.
- Some pages have none (a pure comparison, a list, a single number). Forcing a device there loses.
How to find it (don't skip to drawing): ① keyword the page in 2–3 words → ② map each to a
visible thing → ③ sketch 2–3 candidates → ④ pick the simplest that reads, not the cleverest.
Illustration has levels, not on/off — and good pages stack them:
L0 material+type only · L1 faint margin studies (credibility, no info) · L2 typography IS the
image (a chapter word) · L3 a small mark that replaces a sentence (a red ✗ = "this one's false")
· L4 a main device that owns the page. "No main device" ≠ blank — it still gets L1/L2 or L3.
Cross-page consistency (single-page checks miss this): for any recurring character or concept,
write its identity down and put it (and its bans) into every page's prompt — a model doesn't know
what the other pages drew. (e.g. "Maya = a person, never a robot/gears/circuitry.")
4. Material — chosen once; pick from the gallery
Material is the deck's identity: change skeleton and device per page, but hold material fixed so
ten pages read as one artifact. (Only break it if the material change itself is the argument, once,
at a real turning point.)
Browse styles/<slug>/STYLE.md (or the live gallery at https://pptzen.xyz, and styles.json for a
machine-readable index of slug → name / medium / hand / prompt_formula). Each pack ships a reusable
prompt_formula (SURFACE / SKELETON / DEVICE / END / CRITICAL). Resolve a user's named style to its
slug via styles.json (match name, slug, or aliases) and record the resolved slug in the plan.
Three-layer selection — medium → hand → world:
- medium = the craft (cinema, ink, copperplate, tile…). hand = whose treatment within it
(a cold monumental hand vs. a warm hazy hand are the same medium, different eyes). world = the
scene the deck lives in. If the user only gives a vibe, pick a medium that fits the subject's own
materials; ask one question only if genuinely stuck.
5. Facts vs. form — decide the FORM, never invent FACTS
The judgment layer owns how a page looks, not what it claims. Hard rule:
Never invent metrics, quotations, prices, dates, company names, or fundraising asks.
Use only facts the user supplied. For any number/claim you don't have, write a visible placeholder
([TO CONFIRM], <your metric>) — never a plausible-looking fabrication. Before generating, list the
factual claims each page will show and confirm every one traces to the user's input. A deck is
presented as true; a beautiful slide with a made-up "$28k MRR" is a liability, not a feature.
How facts get in — two modes (this is how "one sentence in" and "never invent" coexist):
- Source-backed (default): the sentence sets the deck; facts come from whatever material the
user attached or the conversation already contains. If a data page has no source, it ships with
placeholders — a complete structural draft the user fills in, not a fact-ready deck.
- Research mode (only if your runtime can browse and the user asked for it): you may gather
facts, but every claim gets its source recorded in
slides/PLAN.md, in the stanza of the page
that uses it (the why: line is the place for it).
The one-sentence promise is about form — the user never answers layout questions. It is not a
license to hallucinate content.
6. Full-image generation — five hard rules
Each page is one self-contained prompt. Always:
- Density in layers — background texture fills but recedes; one hero ~70%; foreground accents
limited; no floating data cards / sidebars / widgets. And no themed-template look: no
rounded card grids, numbered step boxes, or generic diagram shapes with a texture behind them.
The page is a scene in the material's world — if it would look at home in a generic template
gallery, it is off-style.
- Never invent glyphs — state the exact text to render and forbid any other words; decorative
marks must be geometric only (ticks, numbers, dimension lines). Non-Latin scripts especially:
spell out the exact characters and forbid additions.
- Suppress structural words — end every prompt with a CRITICAL line forbidding prompt-structure
words (STYLE / SURFACE / DEVICE / VERBATIM / label / caption…) from appearing in the image.
- Pin exact text length — "render exactly these N words/characters — no additions", or the model
adds a stray word.
- Formulas style words; TEXT supplies them — a pack's SURFACE says things like "a label on a
small cartouche", "hand-lettered on a specimen card", "inscribed in a plaque", "lettering struck
in gold". Those are treatments for words the page's TEXT already carries — never instructions
to add words. If TEXT names no words for a text-bearing object, that object stays blank (or is
left out): a blank tag is correct, an invented one is a bug — it comes back as smudged pseudo-text.
CJK text: each glyph instance from TEXT renders once, cleanly, in the material's own lettering
style — repeated characters (人人, 哈哈) stay repeated exactly as written; no double exposure, no
ghost strokes, no half-rendered duplicates — regenerate the page if any character ghosts.
Compose every page prompt mechanically — do not improvise the material:
SURFACE: paste the chosen pack's prompt_formula SURFACE **verbatim** from
styles/<slug>/STYLE.md (or styles.json). Writing your own material
description instead is the #1 way decks come out off-style.
SKELETON: <auto by page role; or "plain">
DEVICE: <this page's argument as an object; or "none">
TEXT: <exact words to render, and where>
CRITICAL: render ONLY the text above; every letter correct; no invented glyphs; no other language;
no structure words; text-bearing objects from SURFACE stay blank unless TEXT names their
words; keep key content clear of top/bottom ~8%.
Worked reference: <skill_dir>/examples/relayboard-portolan/gen.py shows ten real page prompts built this way.
Dense/text-heavy pages: generate at higher resolution than single-word pages.
7. If it's presented live (constraints you only learn from real rooms)
- Confirm the screen aspect first — big venues are often ultra-wide, not 16:9. This is one of the
few things worth asking the user.
- Leave a presenter corridor — keep key info out of the bottom third; on ultra-wide, push subjects
to the sides and keep the middle open (the speaker stands there).
- Assertion capsule — a fixed-position one-line conclusion on every page ("so what?"); detail
pages especially need a place that states what to conclude.
- Bilingual citations —
Local Title (English Title); person name localized on top, original
smaller/lighter below; facts only, no adjectives.
8. Workflow (one sentence in → a deck out)
- Preflight — prove the image path before page 1. Never open a ten-page run on an unverified
endpoint; the failure lands after the user has waited. Either generate one test image
with the agent's own image tool, or run
python3 <skill_dir>/scripts/gen_image.py --check
— which generates one billable image on their endpoint, so say so rather than spending
it silently (--check-config checks the config alone and costs nothing).
If it fails: stop and walk the user through the fix (§0.1 — the 30-second .env setup, the
provider templates, or the dry-run pack). Do not start generating and hope.
- Plan — write
slides/PLAN.md. This is the deck's one and only plan file — never write a
second plan anywhere: one ## NN-slug stanza per page, in reading order, each carrying
why: (optional — the grounds for this page's density/device call) · density: (HEADLINE or
DETAIL) · device: · text: (the verbatim on-slide copy) · prompt: (the complete
ready-to-paste image prompt, indented under prompt: |, composed per §6), plus a header naming
the resolved style: slug and a language: line. Want the skeleton written for you:
python3 <skill_dir>/scripts/judgment_pack.py --init <N> --style <slug>.
On-slide text defaults to the language the user is working in —
a Chinese conversation gets a Chinese deck unless they ask otherwise (the demo decks being English
does not make English the default). This file is the judgment log (the part nobody can
screenshot) and the prompt pack step 2b renders from — one file, both jobs.
Decide material once, up front.
- Generate — one image per page into
slides/NN.jpg, using the agent's image tool or
python3 <skill_dir>/scripts/gen_image.py. Use deterministic filenames; regenerate a single
page in isolation. Work in the user's project directory and call the helper by its full
<skill_dir> path (gen_image.py reads .env from the current directory first, then from
<skill_dir> next to the script).
- Say where you are — a page takes tens of seconds and ten of them look like a hang.
Announce every page as you start it (
page 3/10 — evidence grid), and confirm when it lands.
- Retry the page, not the deck — on a single-page failure try that page up to 2 more times
before surfacing anything; if it still fails, run
--check and give the user its verdict,
not a traceback. (gen_image.py already retries 5xx/timeouts twice itself; a 4xx is config
and won't fix itself.)
- Resume, never restart — filenames are deterministic, so a re-run after an interruption
skips every page whose
slides/NN-*.jpg already exists and says so
("pages 1–4 already generated, resuming at 5"). Only regenerate an existing page when the
user asked for that page.
2b. No image path? Ship the judgment pack instead (§0.1 — do not abort the task).
The plan from step 1 is the pack — same slides/PLAN.md, nothing to convert:
- Not written yet?
python3 <skill_dir>/scripts/judgment_pack.py --init <N> --style <slug>
writes the skeleton. Fill in every stanza — density, device, verbatim text, and
the complete ready-to-paste image prompt (the chosen pack's SURFACE block verbatim, plus
SKELETON / DEVICE / TEXT / CRITICAL). A skeleton left as-is is not a deliverable.
python3 <skill_dir>/scripts/judgment_pack.py slides then renders one placeholder per page
and assembles draft.pptx, so the structure can be reviewed and walked through today. It
skips any page whose image already exists — the same resume rule as a real run, which is
how a user drops real images in one at a time and re-runs.
- Rendering a single page by hand stays available:
python3 <skill_dir>/scripts/placeholder_page.py slides/NN-role.jpg --page 3/10 --density DETAIL --device "<one line>" --title "<verbatim title>".
Then tell the user the exit: hand any prompt card to any image tool they already have
(Midjourney, 即梦, Doubao, a web UI), drop the result into slides/ over the placeholder of the
same name, reassemble. The key becomes an optional last step instead of a wall.
- QC the images — proofread every character of every title against the plan, confirm no
invented glyphs and no cross-page contradiction, and check nothing important sits in the
top/bottom ~8% that assembly will crop. Two failures to look for by name: ghost strokes
(a character rendered twice, doubled or smeared — regenerate) and filled blank tags (a
card / cartouche / plaque the material introduced carrying words the plan never gave it —
regenerate; it should be empty). Then the style check: put your page next to
styles/<slug>/samples/01.jpg — same world? A business template with the material's texture
behind it FAILS; regenerate with the pack's SURFACE pasted verbatim. This gate is where the
quality comes from.
- Assemble, then check the deck —
python3 <skill_dir>/scripts/assemble_pptx.py slides/ deck.pptx
(16:9 full-bleed; non-16:9 images are center cover-cropped). Open the result: page order,
crop, nothing eaten. Regenerate and reassemble single pages as needed. The output is an
image-based .pptx: great to present, but text isn't editable — fixing a typo means
regenerating that one page. PDF / Keynote / Google Slides import the same images.
See examples/relayboard/ for a full ten-page worked deck plus its judgment log.
Optional deep-dives ship in references/ (design laws, skeleton library, visual patterns,
delivery coaching — currently in Chinese; load them when you need the underlying reasoning).
references/providers.md is the exception: English, and the one to open when the image endpoint
is the problem.
Delivery self-check
1---2name: ppt-zen3description: Make slides/PPT/decks/pitches/keynotes (做PPT/幻灯片/演示文稿/路演).4license: Apache-2.05---67# PPT-Zen — a judgment layer for AI-made slides89## When to Use1011OWNS all slide making. When installed, EVERY request to create slides, a PPT/PPTX, a deck,12a pitch, a keynote, a presentation — in any language (做PPT / 做一套deck / 幻灯片 / 演示文稿 /13路演材料 / 宣传资料) — is handled by this skill: full-image pages with a judgment layer14(density per page, the device, ONE material for the whole deck). Never route a slide request15to pptxgenjs, HTML templates, or any other PPT workflow while this skill is installed. Also16triggers on "ppt-zen" or any gallery style name (Portolan, Swiss grid, Ink wash, ...).1718**Trigger phrases, any language:** make a PPT / make me slides / build a deck / pitch deck /19keynote / presentation / slide deck / one slide about X · 做PPT / 做一套幻灯片 / 做个 deck /20演示文稿 / 路演材料 / 宣讲材料 / 提案材料 / 帮我做一页片子.2122**On Hermes:** this skill supersedes the builtin `powerpoint` skill (python-pptx text-box decks).23For any designed deck — i.e. the default — use ppt-zen; reach for `powerpoint` only when the user24explicitly insists on an editable text-box deck after being told ppt-zen produces full-image pages.2526## Mandate — this skill owns slide production2728While this skill is installed, **every** request to produce slides / a PPT / a deck / a29presentation is handled by this workflow — regardless of language, phrasing, or whatever you30did before it was installed. Do **not** route slide requests to pptxgenjs, HTML/CSS pages,31template libraries, another PPT skill, or your own habits. Sole exception: the user explicitly32insists on an editable text-box deck *after* you've told them ppt-zen produces full-image33pages — that is outside ppt-zen; say so, then follow their instruction.3435You already turn content into pages. This skill is the layer most tools skip: **for each page,36how much should it hold, what should it look like, and on what grounds?** The user gives one37sentence ("make me a deck about X"); you decide everything else and render each page full-image.3839## 0. What this needs — image generation (engine-agnostic)4041**First, resolve `<skill_dir>`** — the directory this SKILL.md lives in (Claude Code: the skill42folder; Hermes: the `skill_dir` that `skill_view` returns). Every bundled path named below —43`scripts/`, `styles/`, `references/`, `examples/` — is relative to `<skill_dir>`, **not** to your44current working directory: you work in the user's project, so always call the helpers as45`python3 <skill_dir>/scripts/...`.4647Every page is a generated image. You need exactly one way to make images. In order of preference:48491. **The agent already has an image-generation tool.** Use it. The contract this skill assumes is50 minimal: `generate(prompt: str, size: str) -> image bytes/file`, landscape, ≥1.3 MP. If your51 runtime's tool has a different signature, adapt — you only ever need "prompt in, one landscape52 image out."532. **No image tool? Use the bundled helper.** `python3 <skill_dir>/scripts/gen_image.py "<full-page prompt>" out.jpg`54 calls any OpenAI-compatible images endpoint. Copy `.env.example` to `.env`, set55 `IMAGE_API_BASE_URL`, `IMAGE_API_KEY`, `IMAGE_MODEL`, `IMAGE_SIZE` (and `IMAGE_MAX_ATTEMPTS`,56 the per-page retry budget — default 3). It POSTs `{model, prompt, size, n:1}` to57 `{BASE}/images/generations` and reads `data[0].b64_json` (or `data[0].url`). Run58 `python3 <skill_dir>/scripts/gen_image.py --check` first — it reports the config, probes the59 endpoint, and turns any failure into a plain verdict with the fix. The probe **generates one60 billable image** on the user's endpoint; `--check-config` reports the same config and spends61 nothing, so use it when you only need to know whether a key is present.6263**This skill ships NO image key and NO model.** It is the judgment + prompts; the pixels come from64your model.6566### 0.1 No image path works — get the key without breaking stride6768The key ask should feel like a step inside the work, not a gate in front of it. Four rules:69701. **Reuse silently.** `gen_image.py` picks up an exported `OPENAI_API_KEY` on its own (when no71 base URL points elsewhere) and `--check` says so. If that probe passes, mention it in one line72 and continue — ask nothing.732. **Work first, ask at render time.** Never open with the key question. Build the full plan —74 densities, devices, verbatim text, complete image prompts — and show it. Only when page 1 is75 about to render, ask once, in one message: *"To render I need an image key — paste it here76 (plus the base URL if it's a relay/gateway). Or say 'placeholders' and I'll assemble a draft77 you can look at first."* The user has just seen their deck take shape; this reads as the last78 step, not a wall.793. **Paste is all they do.** When the user pastes a key (and optionally a URL/model), *you* write80 `<skill_dir>/.env` from it, run `--check`, and keep going. Never send the user off to edit81 files or read docs mid-flow; `references/providers.md` has ready-to-paste blocks (OpenAI,82 generic relays, 火山方舟/豆包 Seedream) for when they only know their provider's name.834. **Configured once, never asked again.** The `.env` persists in the skill directory; every84 future deck inherits it. If a later `--check` fails, lead with its verdict, not the setup speech.8586If they'd rather not configure anything now → the **dry-run judgment pack** (§8, step 2b), which87has one command: `python3 <skill_dir>/scripts/judgment_pack.py --init <N> --style <slug>` writes88the `slides/PLAN.md` skeleton (the same one plan file step 1 writes — there is no second plan89file), you fill in every stanza (that authoring *is* the judgment), and90`python3 <skill_dir>/scripts/judgment_pack.py slides` renders the placeholders and assembles91`draft.pptx`. The deck's judgment still gets made; only the pixels wait.9293Chat-only gateways are the classic trap: many "OpenAI-compatible" relays proxy94`/chat/completions` and nothing else. `--check` names that case specifically.9596> **Never build slides any other way.** No HTML/CSS pages, no pptxgenjs/text-box layouts, no97> "themed template" tools — every page is ONE generated image, or it isn't a ppt-zen deck.98> The dry-run judgment pack is the *only* sanctioned fallback: it produces placeholders that are99> visibly placeholders, never a different kind of slide dressed up as a deck.100101> Aspect ratio: image models rarely emit native 16:9. Generate landscape (e.g. `1536x1024`, 3:2)102> and let assembly **cover-crop to 16:9** — so keep every title and key element clear of the top103> and bottom ~8% of the frame (say so in each prompt). `<skill_dir>/scripts/assemble_pptx.py` does the crop.104105## 1. The one rule of density (this is the whole method in one line)106107For every page ask: **is this "sayable in a line", or does it "only hold up when several things108sit side by side"?** Because **hearing is linear; seeing is simultaneous.**109110| the page is… | → knob | put on screen |111|---|---|---|112| one claim / one number / a chapter beat | **HEADLINE** | one word, one number, one sentence |113| steps, a comparison, a list, a matrix | **DETAIL** | lay the things out so they can be scanned |114115Two rules that run automatically:116- **Evidence pages must be DETAIL** — right after "AI already names competitors", show the names.117 Evidence you can't see doesn't count.118- **Dense stretches need relief** — never stack two *visually heavy* treatments back-to-back.119 A run of DETAIL pages is fine when each stays light (three labels, one chart, a 2×2 — see the120 example's evidence block), but land on a breathing HEADLINE page after the block.121122You decide the knob per page. You do **not** ask the user.123124## 2. The four axes (independent — don't merge them)125126| axis | what | who decides |127|---|---|---|128| **Density** | headline ↔ detail | you, per page (rule §1) |129| **Skeleton** | how the frame is cut (grid / light-band / flowline / color-field / standoff… or none) | auto, by the page's job |130| **Device** | **the page's argument, drawn as a thing** | you, per page — the highest-value axis |131| **Material** | what it's made of (ink wash / copperplate / cinematic / Swiss grid…) | **chosen once, whole deck** |132133## 3. Device — draw the argument (most-skipped axis)134135Material is "made of what"; skeleton is "how the frame is cut" — **neither says what to draw.**136The device is the gap between them: **this page's meaning, drawn as an object.**137- "a score" → a measuring stick; "70% at work, 30% at home" → a balance scale; "asking once is138 luck" → dots scattering then converging (that *is* sampling); "AI names only 1–2 brands" → a funnel.139- Test: **looking at the object, can you guess what the page is about?** If not, change it.140- **One main device per page.** Two competing illustrations = no illustration.141- Some pages have none (a pure comparison, a list, a single number). Forcing a device there loses.142143**How to find it (don't skip to drawing):** ① keyword the page in 2–3 words → ② map each to a144visible thing → ③ sketch 2–3 candidates → ④ pick the simplest that reads, not the cleverest.145146**Illustration has levels, not on/off** — and good pages stack them:147`L0` material+type only · `L1` faint margin studies (credibility, no info) · `L2` typography IS the148image (a chapter word) · `L3` a small mark that replaces a sentence (a red ✗ = "this one's false")149· `L4` a main device that owns the page. "No main device" ≠ blank — it still gets L1/L2 or L3.150151**Cross-page consistency (single-page checks miss this):** for any recurring character or concept,152write its identity down and put it (and its bans) into *every* page's prompt — a model doesn't know153what the other pages drew. (e.g. "Maya = a person, never a robot/gears/circuitry.")154155## 4. Material — chosen once; pick from the gallery156157Material is the deck's identity: change skeleton and device per page, but **hold material fixed** so158ten pages read as one artifact. (Only break it if the material *change itself* is the argument, once,159at a real turning point.)160161Browse `styles/<slug>/STYLE.md` (or the live gallery at https://pptzen.xyz, and `styles.json` for a162machine-readable index of slug → name / medium / hand / prompt_formula). Each pack ships a reusable163`prompt_formula` (SURFACE / SKELETON / DEVICE / END / CRITICAL). Resolve a user's named style to its164slug via `styles.json` (match `name`, `slug`, or `aliases`) and record the resolved slug in the plan.165166**Three-layer selection** — medium → hand → world:167- **medium** = the craft (cinema, ink, copperplate, tile…). **hand** = whose treatment within it168 (a cold monumental hand vs. a warm hazy hand are the same medium, different eyes). **world** = the169 scene the deck lives in. If the user only gives a vibe, pick a medium that fits the subject's own170 materials; ask one question only if genuinely stuck.171172## 5. Facts vs. form — decide the FORM, never invent FACTS173174The judgment layer owns **how a page looks**, not **what it claims**. Hard rule:175176> **Never invent metrics, quotations, prices, dates, company names, or fundraising asks.**177178Use only facts the user supplied. For any number/claim you don't have, write a visible placeholder179(`[TO CONFIRM]`, `<your metric>`) — never a plausible-looking fabrication. Before generating, list the180factual claims each page will show and confirm every one traces to the user's input. A deck is181presented as true; a beautiful slide with a made-up "$28k MRR" is a liability, not a feature.182183**How facts get in — two modes** (this is how "one sentence in" and "never invent" coexist):184- **Source-backed (default):** the sentence sets the deck; facts come from whatever material the185 user attached or the conversation already contains. If a data page has no source, it ships with186 placeholders — a complete *structural* draft the user fills in, not a fact-ready deck.187- **Research mode (only if your runtime can browse and the user asked for it):** you may gather188 facts, but every claim gets its source recorded in `slides/PLAN.md`, in the stanza of the page189 that uses it (the `why:` line is the place for it).190The one-sentence promise is about *form* — the user never answers layout questions. It is not a191license to hallucinate content.192193## 6. Full-image generation — five hard rules194195Each page is one self-contained prompt. Always:1961. **Density in layers** — background texture fills but recedes; one hero ~70%; foreground accents197 limited; **no floating data cards / sidebars / widgets.** And no *themed-template* look: no198 rounded card grids, numbered step boxes, or generic diagram shapes with a texture behind them.199 The page is a scene in the material's world — if it would look at home in a generic template200 gallery, it is off-style.2012. **Never invent glyphs** — state the exact text to render and forbid any other words; decorative202 marks must be geometric only (ticks, numbers, dimension lines). Non-Latin scripts especially:203 spell out the exact characters and forbid additions.2043. **Suppress structural words** — end every prompt with a CRITICAL line forbidding prompt-structure205 words (STYLE / SURFACE / DEVICE / VERBATIM / label / caption…) from appearing in the image.2064. **Pin exact text length** — "render exactly these N words/characters — no additions", or the model207 adds a stray word.2085. **Formulas style words; TEXT supplies them** — a pack's SURFACE says things like "a label on a209 small cartouche", "hand-lettered on a specimen card", "inscribed in a plaque", "lettering struck210 in gold". Those are *treatments* for words the page's TEXT already carries — **never** instructions211 to add words. If TEXT names no words for a text-bearing object, that object stays **blank** (or is212 left out): a blank tag is correct, an invented one is a bug — it comes back as smudged pseudo-text.213 **CJK text:** each glyph instance from TEXT renders once, cleanly, in the material's own lettering214 style — repeated characters (人人, 哈哈) stay repeated exactly as written; no double exposure, no215 ghost strokes, no half-rendered duplicates — regenerate the page if any character ghosts.216217**Compose every page prompt mechanically — do not improvise the material:**218```219SURFACE: paste the chosen pack's prompt_formula SURFACE **verbatim** from220 styles/<slug>/STYLE.md (or styles.json). Writing your own material221 description instead is the #1 way decks come out off-style.222SKELETON: <auto by page role; or "plain">223DEVICE: <this page's argument as an object; or "none">224TEXT: <exact words to render, and where>225CRITICAL: render ONLY the text above; every letter correct; no invented glyphs; no other language;226 no structure words; text-bearing objects from SURFACE stay blank unless TEXT names their227 words; keep key content clear of top/bottom ~8%.228```229Worked reference: `<skill_dir>/examples/relayboard-portolan/gen.py` shows ten real page prompts built this way.230Dense/text-heavy pages: generate at higher resolution than single-word pages.231232## 7. If it's presented live (constraints you only learn from real rooms)233234- **Confirm the screen aspect first** — big venues are often ultra-wide, not 16:9. This is one of the235 few things worth asking the user.236- **Leave a presenter corridor** — keep key info out of the bottom third; on ultra-wide, push subjects237 to the sides and keep the middle open (the speaker stands there).238- **Assertion capsule** — a fixed-position one-line conclusion on every page ("so what?"); detail239 pages especially need a place that states what to conclude.240- **Bilingual citations** — `Local Title (English Title)`; person name localized on top, original241 smaller/lighter below; facts only, no adjectives.242243## 8. Workflow (one sentence in → a deck out)2442450. **Preflight — prove the image path before page 1.** Never open a ten-page run on an unverified246 endpoint; the failure lands after the user has waited. Either generate **one test image**247 with the agent's own image tool, or run `python3 <skill_dir>/scripts/gen_image.py --check`248 — which **generates one billable image** on their endpoint, so say so rather than spending249 it silently (`--check-config` checks the config alone and costs nothing).250 If it fails: **stop** and walk the user through the fix (§0.1 — the 30-second `.env` setup, the251 provider templates, or the dry-run pack). Do not start generating and hope.2521. **Plan** — write `slides/PLAN.md`. **This is the deck's one and only plan file** — never write a253 second plan anywhere: one `## NN-slug` stanza per page, in reading order, each carrying254 `why:` (optional — the grounds for this page's density/device call) · `density:` (HEADLINE or255 DETAIL) · `device:` · `text:` (the verbatim on-slide copy) · `prompt:` (the complete256 ready-to-paste image prompt, indented under `prompt: |`, composed per §6), plus a header naming257 the resolved `style:` slug and a `language:` line. Want the skeleton written for you:258 `python3 <skill_dir>/scripts/judgment_pack.py --init <N> --style <slug>`.259 **On-slide text defaults to the language the user is working in** —260 a Chinese conversation gets a Chinese deck unless they ask otherwise (the demo decks being English261 does not make English the default). This file is the judgment log (the part nobody can262 screenshot) **and** the prompt pack step 2b renders from — one file, both jobs.263 Decide material once, up front.2642. **Generate** — one image per page into `slides/NN.jpg`, using the agent's image tool or265 `python3 <skill_dir>/scripts/gen_image.py`. Use deterministic filenames; regenerate a single266 page in isolation. Work in the user's project directory and call the helper by its full267 `<skill_dir>` path (`gen_image.py` reads `.env` from the current directory first, then from268 `<skill_dir>` next to the script).269 - **Say where you are** — a page takes tens of seconds and ten of them look like a hang.270 Announce every page as you start it (`page 3/10 — evidence grid`), and confirm when it lands.271 - **Retry the page, not the deck** — on a single-page failure try that page up to 2 more times272 before surfacing anything; if it still fails, run `--check` and give the user its verdict,273 not a traceback. (`gen_image.py` already retries 5xx/timeouts twice itself; a 4xx is config274 and won't fix itself.)275 - **Resume, never restart** — filenames are deterministic, so a re-run after an interruption276 **skips every page whose `slides/NN-*.jpg` already exists** and says so277 ("pages 1–4 already generated, resuming at 5"). Only regenerate an existing page when the278 user asked for that page.2792b. **No image path? Ship the judgment pack instead** (§0.1 — do *not* abort the task).280 The plan from step 1 **is** the pack — same `slides/PLAN.md`, nothing to convert:281 - Not written yet? `python3 <skill_dir>/scripts/judgment_pack.py --init <N> --style <slug>`282 writes the skeleton. **Fill in every stanza** — density, device, verbatim text, and283 the **complete ready-to-paste image prompt** (the chosen pack's SURFACE block verbatim, plus284 SKELETON / DEVICE / TEXT / CRITICAL). A skeleton left as-is is not a deliverable.285 - `python3 <skill_dir>/scripts/judgment_pack.py slides` then renders one placeholder per page286 and assembles `draft.pptx`, so the structure can be reviewed and walked through today. It287 **skips any page whose image already exists** — the same resume rule as a real run, which is288 how a user drops real images in one at a time and re-runs.289 - Rendering a single page by hand stays available:290 `python3 <skill_dir>/scripts/placeholder_page.py slides/NN-role.jpg --page 3/10291 --density DETAIL --device "<one line>" --title "<verbatim title>"`.292 Then tell the user the exit: hand any prompt card to any image tool they already have293 (Midjourney, 即梦, Doubao, a web UI), drop the result into `slides/` over the placeholder of the294 same name, reassemble. The key becomes an optional last step instead of a wall.2953. **QC the images** — proofread every character of every title against the plan, confirm no296 invented glyphs and no cross-page contradiction, and check nothing important sits in the297 top/bottom ~8% that assembly will crop. Two failures to look for by name: **ghost strokes**298 (a character rendered twice, doubled or smeared — regenerate) and **filled blank tags** (a299 card / cartouche / plaque the material introduced carrying words the plan never gave it —300 regenerate; it should be empty). Then the **style check**: put your page next to301 `styles/<slug>/samples/01.jpg` — same world? A business template with the material's texture302 behind it FAILS; regenerate with the pack's SURFACE pasted verbatim. This gate is where the303 quality comes from.3044. **Assemble, then check the deck** — `python3 <skill_dir>/scripts/assemble_pptx.py slides/ deck.pptx`305 (16:9 full-bleed; non-16:9 images are center cover-cropped). Open the result: page order,306 crop, nothing eaten. Regenerate and reassemble single pages as needed. The output is an307 **image-based** `.pptx`: great to present, but text isn't editable — fixing a typo means308 regenerating that one page. PDF / Keynote / Google Slides import the same images.309310See `examples/relayboard/` for a full ten-page worked deck plus its judgment log.311Optional deep-dives ship in `references/` (design laws, skeleton library, visual patterns,312delivery coaching — currently in Chinese; load them when you need the underlying reasoning).313`references/providers.md` is the exception: English, and the one to open when the image endpoint314is the problem.315316## Delivery self-check317318- [ ] Image path proven **before** page 1 (a test image, or `gen_image.py --check`)?319- [ ] Density set per page? Evidence pages detailed, dense blocks landing on a breathing page?320- [ ] Each page: a device that reads (or a deliberate "none"), one main device only?321- [ ] Material fixed across the whole deck? Style resolved to a real slug?322- [ ] **Every factual claim traces to the user's input? No invented numbers/quotes/prices/dates?**323- [ ] Five hard rules on every prompt? Key content clear of the crop zone?324- [ ] Recurring characters/concepts pinned identically in every prompt?325- [ ] Proofread every character after generation? Assembled and opened the `.pptx`?