Was macht better-slides?
Build presentations as ONE portable, self-contained .html file that performs: fixed
1920×1080 stage scaled to any screen, big type, timed reveals, optional sound design, and a
"one more thing" finale. No build step, no framework, one fonts request.
This skill carries a point of view. It does not just lay out slides — it applies a speaking methodology (find the one idea, build a hero slide, stick the landing) and a performance grammar (motion + sound that serve the message). Design without a thesis is slop; this skill refuses it.
Core principles
- A deck is a performance. Optimize for what the room feels, not for completeness.
- One idea, one breath. If the talk's thesis won't fit in a breath, it isn't one idea yet. Every deck distills to a single big idea (playbook).
- Huge type, few words, one visual. If a line wouldn't be readable on a phone at arm's length, it's too small.
- Build the hero slide. Every deck needs 1–2 screenshot-worthy visuals that spread the idea without the speaker present.
- Motion and sound are message, not decoration. Every reveal and every cue earns its place by landing a beat. Never animate for the sake of motion.
- Fixed 16:9 stage (NON-NEGOTIABLE). Author at 1920×1080; scale the whole stage to the viewport; letterbox/pillarbox. Never reflow slide content for phones.
- Zero dependencies. Single HTML file (GSAP via one CDN
<script>is the only allowed exception, and the deck degrades gracefully without it). All CSS/JS inline.
The two layers
better-slides always builds both:
- The "what to say" layer — the Speaker Playbook. Read it during content work. It governs structure: distill, lead with story, one number, hero slide, time discipline, a landing that makes them act tonight.
- The "how it lands" layer — the engine + performance style + motion + (optional)
sound. Read
engine/,reference/, and the chosenperformance-styles/*/design.mdduring generation.
A deck that nails layout but has no thesis fails. A deck with a thesis and flat delivery fails. Build both.
Phase 0: Detect mode
- Mode A — New keynote. Build from scratch. → Phase 1.
- Mode B — Upgrade. Turn an existing deck (HTML, notes, or a flat slide export) into a performance. Read it, find the one idea it's burying, then re-author on the engine with the motion/sound layer. → Phase 1 (apply the playbook to existing content).
- Mode C — Enhance. Add a performance treatment (sound, an
omtfinale, a hero slide) to a deck already on this engine. Skip to Phase 3, edit in place. - Mode D — PPTX conversion. Convert a PowerPoint file. Run
python3 scripts/extract-pptx.py <input.pptx> <outdir>(needspip install python-pptx), read the generatedcontent.md+ extractedassets/, confirm the extraction with the user, then continue as Mode B: apply the playbook to the extracted content and re-author it as a performance. Preserve usable images; keep speaker notes as HTML comments.
Phase 1: Content & method
Ask these together (use the structured-question UI if available, else one numbered message):
- Purpose — Conference talk / Pitch / Teaching / Internal / Launch.
- Length — Lightning 5 min / Talk 10 min / Keynote 20–25 min.
- Register — Speaker-led (you'll narrate; few words per slide, more slides) vs. Reading (self-explanatory; denser). When mixed, default speaker-led for live talks.
- Sound — Full sound design (applause/swoosh/chime/
omt) / Subtle cues only / Silent. - Content — All ready / Rough notes / Topic only.
Then read playbook/speaker-playbook.md and apply it to
the content before touching design:
- Distill everything to one idea statable in one breath. Confirm it with the user.
- Pick the 2–3 points that survive. Cut the rest.
- Identify the hero slide (the one number / chart / before→after worth photographing).
- Draft the landing: the one thing the audience should do tonight.
- Map the arc: hook → story → idea → proof (hero) → land → don't-vanish.
Confirm the outline and the one-idea statement before generating.
Images
If the user provides images, scan and evaluate each (what it shows, usable or not, dominant colors), then design the outline around the strong ones. Decks work with zero images via pure-CSS visuals — that is a first-class path, not a fallback.
Phase 2: Style discovery
Show, don't tell. Don't ask the user to describe a look. Generate live preview slides and let them point.
- Read
performance-styles/selection-index.json(compact metadata only — do not bulk-readdesign.mdfiles). - Match the brief's purpose/mood/register against each style's metadata.
- Read only the shortlisted candidates'
preview.mdcards. - Generate 3 live single-slide previews (real title slide for this talk, in each style): typically 1 restrained, 1 expressive, 1 wildcard. Each must look like a genuine first slide — never render style names, "Option A", file paths, or brief notes on the slide itself.
- Save to
.better-slides/previews/and open them. Ask which they prefer (or "mix").
Only after the user picks does the full design.md for that one style get read.
Phase 3: Generate the performance
Before generating, read:
engine/template.html— base deck; copy it, never edit in place. It carries the stage, nav, glass menu, progress, confetti, and the layout kit.engine/stage.css— mandatory fixed-stage CSS (already inlined in the template; include in full in any deck built from scratch).reference/layouts.md— slide recipes.reference/motion.md— timed reveals, staggered builds, theomtfinale. This is the performance layer.reference/audio.md— only if sound was chosen. Web Audio wiring, cue palette, and graceful-silence fallback.- The chosen
performance-styles/*/design.md— the full design system. Preserve its fonts, palette, motion grammar, and sound palette. reference/theming.md— the single<style id="theme">token block to reskin.
Build steps:
- Copy
engine/template.htmlto<dest>/index.html. - Fill the
{{PLACEHOLDERS}}(title, subtitle, brand, canonical URL, OG image). - Apply the chosen style's theme tokens + fonts (one
<style id="theme">block). - Author the slides from the Phase-1 outline using
layouts.mdrecipes. First slide staysactive. The menu, progress, deep links, and confetti recompute automatically. - Apply the performance layer (
motion.md): pace the reveals to the narration — one beat per click. Reserve.slam/omtfor the hero and the finale, not every slide. - If sound was chosen (
audio.md): wire the cue palette from the style, gate all audio behind the first user gesture (browsers block autoplay), and make every cue optional — the deck must be fully usable muted. Never autoplay music without a visible toggle. - Apply the playbook end-state: ensure there is a hero slide, a real CTA landing (not "thanks"), and a don't-vanish slide (QR / contact).
Hard invariants (every slide, every deck)
- Fixed 1920×1080 stage scaled as one unit. No responsive reflow of slide content.
- Slide visibility via
.active(opacity/visibility), neverdisplay:nonetoggling that a later layout rule can override. prefers-reduced-motiondisables motion (mirror every entrance animation there).- Sound is opt-in, gesture-gated, and never required to follow the talk.
- Never negate CSS functions directly (
-clamp(...)); usecalc(-1 * clamp(...)). - No generic "AI slop": no Inter/Roboto/system display fonts, no purple-gradient-on-white, no identical centered card grids. Each style commits to a distinct thesis.
Verify
Open in a browser (or Playwright): step through with arrow keys; confirm reveals fire one beat at a time; toggle sound on/off; resize (stays centered + letterboxed); print-preview for the PDF layout. Check no text overflows and no panels overlap at 1280×720 and one phone viewport.
Phase 4: Perform & share (optional)
When delivering, tell the user how to drive the deck:
- Present —
open index.html; arrows/space/swipe to advance,ffullscreen,msound toggle,pprint-to-PDF;omt/confetti fire on cue. - Edit without the agent — press
e(or ✎ in the menu), click any text and type, thenCtrl/Cmd+Sdownloads the edited file.Escexits edit mode. Mention this — it lets the user fix a typo at the venue without a laptop full of tooling.
Then ask if they want to share. Offer:
-
Deploy to a live URL —
bash scripts/deploy.sh <deck-folder-or-html>(Vercel free tier; walks the user through login on first run). Prefer deploying the deck's folder when it has audio/image assets. Re-running updates the same URL. After deploying, open the URL and click through every slide once to confirm assets load.Before any deploy, run the web-friendly asset checklist:
- Video: h264 +
yuv420p+-movflags +faststart,-anfor bg loops, every<video>gets aposter. Re-encode HEVC/anything else. - Images: photos = JPEG (~88–92), PNG only for transparency. Audit bloat:
find assets \( -name "*.png" -o -name "*.jpg" \) -exec du -k {} + | sort -rn | head. chmod 644everything (image tools write mode-600; servers 403 them). Spot-check live URLs withcurl -o /dev/null -w "%{http_code}".- Copy ONLY referenced assets (
grep -o "assets/[^\"')]*" index.html | sort -u) — never the whole assets dir (private source photos, working files).
A published deck also needs (both REQUIRED):
- Social share card — an
og.jpg(1280×720) captured from the rendered first slide. Runbash scripts/capture-shots.sh <deck.html> --og— it serves the deck, forces entrance animations to their final state, clips to the stage (no baked-in letterbox bars), writesog.jpgat mode 644, and fails loudly if the deck references any asset that 404s. Do NOT hand-drive a browser for this. Then setcanonical/og:urlto the deck's URL andog:image/twitter:imageto the og.jpg as ABSOLUTE URLs,twitter:card=summary_large_image. Re-capture when the title slide changes. Add--previewfor a 1920×1080preview.jpg, or--slides 3,5/--allfor README stills. - Asset preloader gate (media-heavy decks) — see
reference/preloader.md: progress bar that downloads every asset into the browser disk cache, then a Start button gated on the first video'scanplaythrough(the click also unlocks video autoplay).
- Video: h264 +
-
Export to PDF —
bash scripts/export-pdf.sh <deck.html> [out.pdf]. Drives headless Chromium through the deck's print CSS (one slide per 1920×1080 page). First run downloads Chromium (~100MB) — warn the user. Motion and sound are not preserved; the PDF is each slide's final visual state. No-install fallback: presspin the deck and use the browser's "Save as PDF".
Supporting files
| File | Purpose | When |
|---|---|---|
playbook/speaker-playbook.md | The methodology — what to say | Phase 1 |
performance-styles/selection-index.json | Compact style metadata | Phase 2 |
performance-styles/*/preview.md | Title-slide preview cards | Phase 2 (shortlist) |
performance-styles/*/design.md | Full design system (one chosen style) | Phase 3 |
engine/template.html | Base deck — copy, don't edit | Phase 3 |
engine/stage.css | Mandatory fixed-stage CSS | Phase 3 |
reference/layouts.md | Slide recipes | Phase 3 |
reference/motion.md | Timed reveals / omt finale | Phase 3 |
reference/audio.md | Sound design + Web Audio | Phase 3 (if sound) |
reference/theming.md | Token swap | Phase 3 |
reference/preloader.md | Asset preloader gate + share-card pattern | Phase 4 (publish) |
scripts/extract-pptx.py | PPTX content extraction | Phase 0 Mode D |
scripts/deploy.sh | Deploy deck to a live URL (Vercel) | Phase 4 |
scripts/export-pdf.sh | Export deck to PDF | Phase 4 |
scripts/capture-shots.sh | Capture og.jpg share card / slide stills | Phase 4 (publish) |
index.html | The project landing page — itself a deck (Noir) | Reference example |
demo/index.html | Flagship: the "Be Unforgettable" talk (Spotlight) | Reference example |
demo/noir/index.html | "This is not a slideshow" (Noir) | Reference example |
demo/obsidian/index.html | "Subtraction is the work" (Obsidian) | Reference example |
demo/cupertino/index.html | A photo-forward story talk (Cupertino) | Reference example |
demo/terminal/index.html | "Dependencies are debt" (Terminal) | Reference example |
demo/broadsheet/index.html | An essay-as-talk (Broadsheet) | Reference example |