---
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.
