CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

jbaruch/speaker-toolkit

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).

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

generation.mdskills/illustrations/references/

Deck Illustration Generation — Detail

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.

Setup

Before generating, ensure:

  1. 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).

  2. 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.

  3. 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.

Slide Selection Modes

python3 "{speaker_toolkit_root}/skills/illustrations/scripts/generate-illustrations.py" outline.yaml remaining

remaining skips slides whose images already exist; all regenerates every slide; specific slides can be passed as 2 5 9 or a range 2-10.

Model & Style Selection

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 2

Output lands in illustrations/model-comparison/. The roster, vendor aliases, and per-model attributes live in skills/illustrations/scripts/model_registry.py.

Likeness References

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 absolute

Field 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.

CommandReference photos
all / remaining / N / -v NSent as image inputs
--compare NSent to every compared model
--style-exploreNot sent; a stderr warning names the slide
--edit / --fix / --buildNot 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 2

Providers and lanes:

  • OpenAI gpt-image-*: the photos go to /images/edits (image for one, repeated image[] for several) with the slide's prompt and size.
  • Gemini / Nano Banana: the photos go to generateContent as inline image parts ahead of the prompt.
  • Imagen: refused; it has no image input. Bake a Gemini or OpenAI model.
  • API lane only. --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.

Edit / Fix / Versioned Generation

CommandWhen to useOutput
--edit N "<prompt>"Removing content from an existing imageslide-NN-vM.ext
--fix N "<prompt>"Iterating on a near-perfect image (90%+ correct)slide-NN-vM.ext (next version)
-v 2 5 9Generate without overwriting the base imageslide-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.

Slide Format Vocabulary

Each slide's format field defines its format code. The apply-illustrations-to-deck.py script maps each code to a layout + positioning:

Outline FormatLayoutImage Handling
FULLBLANKFull-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 overlayBLANKFull-bleed image + text overlay
IMG+TXTTITLE 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
EXCEPTIONPer content typeNo generated image — real asset from [IMAGE NN] placeholder; handled by presentation-creator's slide walk, not by this skill

File Layout

{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>

Title Safe Zone

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).

Apply to Deck

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% black

The script:

  1. For each FULL slide (a 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.
  2. Adds a zone-sized scrim rectangle above the (later) background and below the title.
  3. Repositions title text boxes into the declared safe zone.
  4. For each slide with format: IMG+TXT, applies the IMG+TXT layout (image ~60% on the left as a picture shape, title placeholder + body on the right).
  5. Inserts build sequences (see skills/illustrations/references/builds.md) for any slide with a 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.json

macOS + 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.

skills

README.md

tile.json