coreyhaines31/slide-deck
When you want to draft, update, convert, or export a slide deck for a React/Next.js slide system (${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site}/src/app/slides/). Writes TypeScript Slide[] arrays using your primitives (Eyebrow, Heading, Accent, Body, BulletList, Divider, TwoCol, GradientText), 12 cycling brand gradients, optional sections for "where am I" context, and speaker notes. Inspired by zarazhangrui/frontend-slides — "show, don't tell" applied to narrative (presents 3 angles, you pick) plus density modes (speaker-led vs reading-first). Four modes — new (draft from brief), update (modify existing, with overflow guards), ppt (convert legacy PPTX → React deck), export (Playwright snapshot existing React deck to standalone HTML, PDF, or Vercel URL — keeps brand). Triggers on "/slide-deck," "/slides new," "/slides export," "/slides update," "/slides ppt," "draft a deck," "deck for [topic]," "talk on [topic]," "keynote on [topic]," "internal deck for [audience]," "convert this pptx," "export this deck.
npx skills add https://github.com/coreyhaines31/makerskills --skill slide-deck
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.
| Mode | Invocation | Goal |
|---|---|---|
| new | /slide-deck new <topic> (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 update, ppt, and export, skip to the corresponding mode section below. For new, continue through Steps 1–8.
Ask in one structured message. Don't round-trip on each.
marketing-like-an-engineer).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.
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:
The user picks one. If they reject all three, propose three more — don't force a path.
For the chosen angle:
Title, Hook, Problem, Framework, Examples, Close). 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.Total slide count should match the duration estimate from Step 1.
Show the outline as a table. the user edits / approves before expand.
For each slide, write the full content using the user's primitives. Reference references/system.md 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 | Eyebrow + <h1> with <Accent> keyword | First slide, sets brand and topic |
| Hook | Heading + Body | A take, story open, contrarian frame, or specific stat |
| Section divider | Eyebrow + Heading (centered, large) | Clean break between sections |
| Framework | Heading + BulletList or custom layout | The thing the user's teaching |
| Two-column | TwoCol | Comparison, before/after, problem/solution |
| Quote / pull-quote | Body (large) | Authority or audience-recognition moment |
| Resource / link | Body + URL on its own line | Outbound (rare — the user's voice says minimize) |
| Close / CTA | Heading + Body + BulletList for next steps | What the audience should do |
Voice anchors — write for the ear, not the page (see narrative-and-voice.md for full rules):
narrative-and-voice.md.)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:
For title slides and section dividers, 2–3 notes is fine.
Write to ${SLIDE_DECK_REPO:-$HOME/code/your-slide-deck-site}/src/app/slides/<slug>/:
layout.tsx — Next.js layout with <title> metadata (use the deck title)page.tsx — the slide deckUse the templates in references/template.md as the skeleton.
The <AUTHOR_HANDLE> / <AUTHOR_SITE> tokens (close-slide footer) come from ${MAKERSKILLS_CONFIG:-$HOME/.config/makerskills}/slide-deck/identity.yaml (keys: handle, site) if it exists. Otherwise ask the user for their handle and site once, offer to save them there, and use those. If they don't want a footer, drop the <p> entirely — never ship a deck with someone else's identity on it.
page.tsx must:
"use client" at the topSlideDeck and Slide type from @/components/slides/slide-deckSectionRange from @/components/slides/sections (only if using sections)@/components/slides/slide-primitivesconst slides: Slide[] = [...]const sections: SectionRange[] = [...] with 0-indexed from/to<SlideDeck slides={slides} sections={sections} />After writing the files, check if your slide-deck dev server is running.
lsof -i :3000-3099 2>/dev/null | grep -E "LISTEN" | head
If a port is in use (portless-compatible — check package.json for the dev script naming):
# Suggested URL pattern
echo "Preview at: http://${SLIDE_DECK_DEV_HOST:-localhost:3000}/slides/<slug>"
If no dev server is running, tell the user:
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).
The archive lives in ${MAKERSKILLS_CONFIG:-$HOME/.config/makerskills}/slide-deck/archive/ (create the directory if missing). Never write the archive inside the skill's own folder — skill installs and upgrades re-sync from source and wipe anything saved there. Migration: if this skill's folder contains an old references/decks-archive.md with user entries, move it to <archive dir>/INDEX.md first.
Append a one-liner to <archive dir>/INDEX.md (create if missing):
- 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.
Modify an existing deck without breaking it. Risks: overflowing slides, exceeding density limits, breaking the section ranges.
Before modifying, check:
page.tsx| Change | Guard |
|---|---|
| Adding bullets | Max 6 per BulletList in reading-first; 3 in speaker-led. If exceeded → split into two slides. |
| Adding text | If <Body> 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 sections array — increment from/to for all sections after the insertion point. |
| Removing slides | Decrement from/to for sections after the removal. Watch for orphaned id references. |
| Rewriting a slide | Preserve the id (used for anchors). Only change content and notes. |
After modifying:
Convert a legacy PPTX (client deck, conference template) into the user's React system.
python3 and python-pptx: 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.
Heading + BulletListTwoColnotes array on each slide${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 content.page.tsx + layout.tsx per the new-deck flow (Step 6).~/Documents/slide-conversions/<slug>-from-pptx/ with the original file + extracted JSON for audit.Snapshot a deck rendered in your slide-site dev server to portable HTML / PDF / Vercel URL. Output is brand-perfect because it's screenshots of your actual rendered React deck.
Output options:
html — standalone HTML file with snapshots as inline <img>, keyboard nav (arrow keys) baked inpdf — combined slide snapshotsvercel — push standalone HTML to a Vercel project for a shareable URLFlow (full details in references/export.md):
${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.page.tsx, count entries in the slides array. bash references/export.md script: snapshot-deck <slug> <count>
http://${SLIDE_DECK_DEV_HOST:-localhost:3000}/slides/<slug>?present=1 (presenter mode hides chrome)localStorage["slides:/slides/<slug>"] = "0" to start at slide 0~/Documents/slide-exports/<slug>-<YYYY-MM-DD>/slide-<n>.pnghtml → wrap snapshots in a minimal HTML shell with arrow-key navigationpdf → use magick (ImageMagick) or img2pdf to combine PNGsvercel → vercel deploy ~/Documents/slide-exports/<slug>-<date>/Caveats (mention to the user):
| Invocation | Mode | Behavior |
|---|---|---|
| /slide-deck new <topic> | 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 |
| /slide-deck notes <slug> | 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 |
business-brainstorm — if a pitch deck, brainstorm the offer first; deck draws from the briefdecide — for talks that hinge on a decision (e.g., "should I take VC money?"), /decide firstdeep-research — for talks needing data the deck doesn't have yetsecond-brain — pull relevant [[wiki]] pages as content sources; the deck can cite themwatch-video — turn a podcast episode, Loom, or talk recording into a deck outline (run in visual mode to also capture key moments + slides shown)jab-hook — once delivered, the talk becomes promo angles for the BIP rotationfrontend-skills (external) — for non-branded HTML decks where your React deck repo isn't the home?present=0 mode so the export is clean. Never export the presenter view.vercel path prompts before deploying. Auto-renew is on for domains + Vercel projects.Take coreyhaines31/slide-deck from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip.
Without those the skill loads but fails at the first command.