/slide-deck — Draft, update, convert, and export branded React decks
Authors React/TypeScript decks for
${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site}/src/app/slides/<slug>/page.tsx
using the user's slide system. Branded output (no separate HTML pipeline) — when portable HTML/PDF is needed, export mode snapshots the rendered React deck via Playwright so the output is brand-perfect.
Modes (pick one before Step 1)
| Mode | Invocation | Goal |
|---|
| new | (default) | Draft a new deck from a brief |
| update | /slide-deck update <slug>
| Modify an existing deck (with overflow guards) |
| ppt | /slide-deck ppt <path-to-pptx>
| Convert a legacy PPTX into a React deck |
| export | /slide-deck export <slug> [html|pdf|vercel]
| Snapshot a deck to HTML, PDF, or Vercel URL |
For
,
, and
, skip to the corresponding mode section below. For
, continue through Steps 1–8.
Step 1 — Capture the brief (ask all at once)
Ask in one structured message. Don't round-trip on each.
- Topic / title — what's the deck about?
- Audience — who's in the room? (technical / executive / mixed / clients) Push for specificity: "founders" is too broad; "B2B SaaS founders at MicroConf" is workable.
- Length — rough slide count: 5–10 (lightning / short internal) / 10–15 (short keynote, pitch) / 20–25 (keynote) / 30+ (workshop — uncommon for branded decks).
- Density — speaker-led (1 idea/slide, big type, lots of breathing room, more slides if needed) or reading-first (4–6 bullets/slide, structured grids, self-contained for async review).
- CTA — what should the audience do/think/feel after?
- Slug — kebab-case (e.g.,
marketing-like-an-engineer
).
- Content state — all content ready / rough notes / topic only.
Remember density — it affects slide count, copy length per slide, and which primitives to favor. See
references/narrative-and-voice.md
for the density-specific rules.
Step 2 — Three narrative angles
Riff on
zarazhangrui/frontend-slides
' "show, don't tell" — but applied to
story, not visuals (your visual system is fixed).
Pitch 3 angles in 1–2 sentences each:
- Safe — most likely to land. Conventional structure for the audience.
- Bold — contrarian or counterintuitive frame. Higher upside, slight risk.
- Wildcard — unexpected structure (story-first, single-question deck, anti-thesis, etc.).
the user picks one. If he rejects all three, propose three more — don't force a path.
Step 3 — Outline
For the chosen angle:
- Sections — propose 3–7 named sections (e.g., , , , , , ). The default 3-act structure is OPTIONAL; only use it if the user wants it or the deck is a keynote-length talk that benefits from one.
- Slide titles within each section
- One-line takeaway per slide
Total slide count should match the duration estimate from Step 1.
Show the outline as a table. the user edits / approves before expand.
Step 4 — Expand to slide content
For each slide, write the full content using his primitives. Reference
for the primitive vocabulary and
references/narrative-and-voice.md
for hook patterns and voice rules.
Slide types and which primitives fit:
| Slide type | Primitives | Pattern |
|---|
| Title | + with keyword | First slide, sets brand and topic |
| Hook | + | A take, story open, contrarian frame, or specific stat |
| Section divider | + (centered, large) | Clean break between sections |
| Framework | + or custom layout | The thing the user's teaching |
| Two-column | | Comparison, before/after, problem/solution |
| Quote / pull-quote | (large) | Authority or audience-recognition moment |
| Resource / link | + URL on its own line | Outbound (rare — the user's voice says minimize) |
| Close / CTA | + + for next steps | What the audience should do |
Voice anchors — write for the ear, not the page (see
for full rules):
- Decks are spoken aloud. Slide text + speaker notes both get said out loud. Write as you'd talk.
- Read every slide out loud before saving. If you stumble, if it sounds like a press release, rewrite.
- Contractions everywhere (don't, won't, you're, I'd). Strip them only on reading-first decks.
- "You" — never "the audience," "users," "people."
- Numbers said naturally ("a quarter" not "23.7%").
- Conviction-coded, listener-perspective, short sentences, specific nouns.
- No filler ("Today I want to talk about…") — open with a take.
- (Reading-first density mode exception: written voice is fine since no one will speak the slides — see .)
Step 5 — Speaker notes
Every slide gets 3–5 notes lines. Notes are the full spoken talk — write them the way you'd actually say them, pauses and asides included. Slide text is the headline; notes are the full thought.
Notes structure:
- The opener — what you say when the slide comes up
- The point — the one idea this slide is making
- The supporting beat — example, data, or color
- The transition — how this connects to the next slide
- (Optional) The aside — a quip or callback
For title slides and section dividers, 2–3 notes is fine.
Step 6 — Generate files
Write to
${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site}/src/app/slides/<slug>/
:
- — Next.js layout with metadata (use the deck title)
- — the slide deck
Use the templates in
as the skeleton.
- Have at the top
- Import and type from
@/components/slides/slide-deck
- Import from
@/components/slides/sections
(only if using sections)
- Import the primitives the user uses from
@/components/slides/slide-primitives
- Declare
const slides: Slide[] = [...]
- (Optional) Declare
const sections: SectionRange[] = [...]
with 0-indexed /
- Export default a component that returns
<SlideDeck slides={slides} sections={sections} />
Step 7 — Preview
After writing the files, check if your slide-deck dev server is running.
bash
lsof -i :3000-3099 2>/dev/null | grep -E "LISTEN" | head
If a port is in use (portless-compatible — check
for the dev script naming):
bash
# Suggested URL pattern
echo "Preview at: http://${SLIDE_DECK_DEV_HOST:-localhost:3000}/slides/<slug>"
If no dev server is running, tell the user:
bash
cd ${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site} && npm run dev
# then visit http://${SLIDE_DECK_DEV_HOST:-localhost:3000}/slides/<slug>
Don't auto-start the dev server (might disrupt other work).
Step 8 — Archive
Append a one-liner to
references/decks-archive.md
(create if missing):
markdown
- 2026-06-17 — [<title>](${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site}/src/app/slides/<slug>/page.tsx) — <audience> — <one-line angle>
This compounds — future decks can grep "what talks have I done about X" to avoid repetition and find reusable patterns.
Mode: update
Modify an existing deck without breaking it. Risks: overflowing slides, exceeding density limits, breaking the section ranges.
Before modifying, check:
- Read the existing
- Count slides + identify the section ranges
- For each modification, apply the right guard:
| Change | Guard |
|---|
| Adding bullets | Max 6 per in reading-first; 3 in speaker-led. If exceeded → split into two slides. |
| Adding text | If paragraph >2 sentences in speaker-led → split. >5 sentences in reading-first → split. |
| Adding images | Images must fit in the 1920×1080 stage. If the slide already has heavy content, move image to its own slide. |
| Adding slides | Update array — increment / for all sections after the insertion point. |
| Removing slides | Decrement / for sections after the removal. Watch for orphaned references. |
| Rewriting a slide | Preserve the (used for anchors). Only change and . |
After modifying:
- Re-count slides and verify section ranges sum correctly
- Spot-check the visual in the dev server before committing
Mode: ppt
Convert a legacy PPTX (client deck, conference template) into the user's React system.
-
Extract content via
and
:
bash
pip install python-pptx 2>/dev/null
python3 -c "
from pptx import Presentation
import json, sys
p = Presentation(sys.argv[1])
out = []
for i, s in enumerate(p.slides):
title = next((sh.text for sh in s.shapes if sh.has_text_frame and sh.shapes_element.tag.endswith('}sp') == False), '')
texts = [sh.text for sh in s.shapes if sh.has_text_frame]
notes = s.notes_slide.notes_text_frame.text if s.has_notes_slide else ''
out.append({'i': i, 'texts': texts, 'notes': notes})
print(json.dumps(out, indent=2))
" "<path-to-pptx>"
See
references/ppt-conversion.md
for the full extraction + mapping recipe.
-
Show the user the extracted summary — slide titles, content excerpts, image count. Confirm before proceeding.
-
Map to React primitives:
- First slide → title pattern (Eyebrow + h1 + Accent)
- Content slides with bullets →
- Comparison slides →
- Section breaks (title-only slides in PPTX) → section divider pattern
- Speaker notes from PPTX → array on each slide
-
Images — copy referenced images from PPTX assets to
${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site}/public/slide-assets/<slug>/
, reference them in slides via
<img src="/slide-assets/<slug>/<filename>" />
inside the
.
-
Write + per the new-deck flow (Step 6).
-
Preserve the original PPTX — never modify in place. Save under
~/Documents/slide-conversions/<slug>-from-pptx/
with the original file + extracted JSON for audit.
Mode: export
Snapshot a deck rendered in the corey.co dev server to portable HTML / PDF / Vercel URL. Output is brand-perfect because it's screenshots of your actual rendered React deck.
Output options:
- — standalone HTML file with snapshots as inline , keyboard nav (arrow keys) baked in
- — combined slide snapshots
- — push standalone HTML to a Vercel project for a shareable URL
- Verify dev server: confirm
${SLIDE_DECK_DEV_HOST:-localhost:3000}/slides/<slug>
loads. If not, prompt the user to cd ${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site} && npm run dev
.
- Count slides: read , count entries in the array.
- Run Playwright snapshot:
bash
bash references/export.md script: snapshot-deck <slug> <count>
- Launches headless Chromium at 1920×1080
- Loads
http://${SLIDE_DECK_DEV_HOST:-localhost:3000}/slides/<slug>?present=1
(presenter mode hides chrome)
- Sets
localStorage["slides:/slides/<slug>"] = "0"
to start at slide 0
- Loops: screenshot → keyboard ArrowRight → wait — for N slides
- Saves PNGs to
~/Documents/slide-exports/<slug>-<YYYY-MM-DD>/slide-<n>.png
- Combine per output type:
- → wrap snapshots in a minimal HTML shell with arrow-key navigation
- → use (ImageMagick) or to combine PNGs
- →
vercel deploy ~/Documents/slide-exports/<slug>-<date>/
- Report path / URL.
Caveats (mention to the user):
- Animations and presenter view are not preserved — exports are static snapshots.
- For interactive demo, present the React version live; for sharing/PDF/portable, use exports.
- Snapshots are 1920×1080 — high-quality on any device, but file size scales with slide count.
Modes (quick invocations)
| Invocation | Mode | Behavior |
|---|
| new | Full pipeline (Steps 1–8) |
/slide-deck angles <topic>
| new | Stop at Step 2 (just the 3 angles) |
/slide-deck outline <topic>
| new | Stop at Step 3 (outline only) |
/slide-deck expand <slug>
| new | Skip to Step 4 from an existing outline |
| update | Rewrite speaker notes for an existing deck |
/slide-deck rewrite <slug> <slide-id>
| update | Edit one slide |
/slide-deck update <slug>
| update | General modification with overflow guards |
/slide-deck ppt <pptx-path>
| ppt | Convert legacy PPTX → React deck |
/slide-deck export <slug> html
| export | Snapshot to standalone HTML |
/slide-deck export <slug> pdf
| export | Snapshot to PDF |
/slide-deck export <slug> vercel
| export | Snapshot + Vercel deploy → shareable URL |
/slide-deck preview <slug>
| — | Just check the deck URL |
Composes with
- — if a pitch deck, brainstorm the offer first; deck draws from the brief
- — for talks that hinge on a decision (e.g., "should I take VC money?"), first
- — for talks needing data the deck doesn't have yet
- — pull relevant pages as content sources; the deck can cite them
- — turn a podcast episode, Loom, or talk recording into a deck outline (run in mode to also capture key moments + slides shown)
- — once delivered, the talk becomes promo angles for the BIP rotation
- (external) — for non-branded HTML decks where your React deck repo isn't the home
Notes on quality
- Show, don't tell — applied to narrative. Present 3 different angles for the deck (not one polished draft); let the user pick. Committing to a narrative before the alternatives are surfaced produces decks that are workmanlike, not memorable.
- Density modes matter more than aesthetic. A speaker-led deck has 3-word slides and 5-line speaker notes. A reading-first deck (leave-behind, async) reverses it. Same content, opposite artifact. Ask which mode before drafting.
- Slide text is abbreviated spoken. Both pass the read-aloud test. If a slide reads like a memo, it's wrong. If speaker notes read like slides, they're wrong.
- Overflow guards on update mode. Don't blindly cram more content into an existing slide — if the addition tips the slide over its target word count or line count, propose splitting the slide or trimming existing content. Silently overflowing produces cramped decks.
- Presenter-view stripped for exports. Playwright snapshots the mode so the export is clean. Never export the presenter view.
- Brand-perfect > portable. The React deck is the source of truth. HTML/PDF/Vercel exports are snapshots for sharing — animations, interactions, presenter view live only in the React version.
- 1920×1080 default, 1280×720 for previews. Full-res snapshots run 30-50 MB for a 20-slide deck; low-res halves that at minimal visual loss.
- Deploy is a real-money operation. Export mode's path prompts before deploying. Auto-renew is on for domains + Vercel projects.