md-slides — Markdown deck → single-file HTML presentation
Converts a markdown deck (slides separated by `---` HR boundaries or by `# ` H1 headings, with optional `<!-- notes: ...
How to use it
Claude Code
- Run the line below. It pulls the whole folder into
~/.claude/skills/md-slides, including the files SKILL.md points to. - Describe your job in plain words. Claude Code follows the skill from there.
npx degit alirezarezvani/claude-skills/markdown-html/skills/md-slides#main ~/.claude/skills/md-slidesFor one project only, change the path to .claude/skills/md-slides. This skill also uses config_loader.py, slide_splitter.py, presenter_notes_parser.py, deck_html_renderer.py, Prism.js, reveal.js — copying SKILL.md alone won't be enough. See the folder on GitHub.
Claude (web or desktop app)
- On this page open ⋯ → Download .md.
- Save it as SKILL.md in a folder, zip the folder, then Customize → Skills → + → Create skill → Upload a skill.
- Pick the file and Save. Claude shows the name and description and runs a security scan.
- Check the skill is switched on.
- Start a new chat and describe your job in plain words. The AI follows the skill from there.
ChatGPT or another app
- ChatGPT: make a Project and paste it into Instructions.
- Neither? Paste it at the top of a new chat — it works for that chat.
Not working?
- Check which app you pasted it into — the steps above name the right one.
- Some skills need the paid tier of Claude or ChatGPT.
Paste into Claude, ChatGPT or Cursor.
Source of md-slides — Markdown deck → single-file HTML presentation
Show the full text103 lines
| name | description | version | author | license | tags | compatible_tools |
|---|---|---|---|---|---|---|
| md-slides | Converts a markdown deck (slides separated by `---` HR boundaries or by `# ` H1 headings, with optional `<!-- notes: ... -->` presenter notes blocks) into a single-file HTML presentation with arrow-key / space / PgDn / PgUp / Home / End / P / Esc keyboard navigation, presenter mode (split view with current slide + speaker notes + clock + next-slide preview), URL-hash deep linking, and `@media print` page-per-slide for PDF export. Triggers when the markdown-html-orchestrator classifies an input as SLIDES, or when invoked directly via /cs:md-slides. Reuses md-document's markdown parser for slide-body rendering and reads design-system tokens via config_loader.py. Refuses if input has no clear slide boundaries, produces a 1-slide deck, or `--strict-notes` is on with < 50% notes coverage. Use after orchestrator routing. | 2.10.3 | Alireza Rezvani | MIT | [markdown, html, slides, deck, presenter-mode, keyboard-nav, print-to-pdf, single-file, design-system] | [claude-code, codex-cli, cursor, antigravity, opencode, gemini-cli] |
md-slides — Markdown deck → single-file HTML presentation
The slide-deck converter. Reads a markdown deck (HR or H1 boundaries, optional presenter notes), emits a single-file HTML presentation that runs in any browser with keyboard navigation, presenter mode, and print-to-PDF.
Three stdlib tools pipeline together:
slide_splitter.py → presenter_notes_parser.py → deck_html_renderer.py
(md → ordered (extract <!-- notes: (slides + design-system
slides with --> blocks, attach tokens → single-file
titles) per slide) HTML with keyboard nav)
When to invoke
| Symptom | Action |
|---|---|
markdown-html-orchestrator routes input as SLIDES |
Invoke this skill |
User runs /cs:md-slides <path>.md directly |
Invoke this skill |
Input has 3+ --- HR lines OR 5+ H1 headings with short bodies |
Invoke this skill |
| Input is a long-form spec | Route to md-document instead |
| Input is a code review | Route to md-review instead |
| Input has no clear slide boundaries | Refuse, route to md-document |
| Input would produce 1 slide | Refuse (it's a poster) |
Pipeline
# 1. Split slides on --- or H1 (auto-detect by default)
python3 markdown-html/skills/md-slides/scripts/slide_splitter.py \
--input <path>.md --output /tmp/slides.json
# 2. Extract <!-- notes: ... --> blocks from each slide
python3 markdown-html/skills/md-slides/scripts/presenter_notes_parser.py \
--slides /tmp/slides.json --output /tmp/deck.json
# 3. Render single-file HTML deck
python3 markdown-html/skills/md-slides/scripts/deck_html_renderer.py \
--slides /tmp/deck.json --title "My Talk" --output deck.html
What ships in the HTML
- All slides as
<section class="slide">— one visible at a time, controlled by JS - Keyboard nav —
→/Space/PgDnadvance;←/PgUpprevious;Home/Endjump;Ppresenter mode;Escexits presenter - URL-hash deep linking —
#3jumps to slide 3; browser back/forward walks slides; sharedeck.html#5to send someone directly there - Progress bar — 3px at top showing position through the deck
- Slide counter — bottom-right ("3 / 12")
- Presenter mode (P key) — splits the window: current slide on left (60% width), panel on right with clock + speaker notes + next-slide preview
- Print stylesheet —
Cmd+Pproduces a PDF with one slide per page @media (prefers-reduced-motion: reduce)honored- 12 brand CSS custom properties from design-system; design_style affects layout density
- Reuses md-document's markdown parser — slide bodies render with consistent paragraph/list/code/table/callout handling
Hard rules
- Refuses input with no clear slide boundaries. Auto mode needs ≥ 3 HR lines or ≥ 5 H1 headings. Otherwise exit 6 — route to md-document.
- Refuses 1-slide decks. That's a poster, not a deck. Exit 5.
- Refuses input < 100 lines. Same Shihipar threshold as all converters.
- Refuses without onboarding. Same gate as every converter.
--strict-notesrefuses < 50% notes coverage. A deck where most slides have no notes isn't set up for presenter mode. Exit 7.- Soft-warns slides > 40 source lines. Signal-to-noise; renders anyway but surfaces the count.
- Single-file output. All CSS + JS inline. Only external is Google Fonts CSS. Prism.js is opt-in via
--syntax. - No JS framework runtime. Vanilla JS + keyboard event handlers, no React/Vue/Svelte.
Forcing-question library (Matt Pocock grill discipline)
- Is this actually a deck, or a long document? Recommended: if you can't draw clear slide boundaries, it's not a deck. Canon: Tufte Cognitive Style of PowerPoint.
- HR (
---) or H1 boundaries? Recommended: HR for typical decks; H1 for outline-driven decks. Canon: Marp / reveal.js / pandoc convergence. - Will it be presented live or distributed for self-paced reading? Recommended: live → need presenter notes; self-paced → notes optional. Canon: Weinschenk 100 Things Every Presenter Needs to Know.
- Is there any slide over 40 source lines? Recommended: split it. Canon: NN/g — audience attention drops past ~6 bullets / 200 words.
- Is
--syntaxneeded? Recommended: only for decks with substantial code blocks. Default off. Canon: single-file shareability discipline.
Distinct from
md-document— that's one continuous document. This is N discrete slides.md-review— that renders diff hunks + annotations. This renders prose slides.marketing/landing/— that's a landing page, not a deck.- Keynote / PowerPoint — those are graphic-design tools. This is for markdown-authored decks projected from a browser.
Output artifact
{default_output_dir}/deck-{slug}.html (path resolved by orchestrator's output_path_resolver.py; collision suffix -2, -3, … by default).
References
- Shihipar — Claude Code HTML output (Medium, 2026), Tier 3 use case "Slide Decks"
- Reynolds — Presentation Zen (less is more discipline)
- Atkinson — Beyond Bullet Points (the bullet-heavy failure mode)
- Tufte — The Cognitive Style of PowerPoint (the polemic)
- reveal.js / Big / Marp — convergent markdown-to-deck conventions
- See
references/for full citations (presentation_ux, keyboard_nav_patterns, single_file_deck_conventions)
| 1 | |
| 2 | name md-slides |
| 3 | description "Converts a markdown deck (slides separated by `---` HR boundaries or by `# ` H1 headings, with optional `<!-- notes: ... -->` presenter notes blocks) into a single-file HTML presentation with arrow-key / space / PgDn / PgUp / Home / End / P / Esc keyboard navigation, presenter mode (split view with current slide + speaker notes + clock + next-slide preview), URL-hash deep linking, and `@media print` page-per-slide for PDF export. Triggers when the markdown-html-orchestrator classifies an input as SLIDES, or when invoked directly via /cs:md-slides. Reuses md-document's markdown parser for slide-body rendering and reads design-system tokens via config_loader.py. Refuses if input has no clear slide boundaries, produces a 1-slide deck, or `--strict-notes` is on with < 50% notes coverage. Use after orchestrator routing." |
| 4 | version 2.10.3 |
| 5 | author Alireza Rezvani |
| 6 | license MIT |
| 7 | tags [markdown, html, slides, deck, presenter-mode, keyboard-nav, print-to-pdf, single-file, design-system] |
| 8 | compatible_tools [claude-code, codex-cli, cursor, antigravity, opencode, gemini-cli] |
| 9 | |
| 10 | |
| 11 | # md-slides — Markdown deck → single-file HTML presentation |
| 12 | |
| 13 | The slide-deck converter. Reads a markdown deck (HR or H1 boundaries, optional presenter notes), emits a single-file HTML presentation that runs in any browser with keyboard navigation, presenter mode, and print-to-PDF. |
| 14 | |
| 15 | Three stdlib tools pipeline together: |
| 16 | |
| 17 | |
| 18 | slide_splitter.py → presenter_notes_parser.py → deck_html_renderer.py |
| 19 | (md → ordered (extract <!-- notes: (slides + design-system |
| 20 | slides with --> blocks, attach tokens → single-file |
| 21 | titles) per slide) HTML with keyboard nav) |
| 22 | |
| 23 | |
| 24 | ## When to invoke |
| 25 | |
| 26 | | Symptom | Action | |
| 27 | |---|---| |
| 28 | | `markdown-html-orchestrator` routes input as SLIDES | Invoke this skill | |
| 29 | | User runs `/cs:md-slides <path>.md` directly | Invoke this skill | |
| 30 | | Input has 3+ `---` HR lines OR 5+ H1 headings with short bodies | Invoke this skill | |
| 31 | | Input is a long-form spec | Route to `md-document` instead | |
| 32 | | Input is a code review | Route to `md-review` instead | |
| 33 | | Input has no clear slide boundaries | Refuse, route to `md-document` | |
| 34 | | Input would produce 1 slide | Refuse (it's a poster) | |
| 35 | |
| 36 | ## Pipeline |
| 37 | |
| 38 | |
| 39 | # 1. Split slides on --- or H1 (auto-detect by default) |
| 40 | python3 markdown-html/skills/md-slides/scripts/slide_splitter.py \ |
| 41 | --input <path>.md --output /tmp/slides.json |
| 42 | |
| 43 | # 2. Extract <!-- notes: ... --> blocks from each slide |
| 44 | python3 markdown-html/skills/md-slides/scripts/presenter_notes_parser.py \ |
| 45 | --slides /tmp/slides.json --output /tmp/deck.json |
| 46 | |
| 47 | # 3. Render single-file HTML deck |
| 48 | python3 markdown-html/skills/md-slides/scripts/deck_html_renderer.py \ |
| 49 | --slides /tmp/deck.json --title "My Talk" --output deck.html |
| 50 | |
| 51 | |
| 52 | ## What ships in the HTML |
| 53 | |
| 54 | **All slides as `<section class="slide">`** — one visible at a time, controlled by JS |
| 55 | **Keyboard nav** — `→` / `Space` / `PgDn` advance; `←` / `PgUp` previous; `Home`/`End` jump; `P` presenter mode; `Esc` exits presenter |
| 56 | **URL-hash deep linking** — `#3` jumps to slide 3; browser back/forward walks slides; share `deck.html#5` to send someone directly there |
| 57 | **Progress bar** — 3px at top showing position through the deck |
| 58 | **Slide counter** — bottom-right ("3 / 12") |
| 59 | **Presenter mode** (P key) — splits the window: current slide on left (60% width), panel on right with clock + speaker notes + next-slide preview |
| 60 | **Print stylesheet** — `Cmd+P` produces a PDF with one slide per page |
| 61 | **`@media (prefers-reduced-motion: reduce)`** honored |
| 62 | **12 brand CSS custom properties** from design-system; design_style affects layout density |
| 63 | **Reuses md-document's markdown parser** — slide bodies render with consistent paragraph/list/code/table/callout handling |
| 64 | |
| 65 | ## Hard rules |
| 66 | |
| 67 | **Refuses input with no clear slide boundaries.** Auto mode needs ≥ 3 HR lines or ≥ 5 H1 headings. Otherwise exit 6 — route to md-document. |
| 68 | **Refuses 1-slide decks.** That's a poster, not a deck. Exit 5. |
| 69 | **Refuses input < 100 lines.** Same Shihipar threshold as all converters. |
| 70 | **Refuses without onboarding.** Same gate as every converter. |
| 71 | **`--strict-notes` refuses < 50% notes coverage.** A deck where most slides have no notes isn't set up for presenter mode. Exit 7. |
| 72 | **Soft-warns slides > 40 source lines.** Signal-to-noise; renders anyway but surfaces the count. |
| 73 | **Single-file output.** All CSS + JS inline. Only external is Google Fonts CSS. Prism.js is opt-in via `--syntax`. |
| 74 | **No JS framework runtime.** Vanilla JS + keyboard event handlers, no React/Vue/Svelte. |
| 75 | |
| 76 | ## Forcing-question library (Matt Pocock grill discipline) |
| 77 | |
| 78 | **Is this actually a deck, or a long document?** Recommended: if you can't draw clear slide boundaries, it's not a deck. Canon: Tufte *Cognitive Style of PowerPoint*. |
| 79 | **HR (`---`) or H1 boundaries?** Recommended: HR for typical decks; H1 for outline-driven decks. Canon: Marp / reveal.js / pandoc convergence. |
| 80 | **Will it be presented live or distributed for self-paced reading?** Recommended: live → need presenter notes; self-paced → notes optional. Canon: Weinschenk *100 Things Every Presenter Needs to Know*. |
| 81 | **Is there any slide over 40 source lines?** Recommended: split it. Canon: NN/g — audience attention drops past ~6 bullets / 200 words. |
| 82 | **Is `--syntax` needed?** Recommended: only for decks with substantial code blocks. Default off. Canon: single-file shareability discipline. |
| 83 | |
| 84 | ## Distinct from |
| 85 | |
| 86 | **`md-document`** — that's one continuous document. This is N discrete slides. |
| 87 | **`md-review`** — that renders diff hunks + annotations. This renders prose slides. |
| 88 | **`marketing/landing/`** — that's a landing page, not a deck. |
| 89 | **Keynote / PowerPoint** — those are graphic-design tools. This is for markdown-authored decks projected from a browser. |
| 90 | |
| 91 | ## Output artifact |
| 92 | |
| 93 | `{default_output_dir}/deck-{slug}.html` (path resolved by orchestrator's `output_path_resolver.py`; collision suffix `-2`, `-3`, … by default). |
| 94 | |
| 95 | ## References |
| 96 | |
| 97 | Shihipar — *Claude Code HTML output* (Medium, 2026), Tier 3 use case "Slide Decks" |
| 98 | Reynolds — *Presentation Zen* (less is more discipline) |
| 99 | Atkinson — *Beyond Bullet Points* (the bullet-heavy failure mode) |
| 100 | Tufte — *The Cognitive Style of PowerPoint* (the polemic) |
| 101 | reveal.js / Big / Marp — convergent markdown-to-deck conventions |
| 102 | See `references/` for full citations (presentation_ux, keyboard_nav_patterns, single_file_deck_conventions) |
| 103 |
Discussion
Browse more free Claude skills or everything in Design.