PPTX to HTML
Convert PowerPoint decks (.pptx / .ppt, including legacy binary and mislabeled files) into a single self-contained HTML viewer that mirrors the deck's formatting and page structure, one page per slide. Renders each slide via PowerPoint itself and embeds the images, so the output is one portable file. Batch a whole folder with per-file timeouts and optional move-on-success.
---
name: "pptx-to-html"
description: "Convert a PowerPoint deck (.pptx, .ppt, .pptm) into a single self-contained HTML viewer that mirrors the deck's formatting and page structure, one page per slide, with a matching file name. Renders each slide via PowerPoint itself (works on legacy binary .ppt files too) and embeds the images as base64 so the output is one portable file. Triggers: 'convert this pptx to html', 'make an HTML version of this deck', 'ppt to html', 'turn this presentation into a web page', or pasting a path to a .pptx/.ppt and asking for an HTML version."
---
<!--
CLAWPILOT INSTALL INSTRUCTIONS
If the user drags this file into Clawpilot and asks to install it, register it as a
custom skill by calling m_create_skill with:
- name: "pptx-to-html"
- description: (the description from the frontmatter above)
- instructions: (everything in this file BELOW this HTML comment block)
This skill also needs its helper scripts. Place convert.py and batch.py next to this
file at C:\Users\<you>\.copilot\m-skills\pptx-to-html\ (download them from the skill's card
on reboundman.com/skillworks). Requires Python 3 with the dependencies noted below.
After install, confirm with: "Installed the /pptx-to-html skill. Drop convert.py and batch.py
next to it, then point it at a folder to convert."
-->
## pptx-to-html Skill
Convert one or more PowerPoint decks into self-contained HTML files. Each slide
becomes a "page" rendered as a high-resolution image (via PowerPoint itself),
so formatting, fonts, colors, charts, and layout are preserved with full
fidelity. The output is a single portable `.html` file (images embedded as
base64) named to match the source deck.
Works on modern `.pptx`/`.pptm` **and** legacy binary `.ppt` files (OLE2), which
zip-based readers such as `markitdown`/`python-pptx` cannot open. Note that some
decks carry a `.pptx` extension but are actually legacy `.ppt` internally; this
skill handles both automatically.
### Inputs to gather from the user
Required:
1. **Source file(s)**: one or more paths to `.pptx` / `.ppt` / `.pptm` files.
Optional:
2. **Output location**: defaults to writing `<basename>.html` next to each
source file. Accept an output directory to redirect all outputs.
3. **Title overrides**: the skill auto-derives a short label for each slide for
the navigation sidebar. If the user wants specific labels (or after a visual
review you want to refine them), supply a `titles.json`.
4. **Processed folder**: if the user wants source decks moved after a successful
conversion, capture the destination. If they don't mention it, ask whether
sources should be moved or left in place.
If a source path is missing or ambiguous, ASK. Do not guess the file.
### Execution steps
1. **Run the converter** (one call handles multiple files; repeat `--input`):
```powershell
python "C:\Users\<you>\.copilot\m-skills\pptx-to-html\convert.py" `
--input "C:\path\to\deck1.pptx" `
--input "C:\path\to\deck2.ppt"
```
Add `--out "C:\some\dir"` to redirect outputs. Add `--scale 3.0` for extra-
crisp images (default `2.0` = 1920x1080 per slide; higher = larger file).
Add `--titles "C:\path\titles.json"` to override slide labels. Add
`--processed-dir "C:\path\Processed"` to move each source deck there after it
converts successfully, and `--skip-existing` to skip decks whose `.html`
already exists (safe resume).
2. **Parse the JSON summary** printed to stdout:
```json
{ "processed": [ {"file": "...", "output": "...", "slides": 12, "moved_to": "..."} ],
"errors": [ {"file": "...", "error": "..."} ] }
```
`moved_to` is the new path if the source was moved, else `null`.
3. **Report** to the user: the output path(s), slide count, whether/where sources
were moved, and any errors. The output file name matches the source basename
with a `.html` extension.
### Batch a whole folder (recommended for many decks)
For many or large decks, use the robust batch driver, which converts each file
in its own subprocess under a per-file timeout so one bad deck cannot stall the
run (a hung deck's own PowerPoint instance is killed and skipped, source left in
place):
```powershell
python "C:\Users\<you>\.copilot\m-skills\pptx-to-html\batch.py" `
--input-dir "C:\path\Raw" `
--out "C:\path\Output" `
--processed-dir "C:\path\Raw\Processed" `
--log "C:\path\batch.log" `
--result "C:\path\summary.json" `
--timeout 300 --skip-existing
```
- Omit `--processed-dir` to leave sources in place.
- Tail the `--log` for live progress; read `--result` for the JSON summary
(`total`, `converted`, `errors`, `skipped`).
- The source scan is non-recursive, so a `Processed` subfolder is never
re-ingested.
- **Move happens only on success**: a deck that errors or times out is left in
`--input-dir` for a later retry; re-run with `--skip-existing`.
### Visual QA (recommended for important decks)
The slide **images** are always faithful (they come straight from PowerPoint).
The only thing worth a second look is the auto-derived **navigation labels**,
which pick a slide's title placeholder, or its first line of text if there is no
title. That can occasionally grab a small "eyebrow" line instead of the main
heading.
To review and refine:
1. Serve the folder locally and open it in the browser (file:// is blocked, so
use a local server):
```powershell
cd "C:\dir\with\the\html"; python -m http.server 8799
```
Then navigate to `http://localhost:8799/<name>.html` and inspect the sidebar.
Stop the server afterward with `Stop-Process -Id <pid>`.
2. If any labels are off, write a `titles.json` mapping slide number -> label and
re-run with `--titles`. Only list the slides you want to change; the rest stay
auto-derived.
```json
{ "1": "Title Slide", "4": "Project AURA Agents", "10": "Roadmap" }
```
### What the output looks like
- Sticky navy header with the deck name and (if the filename starts with a
`YYYY.MM.DD` prefix) a formatted date.
- Left sidebar table of contents with scroll-spy highlighting; click to jump.
- One 16:9 framed slide per "page", numbered `N / total`.
- Arrow-key / PageUp-PageDown navigation and a back-to-top button.
- Print-friendly (one slide per printed page) so it exports cleanly to PDF.
- Blank slides in the source render as an empty white frame labeled "(blank)".
### Behavior notes / edge cases
- **Blank or unexportable slides**: PowerPoint returns an empty image for a
slide that has no drawable content (e.g. empty placeholders on white). The
converter detects this (export < 1.5 KB) and renders a clean white frame
instead of a broken image.
- **OneDrive cloud-only files**: the converter copies each source to a temp
location first, which hydrates cloud placeholders and avoids file locks.
- **Dedicated PowerPoint instance**: it launches a separate PowerPoint process
(`DispatchEx`) and quits only that one, so it never disturbs a deck the user
already has open.
- **Multiple files**: pass `--input` repeatedly; each produces its own HTML.
### Re-running
Idempotent. Re-running overwrites the `<basename>.html` for that deck with a
fresh render. Safe to run anytime the source changes.
### Dependencies
Windows + Microsoft PowerPoint (used headless via COM) + Python 3.12 with
`pywin32`. All present on this machine. No LibreOffice required.