CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/speaker-toolkit

Six-skill presentation system: ingest talks into a rhetoric vault, run interactive clarification, generate a speaker profile, create presentations that match your documented patterns, produce the deck illustrations + thumbnail visual layer, and publish talk pages to a Jekyll shownotes site. Includes a 111-entry Presentation Patterns taxonomy (81 observable: 62 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns) for scoring, brainstorming, and go-live preparation.

Quality

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

thumbnails.mdskills/illustrations/references/

Thumbnail Generation — Detail

Reference for Step 7 (thumbnail) in SKILL.md. The thumbnail-generation-rules steering rule is auto-loaded — apply it, don't restate it.

Pre-Flight

Before any thumbnail work, confirm the inputs:

  1. speaker-profile.jsonpublishing_process.thumbnail config and visual_style_history.
  2. secrets.json — Gemini API key.
  3. presentation-spec.md — talk slug, metadata.
  4. outline.yaml — slide references; the style_anchor block (if present) feeds --portrait-style.
  5. YouTube video URL — provided by the speaker at trigger time.
  6. Tracking database — load through the ingress owner's strict reader and retain its SHA-256. Use the exact non-empty config.python_path for the mutation in Sub-step 10. Missing or invalid config stops this flow and invokes Skill(skill: "vault-ingress") at Step 1.

Set host_python to the current host's explicit absolute interpreter path (not a PATH lookup). The sole interpreter-bootstrap exception is one stdlib-only owner read:

"{host_python}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/read-tracking-database.py" \
  "~/.claude/rhetoric-knowledge-vault/tracking-database.json"

Resolve vault_root and python_path from that report, then immediately repeat the read with "{python_path}" against the resolved database and require the same database bytes/SHA-256. The unconfigured host_python is authorized only for the first owner-reader invocation. Every command below uses the configured interpreter; never fall back to a PATH interpreter.

Read tracking-database.json through the vault path used by presentation-creator. Selection and composition may read legacy database schema 0 or current schema 1 without mutation. Before copying the approved thumbnail or writing tracking state, require database schema 1, current independent records, and talk schema 5. Invoke Skill(skill: "vault-ingress") for schema 0 and stop this run. Unknown future generations are no usable prior state. Preserve every schema field and use the presentation-creator exact-generation atomic-write contract.

If shownotes are needed too (Step 7.2 in presentation-creator) and don't exist yet, STOP and ask before generating the thumbnail.

Sub-step 1: Slide Selection

Scan the outline for high-impact slides. Suggest 3–5 candidates ranked by visual engagement:

  • Illustrations — highest impact, already designed for visual punch.
  • Bold claims / provocative statements — text that triggers curiosity.
  • Key diagrams / architecture visuals — concrete and recognizable.
  • Demo screenshots — when the demo is the main attraction.

Avoid: bio slides, shownotes URL slides, bullet-heavy slides, generic titles.

Present candidates to the speaker with slide numbers and brief descriptions. The speaker picks one — never auto-select.

Sub-step 2: Slide Image Resolution

Resolution chain:

  1. Existing illustration (preferred) — check illustrations/ for slide-{NN}.* matching the chosen slide.
  2. PPTX extraction — use the helper mode:
    "{python_path}" "{speaker_toolkit_root}/skills/illustrations/scripts/generate-thumbnail.py" \
      --extract-slide deck.pptx 15 --output slide-15.png
    Uses LibreOffice headless or PowerPoint AppleScript on macOS.
  3. Ask the speaker — if extraction fails, request a screenshot or exported image of the slide.

Sub-step 3: Speaker Photo

Resolution order:

  1. publishing_process.thumbnail.speaker_photo_path from speaker profile.
  2. Ask the speaker to provide a path or URL.

The photo must be a real photograph — never AI-generated. Expression should convey engagement and energy, not a neutral corporate headshot.

Sub-step 4: Hook Title Text

NOT the full talk title. A 3–5 word hook designed for thumbnail readability at small sizes.

  • Propose 2–3 options based on the talk's thesis and key claim.
  • The speaker confirms or edits.
  • ALL CAPS is standard.
  • Must be readable at 160×90 pixels (YouTube search-result size).

Sub-step 5: Aesthetic Selection

Walk the precedence chain (thumbnail-generation-rules Rule 7):

  1. publishing_process.thumbnail.aesthetic_preference — explicit speaker preference ("photo" or "comic_book"). Honor it and stop.
  2. visual_style_history.default_illustration_style — fuzzy-match against the comic-book family (comic_book / comic-book / halftone / illustrated / cartoon / caricature) → recommend comic_book. Documented styles outside that set (retro_tech_manual, watercolor, etc.) → out-of-scope; ask the speaker before generating.
  3. visual_style_history.confirmed_visual_intents — same fuzzy-match against each entry's pattern and rule fields.
  4. Default → photo.

