pptxgenjs, or edit/repair an existing .pptx template directly via its XML. Use this path when the user explicitly asks for a .pptx/PowerPoint file to open and edit in PowerPoint/Keynote/Google Slides, or hands you an existing .pptx template to modify. See PPTX-CREATING.md [blocked] and PPTX-EDITING.md [blocked].SCRIPT=~/.opencode/skills/presentations/presentation.ts
# Create a slide (content = HTML body only, no html/head/body tags)
bun run "$SCRIPT" create_slide '{"presentation_name":"my-deck","slide_number":1,"slide_title":"Intro","content":"<div style=\"...\">...</div>","presentation_title":"My Deck"}'
# List slides
bun run "$SCRIPT" list_slides '{"presentation_name":"my-deck"}'
# Delete a slide
bun run "$SCRIPT" delete_slide '{"presentation_name":"my-deck","slide_number":2}'
# List all presentations
bun run "$SCRIPT" list_presentations
# Delete a presentation
bun run "$SCRIPT" delete_presentation '{"presentation_name":"my-deck"}'
# Validate dimensions (Playwright)
bun run "$SCRIPT" validate_slide '{"presentation_name":"my-deck","slide_number":1}'
# Export to PDF
bun run "$SCRIPT" export_pdf '{"presentation_name":"my-deck"}'
# Export to PPTX (screenshot-based: editable text boxes over a rendered background — fast, good enough for most decks)
bun run "$SCRIPT" export_pptx '{"presentation_name":"my-deck"}'
# Generate viewer HTML (no server)
bun run "$SCRIPT" preview '{"presentation_name":"my-deck"}'
# Start on-demand viewer server (port 3210 by default)
bun run "$SCRIPT" serve '{"port":3210}'
serve action when you need to preview slides:bun run "$SCRIPT" serve '{"port":3210}'
presentations/ directory. When you need it to keep running, launch the same command in pty_spawn.export_pdf or export_pptx only when the user requests that export.show:show(action="show", type="url", url="http://localhost:3210/presentations/<name>/", title="Slide Preview")
content is the <body> content only — wrapper injected automaticallybox-sizing: border-box, max 40px paddingwindow.addEventListener('load', () => { ... })presentations/images/ → reference as ../images/filename<div style="width:1920px;height:1080px;background:linear-gradient(135deg,#1e1b4b,#312e81);
color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;
box-sizing:border-box;padding:100px;text-align:center;">
<div style="font-size:24px;color:#a5b4fc;letter-spacing:4px;text-transform:uppercase;margin-bottom:32px;">SUBTITLE</div>
<h1 style="font-size:80px;font-weight:800;margin:0;line-height:1.1;">Title</h1>
</div>
<div style="width:1920px;height:1080px;background:#0f172a;color:#f8fafc;
display:grid;grid-template-columns:1fr 1fr;gap:80px;
box-sizing:border-box;padding:80px;align-items:center;">
<div><!-- left --></div><div><!-- right --></div>
</div>
create_slide × N → validate_slide → serve → show viewer URL → offer to create a PDF or PPTX export
skills/design-foundations/SKILL.md for palette, fonts + pairings, chart colors, and core principles (1 accent + neutrals, no decorative imagery, accessibility). Below is slides-specific guidance.skills/design-foundations/SKILL.md for the full "Earn Every Color" philosophy, contrast rules, and the custom-palette workflow (user hue → derive surfaces by desaturating → test contrast).#22808D only where emphasis is needed (see skills/design-foundations/SKILL.md).skills/design-foundations/SKILL.md for font pairings (Slides Pairings table) and size hierarchy. Default to professional sans-serif. Use serif for headings only when formal tone is needed.margin: 0 on the text box or offset the shape to account for paddingborder-left: 3px solid <accent> is another AI-generated hallmark. Use background color, subtle neutral borders, or whitespace to separate content blocksbullet: true on large stat text — bullets at 60-72pt render as giant dots. Only use bullets on body-sized text (14-16pt)bullet: true on all text in a slide — bullet points should only be used for actual lists of 3+ items. Don't bullet a title, subtitle, description, or stat. Bullets on every text element makes slides look like a Word document\$1.2M, \$1,200K, or implied thousands) and apply it to every figure in a table or chart. Never mix suffixed and implied-thousands values in the same view. Use parentheses for negatives in financials ((\$1,234)).<a href="..."> link. In PPTX (pptxgenjs), use an array of text objects with hyperlink options:slide.addText([
{ text: "Source: " },
{ text: "Reuters", options: { hyperlink: { url: "https://reuters.com/article/123" } } },
{ text: ", " },
{ text: "WHO", options: { hyperlink: { url: "https://who.int/publications/m/item/update-42" } } },
{ text: ", " },
{ text: "World Bank", options: { hyperlink: { url: "https://worldbank.org/en/topic/water" } } }
], { x: 0.5, y: 5.2, w: 9, h: 0.3 });
hyperlink.url with the full https:// URL — never omit hyperlinks"Sources: WHO, Reuters, UNICEF" (plain text, no hyperlinks)"Source: WHO, https://who.int/report/123" (raw URL in text instead of hyperlink)[{ text: "WHO", options: { hyperlink: { url: "https://who.int/report/123" } } }] (clickable name)export_pptx action — when the user explicitly wants a plain, fully native PowerPoint file: generated from scratch for maximum PowerPoint-editability, or built from/edited against an existing .pptx template the user handed you. The HTML deck's export_pptx action is screenshot-based (a rendered background image + overlaid editable text boxes) and is the fastest route to a downloadable .pptx — reach for the techniques below when the user needs a deck that's natively structured throughout (every shape, table, and chart is a real PowerPoint object) or needs an existing PowerPoint template edited in place.| Objective | Technique | Reference |
|---|---|---|
| Extract text or data | anydoc presentation.pptx | Also: scripts/slides.py thumbnail for visual grid |
| Modify an existing file or template | Unpack to XML, edit, repack | See PPTX-EDITING.md [blocked] |
| Generate a deck from scratch | JavaScript with pptxgenjs | See PPTX-CREATING.md [blocked] |
soffice), Poppler (pdftoppm), and anydoc are installed system tools. Python packages such as lxml, pillow, python-pptx, playwright, and markitdown[pptx] are pre-installed — run scripts with python3. Use uv run --with <package> only for a package that is not pre-installed. Project-local Node packages provide pptxgenjs, React, and Sharp.skills/presentations/scripts/: repair.py (fix pptxgenjs OOXML bugs), unpack.py / pack.py (unpack a .pptx to editable XML and repack it), slides.py (clean / add / thumbnail subcommands for slide-level XML surgery).anydoc output.pptx
anydoc output.pptx | grep -iE "xxxx|lorem|ipsum|this.*(page|slide).*layout"
soffice --headless --convert-to pdf output.pptx
pdftoppm -jpeg -r 150 output.pdf slide
ls slide-*.jpg # always ls — zero-padding varies by page count
session_start_background, or session_spawn if the alias is what the runtime exposes). Give it the slide image paths plus a prompt like this:Visually inspect these slides. Assume there are issues — find them.
Check for: stray dots/circles (orphan shapes, bullets at display size), overlapping elements, text overflow/cutoff, decorative lines mispositioned after title wrap, source footers colliding with content, elements too close (< 0.3" gaps), uneven spacing, insufficient slide-edge margins (< 0.5"), misaligned columns, low-contrast text or icons, narrow text boxes causing excessive wrapping, and leftover placeholder content.
For each slide, list every issue found, even minor ones.
session_read and treat the returned review as the visual QA checklist.soffice + pdftoppm)pdftoppm -jpeg -r 150 -f N -l N output.pdf slide-fixed
ls slide-fixed-*.jpg
.pptx file, which renders inline for the user. Surface it directly:show(type="file", path="/workspace/output.pptx")
Generate (pptxgenjs, see PPTX-CREATING.md) or edit (unpack/edit XML/repack, see PPTX-EDITING.md)
→ repair.py (if generated with pptxgenjs) → Content QA → Visual QA (background session) → fix-and-verify → deliver
Start with one job and grow from there.