Eleven skills for conference speakers covering rhetoric analysis, talk authoring, deck building and export, CFP submissions, publishing, illustrations, shownotes, and screencast production, informed by a 113-entry Presentation Patterns taxonomy (83 observable: 64 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns).
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Reference for Step 4 (deck illustrations) and Step 6 (apply to deck) in
SKILL.md. The illustration-rules and title-overlay-rules steering rules
are auto-loaded — apply them, don't restate them.
Before generating, ensure:
Lane and credentials — --image-lane auto prefers a compatible
subscription CLI. Existing pinned-model/exact-size requests use API;
--allow-cli-native explicitly permits OpenAI's unpinned native model and
observed dimensions. Force HTTP with --image-lane api, or require native
Codex with --image-lane cli --allow-cli-native. Gemini and Imagen remain
API-only. See image-provider-lanes.md for the
capability/authentication boundary and diagnostics.
API requests dispatch by model-name prefix:
gpt-image-* → OpenAI; imagen-* and gemini-* / nano-banana-* →
Google. Add whichever keys the run will actually use to
{vault}/secrets.json (preferred):
{
"gemini": { "api_key": "your-google-key" },
"openai": { "api_key": "your-openai-key" }
}Only vendors that select API need keys. Native-only runs never read
secrets.json or require an API key. Mixed comparison/exploration runs check
each API vendor on first use; provide those keys before starting to avoid
a partially rendered grid. A present but failing CLI never retries API.
Env-var fallbacks: GEMINI_API_KEY, OPENAI_API_KEY. Get keys from
https://aistudio.google.com/app/apikey (Google) and
https://platform.openai.com/api-keys (OpenAI).
Model availability — verify the baked model is accessible with your key.
The script reads it from outline.yaml's style_anchor.model field.
Imagen models have no edit endpoint — --edit, --build, and --fix
require a Gemini or OpenAI model.
Python 3.10+ — install the project's declared dependencies from
pyproject.toml. API-only plain generation uses the standard library;
masked edits need Pillow. The native lane also uses the co-shipped process
supervisor and its declared psutil dependency.
python3 "{speaker_toolkit_root}/skills/illustrations/scripts/generate-illustrations.py" outline.yaml remainingremaining skips slides whose images already exist; all regenerates every
slide; specific slides can be passed as 2 5 9 or a range 2-10.
Phase 2 strategy uses --style-explore (renders candidate styles × the
priority-driven model shortlist × formats into a structured style-explore/
grid) — see strategy.md Sub-steps 3 and 5.
--compare remains a quick single-slide model spot-check: it renders one
slide's prompt across the cached COMPARE_MODELS roster.
python3 "{speaker_toolkit_root}/skills/illustrations/scripts/generate-illustrations.py" outline.yaml --compare 2Output lands in illustrations/model-comparison/. The roster, vendor aliases,
and per-model attributes live in skills/illustrations/scripts/model_registry.py.
A slide that depicts a real person, such as the speaker's bio plate, can name
real photos of that person in outline.yaml:
- n: 2
format: FULL
text_overlay: "none"
image_prompt: |
[STYLE ANCHOR]. A field-guide engraving of the speaker in his signature hat.
reference_images:
- photos/speaker.jpg # relative to the talk directory, inside it
- /Users/me/photos/side.png # or absoluteField contract (owned by presentation-creator's outline_schema.py): outline
schema 3, up to four entries, each a .jpg / .jpeg / .png / .webp file
that decodes as that format, on a slide with an image_prompt. Every outline
load validates the files and names the fix for a missing, escaping, undecodable
or misnamed photo.
| Command | Reference photos |
|---|---|
all / remaining / N / -v N | Sent as image inputs |
--compare N | Sent to every compared model |
--style-explore | Not sent; a stderr warning names the slide |
--edit / --fix / --build | Not sent; they edit the rendered image, which already carries the likeness |
Re-render one slide as a new version, leaving the current image in place:
python3 "{speaker_toolkit_root}/skills/illustrations/scripts/generate-illustrations.py" outline.yaml -v 2Providers and lanes:
gpt-image-*: the photos go to /images/edits (image for one,
repeated image[] for several) with the slide's prompt and size.generateContent as inline image
parts ahead of the prompt.--image-lane auto stays on API and reports
cli_likeness_reference_unverified; --image-lane cli refuses with that
reason. The Codex adapter can only edit its one reference.The prompt gains a LIKENESS REFERENCE note after the safe-zone or poster
directives: the photos guide facial likeness only, the scene decides pose,
clothing and props, everything renders in the slide's style anchor medium, and
the photo is never pasted in. It is graphic-composition framing per
thumbnail-generation-rules §6. Poster-theatrical slides keep their embedded
title and footer directives. Put the hat, glasses and other signature items in
the image_prompt too; the photo alone does not decide clothing.
| Command | When to use | Output |
|---|---|---|
--edit N "<prompt>" | Removing content from an existing image | slide-NN-vM.ext |
--fix N "<prompt>" | Iterating on a near-perfect image (90%+ correct) | slide-NN-vM.ext (next version) |
-v 2 5 9 | Generate without overwriting the base image | slide-NN-vM.ext |
--edit and --fix auto-append the safety suffixes (DO NOT add any new elements, Let background continue naturally). The explicit preservation
list (Keep the X. Keep the Y.) must always be added manually — the script
cannot know what to preserve.
Each slide's format field defines its format code. The
apply-illustrations-to-deck.py script maps each code to a layout +
positioning:
| Outline Format | Layout | Image Handling |
|---|---|---|
FULL | BLANK | Full-bleed image at 16:9 slide dimensions (left=0, top=0, width=13.333", height=7.5"); title repositioned into the declared Safe zone |
FULL + text overlay | BLANK | Full-bleed image + text overlay |
IMG+TXT | TITLE only (no body) | Image ~60% of slide on the left, title + body on the right. Exact geometry is owned by the IMGTXT_* constants in skills/illustrations/scripts/apply-illustrations-to-deck.py (image left=0.3", top=0.8", width=8.0", height=5.9"; text column left=8.5", width≈4.5") — read the constants when debugging layout, not the table |
EXCEPTION | Per content type | No generated image — real asset from [IMAGE NN] placeholder; handled by presentation-creator's slide walk, not by this skill |
{talk-dir}/illustrations/
├── slide-01.jpg ← one file per illustrated slide
├── slide-02.png
├── slide-05-v2.jpg ← versioned iterations (--fix / --edit / -v)
├── builds/ ← progressive reveal build steps (see builds.md)
│ ├── slide-05-build-00.jpg
│ ├── slide-05-build-01.jpg
│ └── slide-05-build-02.jpg
└── model-comparison/ ← --compare output
{talk-dir}/style-explore/ ← --style-explore output (Phase 2 strategy)
├── candidates.json ← agent-written input (styles × shortlist × formats)
├── index.md ← contact sheet grouping every render by style
└── <style-slug>/<format>/<model>.<ext>The Safe zone: line in each FULL slide block tells the script to append a
TITLE SAFE ZONE directive to the prompt before generation. Five zones are
supported: upper_third, middle_third, lower_third, left_half,
right_half. See skills/illustrations/references/title-placement.md
for the outline schema and rules/title-overlay-rules.md
for the full policy (auto-loaded).
python3 "{speaker_toolkit_root}/skills/illustrations/scripts/apply-illustrations-to-deck.py" \
deck.pptx illustrations/ outline.yaml \
--out deck-with-titles.pptx \
--scrim-color 100903 --scrim-alpha 47553 # omit for plain 45% blackThe script:
Safe zone: field), records the illustration in a
backgrounds manifest (--backgrounds-out, default <out_stem>.backgrounds.json)
for the PowerPoint background pass below — it does NOT insert a picture shape.format: IMG+TXT, applies the IMG+TXT layout
(image ~60% on the left as a picture shape, title placeholder + body on the right).builds: block.Then set the FULL-slide backgrounds via the real PowerPoint app, so each illustration becomes the slide BACKGROUND FILL (covered by the layout's halftone-dot overlay) and survives — a python-pptx round-trip would drop it. Run this as the FINAL write of the build, AFTER speaker notes are injected:
# operate on a uniquely-named copy — PowerPoint keys open decks by filename
cp deck-with-titles.pptx deck-bg-src.pptx
bash "{speaker_toolkit_root}/skills/presentation-creator/scripts/apply-backgrounds.sh" \
deck-bg-src.pptx deck-final.pptx deck-with-titles.backgrounds.jsonmacOS + Microsoft PowerPoint only; see rules/deck-editing-rules.md.
If no scrim color is supplied, run python3 "{speaker_toolkit_root}/skills/illustrations/scripts/suggest-scrim-color.py" illustrations/
first to sample a deck-tuned color. For warm or cool styled decks, the
sampled color reads as "deeper shadow in the same style" instead of a flat
black film.
.tessl-plugin
rules
skills
cfp-writer
references
illustrations
presentation-builder
presentation-creator
references
patterns
build
deliver
prepare
scripts
presentation-publisher
screencast-editor
screencast-recorder
shownotes-publisher
vault-clarification
vault-ingress
references
scripts
vault-profile