Lead with the recommended aesthetic. Offer a two-candidate side-by-side only when the speaker is genuinely undecided — not as a default. Comic-book is high-variance: when it works, CTR rises significantly; when it misses, it looks off-brand.

Sub-step 6: Pass Through the Deck's Style Anchor

If outline.yaml has a style_anchor block (with full / imgtxt anchor paragraphs), pass the matching format's anchor paragraph to generate-thumbnail.py via --portrait-style "<anchor>". The script pre-stylizes the speaker photo into the anchor's medium (sepia tech-manual, watercolor, pen-and-ink, etc.) before composition, so the output palette matches the deck. Without this pass-through, photographic skin tones beside an illustrated background produce a jarring two-medium composite even when the aesthetic is otherwise correct.

If Phase 2 didn't produce a style anchor (stock-image-only deck), omit --portrait-style.

Sub-step 7: Generate

# Single recommended candidate (the precedence-chain winner)
"{python_path}" "{speaker_toolkit_root}/skills/illustrations/scripts/generate-thumbnail.py" \
  --slide-image illustrations/slide-15.png \
  --speaker-photo ~/photos/headshot.jpg \
  --title "JUDGMENT DAY" \
  --subtitle "DevNexus 2026" \
  --vault ~/.claude/rhetoric-knowledge-vault \
  --aesthetic <photo|comic_book> \
  --style slide_dominant \
  --title-position top \
  --brand-colors "#5B2C6F,#C0392B" \
  --output thumbnail.png

# Anchor-matched (when the deck has a style_anchor block)
"{python_path}" "{speaker_toolkit_root}/skills/illustrations/scripts/generate-thumbnail.py" \
  --slide-image illustrations/slide-15.png \
  --speaker-photo ~/photos/headshot.jpg \
  --title "JUDGMENT DAY" \
  --aesthetic photo \
  --portrait-style "<full anchor paragraph>" \
  --output thumbnail-anchored.png

Apply other speaker preferences from publishing_process.thumbnail:

  • style_preference--style
  • title_position--title-position
  • brand_colors--brand-colors

aesthetic_preference is consumed at Sub-step 5 — don't re-apply it.

The script (per invocation, runs once per --aesthetic):

  • Sends slide image + speaker photo + prompt to Gemini as multimodal input.
  • Uses the researched prompt strategy per the chosen aesthetic.
  • Validates output: exactly 1280×720, <2MB, PNG preferred.
  • Saves to the specified output path (default: thumbnail.png in the illustrations dir).

Sub-step 8: Speaker Review

Present the generated thumbnail. If rejected, iterate — never regenerate from scratch:

  • "Face looks wrong" → adjust style variant or try a different slide image. Don't add face-preservation language (it trips Gemini's safety filter on photo aesthetic).
  • "Text is unreadable" → increase contrast, change --title-position.
  • "Too busy" → switch to a simpler style variant.
  • "Wrong mood" → adjust expression guidance in the prompt.

Sub-step 9: Copy Thumbnail to Shownotes Site

If publishing_process.shownotes.enabled is true, the SSG template expects the thumbnail at a specific path relative to the shownotes site root — otherwise the live page falls back to a placeholder with no warning.

Resolve the destination using publishing_process.shownotes:

{shownotes.source.path_or_url}/{shownotes.thumbnail_path_template}

with {slug} substituted from the Presentation Spec. For Jekyll-based shownotes the default template is assets/images/thumbnails/{slug}-thumbnail.png — the nested thumbnails/ subdirectory AND the -thumbnail suffix are both mandatory. Do not strip either.

Create the thumbnails/ directory if it doesn't exist, then copy (don't move) the generated thumbnail. The local copy in illustrations/thumbnail.png stays with the talk's working directory for tracking.

If shownotes.ssg_template_pointer is set, read that file after a site redesign to re-derive the path convention. Don't reinvent it from folklore.

Sub-step 10: Tracking Database Update

Prepare this complete thumbnails[] record:

{
  "schema_version": 1,
  "talk_slug": "judgment-day",
  "youtube_url": "https://youtube.com/watch?v=...",
  "source_slide_num": 15,
  "speaker_photo_used": "/path/to/headshot.jpg",
  "thumbnail_path": "illustrations/thumbnail.png",
  "shownotes_thumbnail_path": "assets/images/thumbnails/judgment-day-thumbnail.png",
  "dimensions": "1280x720",
  "file_size_kb": 185,
  "created_at": "2026-04-20",
  "approved": true
}

Persist it with the ingress owner's upsert_thumbnail mutation, expecting the exact existing record for the slug or {"$missing": true}. In the same plan, use update_talk_publishing to set thumbnail_generated: true on the exact talk filename, expecting its current value. Dry-run the whole plan, review it, apply against the reported input SHA, and re-read as specified by the owner mutation contract. Keep that talk at schema_version: 5. illustrations is an authorized writer of current thumbnail and talk records; vault-ingress remains their schema owner. Never rewrite tracking-database.json directly.

skills

README.md

tile.json