Create and manage presentations using Marp markdown. Trigger on "presentation", "slides", "deck", "slide deck", "Marp", "charts" (when referring to slides, not graphs).
Build professional PPTX presentations from prose documents. Reads a document describing a presentation (spec, outline, notes, or any structured description), designs the deck holistically, generates HTML slides in parallel, and assembles a .pptx via document-skills:pptx.
/presentation <filename>
No filename provided → ask for one (unchanged)
.pptx file → extract content, then offer choice
a. Extract content via python -m markitdown <file> → slide text as markdown
b. Extract theme/colors via unpack.py + theme1.xml parsing (see PPTX/PDF Input below)
c. Generate thumbnail grid for visual reference
d. Write skeleton-structured markdown to <basename>.md
e. Ask: "Refine with spec interview?" or "Build now?"
/spec (see Spec Integration below), then continue to build pipeline.pdf file → extract content, then offer choice
a. Extract text via the Read tool (handles PDFs natively; use pages parameter for >10 pages)
b. No style extraction — Style Notes says "No source style available — will be designed fresh."
c. Write skeleton-structured markdown to <basename>.md
d. Ask: "Refine with spec interview?" or "Build now?"
/spec, then continue to build pipelineFile doesn't exist (.md or no extension) → offer choice
a. Ask: "Start with a spec interview?" or "Create a skeleton outline?"
b. Spec path → delegate to /spec, then continue to build pipeline
c. Skeleton path → create from references/skeleton.md, then stop — user fills it in and re-runs
File exists (markdown) → offer choice
a. Ask: "Refine with spec interview?" or "Build now?"
b. Spec path → delegate to /spec, then continue to build pipeline
c. Build path → enter build pipeline
When the user chooses the spec interview path, invoke:
/spec <filename> This spec is for a slide presentation. Angles to explore: slide-by-slide narrative flow and structure, visual style and color preferences, diagram and data visualization needs (reference available visualizations as [viz: name] where appropriate), audience and delivery context.
The hint text suggests four angles that produce content the build pipeline's design phase needs:
### Slide Title headings## Style Notes and the design brief[viz: name] references the pipeline resolvesThe spec skill is invoked as-is — it is never modified by this skill. After spec completes and the user has a refined document, the presentation skill continues to the build pipeline.
Tools (resolved via Glob under ~/.claude/):
| Tool | Purpose | Resolution |
|---|---|---|
markitdown |
PPTX → markdown content | python -m markitdown <file> (pip package) |
unpack.py |
Extract XML for theme parsing | Glob: **/pptx/ooxml/scripts/unpack.py under ~/.claude/ |
thumbnail.py |
Visual grid of source slides | Glob: **/pptx/scripts/thumbnail.py under ~/.claude/ |
Sequence:
unpack.py and thumbnail.py via Glob (warn and continue if not found)python -m markitdown input.pptx → slide text contentunpack.py input.pptx /tmp/extract_<slug> → read ppt/theme/theme1.xml<a:clrScheme> for colors (accent1–6, dk1/dk2, lt1/lt2) and <a:fontScheme> for fontsthumbnail.py input.pptx /tmp/thumbnails_<slug> → read grid image for visual referencepages parameter for >10 pages)Follows the skeleton structure so it works with both spec refinement and direct build:
# [Title from source]
## Purpose
[Inferred or placeholder: "Update with presentation purpose."]
## Audience
[Inferred or placeholder: "Update with target audience."]
## Slides
### [Slide 1 Title]
[Extracted content — bullet points, text, table descriptions]
### [Slide 2 Title]
[...]
## Style Notes
[PPTX: extracted colors and fonts from theme]
[PDF: "No source style available — will be designed fresh."]
Derived from the title # heading: lowercase, spaces → hyphens, non-alphanumeric (except hyphens) removed. Example: # Customer Growth Forecasting → customer-growth-forecasting. All output paths use presentations/<slug>/.
Read the full input document. Analyze it holistically to produce three outputs:
Slide plan — an ordered list of slide specs. For each slide:
Design brief — shared context for all slide agents:
Customized template — take the base template (see Slide Template below) and replace the default accent color (#4472C4) with the primary color from the design brief. Adjust .callout border color, th background, and any other accent uses. This produces a deck-specific template that all slide agents share.
Create the output directory structure first, then resolve assets:
presentations/<slug>/slides/, presentations/<slug>/assets/, presentations/<slug>/thumbnails/presentations/<slug>/slides/.gitkeep — this establishes write permissions for the output directory early in the session, before parallel agents need to write there.presentations/<slug>/assets/.[viz: name] patterns, fuzzy-match against .viz/*.png; if ambiguous, list matches and ask; if no match, warn and omit (build continues)..viz/ does not exist and the document references viz embeds, warn and skip.Spawn a Task agent for every slide (subagent_type: general-purpose, model: sonnet). CRITICAL: Launch ALL slide agents in a single message containing multiple Task tool calls. Do NOT spawn them one at a time across separate messages.
Each agent receives:
n (0-based)presentations/<slug>/assets/)references/component-map.md, inlined verbatimEach agent's workflow:
<html> with customized template CSS in <head>, slide content in <body>). Follow all html2pptx constraints strictly. Follow the design brief for color usage, style, and audience-appropriate complexity. Dimensions: width: 720pt; height: 405pt. If the slide has a diagram, render boxes/labels/backgrounds as <div> elements with all text wrapped in <p> tags. Strip notes content — it does not appear on the slide. Image paths use ./assets/<filename>.presentations/<slug>/slides/slide-<n>.html. This file write is required — the agent MUST persist its output to disk.presentations/<slug>/slides/slide-<n>.diagram.js. The snippet operates on a variable named slide (the object returned by html2pptx). Colors must omit the # prefix — use "4C72B0" not "#4C72B0" (incorrect format corrupts the file). Example: slide.addShape(pptx.ShapeType.rightArrow, { x: 2, y: 1.5, w: 1, h: 0.5, fill: { color: "4C72B0" } });const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.setViewportSize({ width: 960, height: 540 });
await page.goto('file://' + require('path').resolve(process.argv[2]));
await page.screenshot({ path: process.argv[3] });
await browser.close();
})();
// Run: node preview.js <html-path> <png-path>
The 960×540 viewport matches 720pt × 405pt at screen resolution (1pt = 4/3 px). Inspect the PNG for text overflow, clipping, and layout problems. PptxGenJS connector/arrow shapes from diagrams are not visible in this preview — they are added post-conversion and validated after assembly.OK: slide-<n> (with diagram) or OK: slide-<n> (no diagram). CRITICAL: Do NOT include any HTML content or diagram code in the response. All content MUST be written to disk. If a file write is denied or fails, return WRITE_FAILED: slide-<n> — never paste the content into the response as a fallback. Context bloat from returned HTML content will degrade the build.Agent failure handling:
OK responses: slide is complete on disk, proceed.WRITE_FAILED responses: tell the user "Slide agents need file write permission to presentations/<slug>/slides/. Please approve writes when prompted." Then re-spawn only the failed agents. If retry also fails, abort and report which slides failed.build.jsResolve paths to html2pptx.js and thumbnail.py from the installed document-skills:pptx skill:
Glob pattern: "**/pptx/scripts/html2pptx.js" under ~/.claude/
Glob pattern: "**/pptx/scripts/thumbnail.py" under ~/.claude/
If either file is not found, abort and tell the user: "document-skills:pptx is required but html2pptx.js / thumbnail.py was not found. Install the pptx skill first."
Spawn a Task agent (subagent_type: general-purpose, model: sonnet) to assemble build.js. Pass it:
html2pptx.js (resolved above)presentations/<slug>/ directory pathThe assembly agent's workflow:
presentations/<slug>/slides/slide-*.html to confirm all expected slides exist.presentations/<slug>/slides/slide-*.diagram.js to identify which slides have diagram code.build.js at presentations/<slug>/build.js with the resolved html2pptx.js absolute path baked in. The file runs from presentations/<slug>/ (all relative paths are relative to it):const pptxgen = require('pptxgenjs');
const html2pptx = require('/absolute/path/to/html2pptx.js'); // resolved absolute path
const pptx = new pptxgen();
pptx.layout = 'LAYOUT_16x9';
(async () => {
// Slide 0
const { slide: slide0 } = await html2pptx('slides/slide-0.html', pptx);
// [inline diagram snippet from slide-0.diagram.js, if it exists]
// Slide 1
const { slide: slide1 } = await html2pptx('slides/slide-1.html', pptx);
// [inline diagram snippet from slide-1.diagram.js, if it exists]
// ... repeat for all slides
await pptx.writeFile({ fileName: 'slides.pptx' });
})();
cd presentations/<slug> && npm install pptxgenjs sharp 2>&1 | tail -5 — verify both packages install successfully before returning.build.js.Notes content is stripped from HTML by agents (step 3.1) — no additional strip step needed in build.js.
Spawn a Task agent (subagent_type: general-purpose, model: sonnet) with these explicit inputs:
build.js: presentations/<slug>/build.jsthumbnail.py (resolved in Step 4)presentations/<slug>/ directory pathThe sub-agent's workflow:
Validate all slides before building — Read every presentations/<slug>/slides/slide-*.html file. Check each against the html2pptx constraints:
<p>, <h1>-<h6>, <span>) — only on <div><div> — all text in <p>, <h1>-<h6>, <ul>, <ol><b>, <i>, <u>, <span>•, –) — must use <ul>/<ol># prefixFix all violations found across ALL slides before proceeding. Do not run build.js until all slides pass validation.
Build: cd presentations/<slug> && NODE_PATH=./node_modules node build.js 2>&1
If build fails: read the error message, fix the offending slide HTML, and re-run. Limit: 2 fix-rebuild cycles. If still failing after 2 cycles, abort and report the error.
Generate thumbnail grid: python <thumbnail.py absolute path> presentations/<slug>/slides.pptx presentations/<slug>/thumbnails
Inspect the thumbnail grid for layout issues — especially connector/arrow placement in diagram slides (this is the first time those elements are visible)
If diagram issues are found: edit the relevant PptxGenJS snippets in build.js, re-run node build.js, and re-generate thumbnails. Limit: 1 rebuild pass.
Return the path to the final output: presentations/<slug>/slides.pptx
IMPORTANT: Do NOT read html2pptx.js source code. All constraint rules are provided above — apply them directly. Reading the converter source wastes context and does not help fix HTML violations.
.pptx pathlibreoffice --headless --convert-to pdf --outdir presentations/<slug>/ presentations/<slug>/slides.pptxThis is the base template. During the design phase (Step 1), the default accent color (#4472C4) is replaced with the primary color from the design brief. The customized template is then inlined verbatim into each slide agent's prompt.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
display: flex;
flex-direction: column;
width: 720pt;
height: 405pt;
padding: 36pt 48pt;
font-family: Arial, Helvetica, sans-serif;
font-size: 18pt;
color: #1a1a1a;
background: #ffffff;
overflow: hidden;
}
.slide-title { font-size: 28pt; font-weight: bold; color: #1a1a1a; margin-bottom: 20pt; line-height: 1.2; }
p { font-size: 18pt; line-height: 1.5; margin-bottom: 8pt; }
ul, ol { padding-left: 24pt; margin-bottom: 12pt; }
li { font-size: 18pt; line-height: 1.5; margin-bottom: 6pt; }
.callout { background: #f0f4ff; border-left: 4pt solid #4472C4; padding: 16pt 20pt; margin: 16pt 0; border-radius: 4pt; }
.callout p { font-size: 20pt; font-weight: 600; color: #2c3e50; margin: 0; }
table { border-collapse: collapse; width: 100%; margin: 12pt 0; }
th, td { border: 1pt solid #d0d0d0; padding: 8pt 12pt; text-align: left; font-size: 15pt; }
th { background: #4472C4; color: white; font-weight: bold; }
tr:nth-child(even) { background: #f5f7fa; }
blockquote { border-left: 4pt solid #888; padding: 8pt 16pt; margin: 12pt 0; font-style: italic; color: #444; }
blockquote p { font-size: 18pt; }
img { max-width: 100%; max-height: 280pt; object-fit: contain; }
</style>
</head>
<body>
<!-- slide content goes here -->
</body>
</html>
The canonical base template is also saved at {SKILL_DIR}/references/template.html.
Inline these rules verbatim into each slide agent's prompt alongside the template. html2pptx.js validates these strictly — violations cause build failures.
<p>, <h1>-<h6>, <span>, etc.) — only on <div> elements (which become PowerPoint shapes)<div> — all text must be in <p>, <h1>-<h6>, <ul>, or <ol> tags<b>, <i>, <u>, <span> — not supported in PowerPoint• or –) — use <ul>/<ol> instead# prefix — use "4472C4" not "#4472C4" (incorrect format corrupts the output file)references/skeleton.md — Template used when creating a new presentation outline (also the target format for PPTX/PDF extraction)references/component-map.md — HTML patterns for common slide elementsreferences/template.html — Base slide HTML/CSS template (customized per-deck in design phase)/spec <filename> <hint>)