Skip to content
Back to skills

building-powerpoint-decks

ASecurity

Build, edit, audit and present PowerPoint decks with Claude — via the powerpoint-mcp server and COM on Windows, or python-pptx anywhere. Load when creating or editing a .pptx, auditing a deck, preparing to present one, adding animation, video or AI images to slides, or when PowerPoint MCP tools are missing or failing.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 7, 2026
ai-agentspythonrustgoreact

Works with

  • mcp

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned October 7, 2026

npx -y skills add PeterKalmstrom/claude-powerpoint-skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of building-powerpoint-decks?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for building-powerpoint-decks
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/peterkalmstrom-building-powerpoint-decks/badge)](https://www.skillsdirectory.com/skills/peterkalmstrom-building-powerpoint-decks)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: building-powerpoint-decks
description: Build, edit, audit and present PowerPoint decks with Claude — via the powerpoint-mcp server and COM on Windows, or python-pptx anywhere. Load when creating or editing a .pptx, auditing a deck, preparing to present one, adding animation, video or AI images to slides, or when PowerPoint MCP tools are missing or failing.
---

# Building PowerPoint decks

Rules, traps and helper scripts for producing decks that render correctly the first time. Detail lives in
[`reference/`](reference/); helper scripts in [`scripts/`](scripts/README.md). Read this file fully, then open
only the reference file the task needs.

## Start here

| Task | Read, in order |
|---|---|
| **New deck** | Audience → claim titles → word budgets ([CONTENT](reference/CONTENT.md), [LAYOUT](reference/LAYOUT.md)) · write a spec and build it with `scripts/build_deck.py` ([BUILDER](reference/BUILDER.md), looks in [DESIGN](reference/DESIGN.md)) · showcase-first (below) · the build loop (below) |
| **Edit an existing deck** | Snapshot first · `scripts/read_deck.py` before judging ([AUDIT](reference/AUDIT.md)) · find the open deck by name ([COM](reference/COM.md)) · rebuilding a generated deck? `scripts/harvest_edits.py` first |
| **Review / audit a deck** | `scripts/lint_deck.py` first (any OS), then [AUDIT](reference/AUDIT.md): taste pass → anchor exceptions → contact sheet |
| **Before a talk** | Audit clean first, then [PRESENTING](reference/PRESENTING.md) |
| **Images, video, Remotion, Veo** | [MEDIA](reference/MEDIA.md), then [ANIMATION](reference/ANIMATION.md) if it moves |
| **PowerPoint tools missing / MCP failing** | [SETUP](reference/SETUP.md) → Troubleshooting |
| **No Windows (Linux, macOS, CI)** | [AUTOMATION](reference/AUTOMATION.md) → *Building .pptx without PowerPoint* |
| **Company template / brand** | `scripts/extract_theme.py` → [LAYOUT](reference/LAYOUT.md) → *Building from a template* |
| **Corporate / labelled deck** | [LABELS](reference/LABELS.md) before choosing a toolchain |

## Reference files

| File | Covers | Runs on |
|---|---|---|
| [SETUP.md](reference/SETUP.md) | Installing `powerpoint-mcp`, troubleshooting, MCP tool list | Windows + PowerPoint |
| [COM.md](reference/COM.md) | Snapshots, multi-deck safety, UTF-8, idempotent builds, keeping hand edits, shape filtering | Windows + PowerPoint |
| [LAYOUT.md](reference/LAYOUT.md) | Slide size, pictures, text wrap, embedded fonts, word budgets, anchor types, layout patterns | Mostly any OS; rendering needs Windows |
| [MEDIA.md](reference/MEDIA.md) | AI images, Remotion, Veo, compression, embedding, combined patterns | Generation any OS; embedding Windows |
| [ANIMATION.md](reference/ANIMATION.md) | When motion earns its place, effect table, native timing traps | Any OS (COM/XML parts marked) |
| [BUILDER.md](reference/BUILDER.md) | Spec-driven deck builder: patterns, limits, chart and type defaults | Any OS |
| [DESIGN.md](reference/DESIGN.md) | Type scale for Full HD, spacing, chart and table defaults, 20 design directions | Any OS |
| [CONTENT.md](reference/CONTENT.md) | Audience, claim titles, cognitive load, speaker notes, showcase-first | Any OS |
| [AUDIT.md](reference/AUDIT.md) | Lint codes, reading a whole deck, defect catalogue with severities, full audit procedure | Scripts Windows; catalogue any OS |
| [PRESENTING.md](reference/PRESENTING.md) | Timing markers, Q&A sheet, notes PDF, rehearsal | Windows + PowerPoint |
| [AUTOMATION.md](reference/AUTOMATION.md) | Headless PowerPoint for checks, building .pptx without COM | Headless Windows; no-COM any OS |
| [LABELS.md](reference/LABELS.md) | Sensitivity labels and what encryption breaks | Any OS |

## Core rules

These apply to every deck. Each links to its full explanation.

1. **Snapshot before anything destructive** — `scripts/backup_snapshot.py`. Undo is not a backup. ([COM](reference/COM.md#snapshot-before-any-risky-bulk-edit))
2. **Never trust `ActivePresentation`** — find the deck by exact name, then substring. ([COM](reference/COM.md#multi-presentation-safety--never-trust-activepresentation))
3. **Rebuild, don't patch** — one idempotent `build_slide_NN.py` per non-trivial slide; name every shape. Three patches = rewrite. ([COM](reference/COM.md#idempotent-build-scripts))
4. **Never overwrite people's edits** — `scripts/harvest_edits.py` before regenerating a deck. ([COM](reference/COM.md#a-generated-deck-that-people-also-edit-in-powerpoint-harvest-before-you-overwrite))
5. **Full HD = 1440 × 810 pt**, set before inserting slides. ([LAYOUT](reference/LAYOUT.md#slide-size--set-it-before-inserting-anything))
6. **About 10 visible words per slide (by anchor type), body ≥ 18 pt on a 960-pt slide — ≥ 27 pt on Full HD (1440 pt)**, claim titles. ([LAYOUT](reference/LAYOUT.md#anchor-types-and-word-budgets), [CONTENT](reference/CONTENT.md#titles-make-a-claim-not-a-topic))
7. **No text baked into images or video** — overlay it in PowerPoint. ([MEDIA](reference/MEDIA.md#generate-images-without-text--overlay-text-in-powerpoint))
8. **Crop pictures, never stretch them.** ([LAYOUT](reference/LAYOUT.md#pictures-stretch--crop-to-fill-never-pass-both-sizes-blindly))
9. **The slide carries the punch, the notes carry the depth** — notes first, fixed order. ([CONTENT](reference/CONTENT.md#write-the-notes-first-in-a-fixed-order))
10. **Lint, then render and LOOK** before calling anything done — `scripts/lint_deck.py` catches what the file shows (overlaps, stretched pictures, small text, missing alt text) on any OS; the render catches the rest. Render via Save As JPEG on Windows, not `Slide.Export`; `scripts/render_lo.py` elsewhere (approximate). (Loop below; [LAYOUT](reference/LAYOUT.md#embedded-fonts-slideexport-renders-a-fallback--use-save-as-jpeg))

## Showcase-first for multi-slide sections

For any section of **4+ slides** that share a design, build the opener and one detail slide first, render both,
and ask the user to approve before producing the rest. Iterating slide 1 of 6 is cheap; rebuilding all six in the
wrong design is not.

## Workflow

The five-step iteration loop that catches silent rendering failures. Use it for every slide edit.

### Iteration loop — build, render, LOOK, critique, fix

**Rule:** every slide edit follows the same five-step loop. Step 3 is the one that gets skipped. Don't skip it.

```
1. Build / edit (idempotent script)
2. Render via presentation.SaveCopyAs(folder, 17)  (Save As JPEG — scripts/render_slides.py)
   slide.Export is fine ONLY when every font in the deck is installed; never for embedded fonts
3. LOOK at the actual rendered image  ←  DO NOT SKIP
4. Lint (scripts/lint_deck.py), then self-critique against the defect catalogue (reference/AUDIT.md)
5. Fix → loop back to step 2,  OR  save → done
```

**Why step 3 matters:** PowerPoint COM properties lie about what you'll see. Rendered PNG is ground truth. Specific silent failures that only show in the render:

- Text wraps to 2 lines despite "fitting" on paper
- Backing rectangle and text desync after one is moved without the other
- Shape stays behind another due to z-order, invisible in render
- Image cache holds the old version after file replacement
- Title placeholder appears empty in COM but renders white-on-white text
- AutoShape rectangles match `HasTextFrame == True`, breaking filter logic

The tool returning `success: true` is *the tool's claim*, not evidence. The PNG is evidence.

**Loop budget:** if 3 fix attempts on the same defect haven't worked, escalate:

- Check if the rule itself is wrong for this anchor type (gallery, knowledge graph, quote — see [Anchor types and word budgets](reference/LAYOUT.md#anchor-types-and-word-budgets))
- Switch from patch to full rebuild — patches drift after the third one
- Ask the user — the expected output may itself be wrong

Never run more than 4 iterations on the same defect without escalating.

**Anti-patterns to recognise:**

- *Source-look-only iteration* — reading COM properties or script values, declaring success without exporting
- *Patch on patch on patch* — each patch tweaks one element without considering layout interactions; backing rectangles drift, z-order shifts, third patch produces shape soup. **Three patches = rewrite the build script.**
- *Tool-output as ground truth* — `{"success": true}` from an MCP tool is not the same as a correctly rendered slide
- *Optimistic font sizing* — "36pt should fit" is a guess until the PNG confirms it
- *Caching trust* — replacing an image at the same path doesn't always update the embedded version; re-add the picture explicitly
- *Active context drift* — see [Multi-presentation safety](reference/COM.md#multi-presentation-safety--never-trust-activepresentation); pin to a specific presentation by name, never trust `ActivePresentation`

## Version-specific facts (as of 2026-10)

These depend on upstream releases. Re-check them when something that used to work breaks:

- `powerpoint-mcp` 1.30.0 needs `--with "mcp<2"` in the uvx args ([SETUP](reference/SETUP.md#connection_closed-at-startup-no-module-named-mcpserverfastmcp)).
- Veo model ids `veo-3.1-generate-preview` and `veo-3.1-fast-generate-preview` are confirmed; a `lite` id is not ([MEDIA](reference/MEDIA.md#key-details)).
- The MCP's `slide_snapshot` renders through `Slide.Export`, so it shows fallback fonts for embedded fonts.
- python-pptx 1.0.2 behaviour is assumed in the slide-copy notes ([COM](reference/COM.md#a-generated-deck-that-people-also-edit-in-powerpoint-harvest-before-you-overwrite)).

---

## Anti-patterns (recurring COM / build traps)

A consolidated catalog of the silent failures that have actually shipped broken slides. Skim this list whenever you're about to write a non-trivial COM patch — most of these fail without raising an error, so they don't show up in stack traces.

| Anti-pattern | What goes wrong | See |
|---|---|---|
| Trusting `app.ActivePresentation` | Targets the wrong deck if another window has focus | [Multi-presentation safety](reference/COM.md#multi-presentation-safety--never-trust-activepresentation) |
| `if not sh.HasTextFrame:` filter | Silently skips AutoShapes (they have empty text frames) | [Filtering shapes](reference/COM.md#filtering-shapes--hastextframe-is-not-is-this-a-text-shape) |
| Moving text without moving its backing | Text floats outside its card or off-slide | [Move text and its backing together](reference/COM.md#move-text-and-its-backing-together) |
| Patching a 5+ shape slide instead of rebuilding | Z-order drifts, conditional filters miss shapes, layout never quite matches | [Idempotent build scripts](reference/COM.md#idempotent-build-scripts) |
| Skipping the LOOK step (step 3 of the loop) | Code "succeeds" but the rendered slide is wrong | [Iteration loop](#iteration-loop--build-render-look-critique-fix) |
| Re-prompting an AI image after 2 text-baked attempts | Wastes budget; the model is locked into baking text | [Generate images WITHOUT text](reference/MEDIA.md#generate-images-without-text--overlay-text-in-powerpoint) |
| Re-prompting Veo for a physics chain reaction | Diffusion video reliably fails dominoes / cradle / pool break | [Known limits — when not to use Veo](reference/MEDIA.md#known-limits--when-not-to-use-veo) |
| Inline reimplementation of helper logic | Drifts from canonical version, no `--quiet` flag, no error stream propagation | [Wrapping Python helpers via subprocess + uvx](reference/MEDIA.md#wrapping-python-helpers-via-subprocess--uvx) |
| Author-name marker for notes-append idempotency | Marker mismatches actual citation format ("X & Y" vs "X T., Y Q."), block gets appended every re-run | [Idempotent notes appending](reference/CONTENT.md#idempotent-notes-appending--use-the-doi-not-author-names) |
| Missing UTF-8 stdout in scripts that `print()` Unicode | Script crashes *after* `target.Save()` succeeds; operator re-runs and double-applies append-style work | [Force UTF-8 stdout](reference/COM.md#force-utf-8-stdout-in-any-script-that-prints-unicode) |
| Sentinel-text check uses a phrase from the pre-build slide | Idempotency check skips structural step (Duplicate / Insert), then rewrites text — destroys adjacent unrelated slides | [Idempotent build scripts](reference/COM.md#idempotent-build-scripts) (Sentinel rule) |
| `AddPicture` to replace a picture inside a Group | New picture lands as a sibling outside the group; old picture remains; layout breaks | [Swapping a picture inside a Group](reference/MEDIA.md#swapping-a-picture-that-lives-inside-a-group) |
| Hardcoded `OUT = r"C:\Users\<somebody>\..."` in chart scripts | Script does nothing useful on any other machine; PNG fails to update; embedded chart looks stale forever | [Portable OUT paths](reference/MEDIA.md#portable-out-paths-in-chart-scripts) |
| Trusting `Slide.Export` / `slide_snapshot` for decks with embedded fonts | Renders a fallback font; real mid-word breaks look clean and pass review | [Embedded fonts](reference/LAYOUT.md#embedded-fonts-slideexport-renders-a-fallback--use-save-as-jpeg) |
| Pinning nothing in the uvx args | A new `mcp` 2.x release kills the server at startup (`CONNECTION_CLOSED`) | [`CONNECTION_CLOSED` at startup](reference/SETUP.md#connection_closed-at-startup-no-module-named-mcpserverfastmcp) |
| Rebuilding a generated deck over a hand-edited one | A day of human edits silently erased | [Harvest before you overwrite](reference/COM.md#a-generated-deck-that-people-also-edit-in-powerpoint-harvest-before-you-overwrite) |
| `Presentations.Add()` then `InsertFromFile` without setting the size | Whole deck silently scaled to 720p, all fonts a third smaller | [Slide size](reference/LAYOUT.md#slide-size--set-it-before-inserting-anything) |
| `AddPicture` / `add_picture` with both width and height | Photos stretched by up to ~60 %, unnoticed | [Pictures stretch](reference/LAYOUT.md#pictures-stretch--crop-to-fill-never-pass-both-sizes-blindly) |
| Validating a generated .pptx with `DisplayAlerts` off | PowerPoint silently repairs the broken file and the check passes | [Headless PowerPoint](reference/AUTOMATION.md#headless-powerpoint-for-checks) |
| Embedding raw Veo / Remotion MP4s | Deck balloons by hundreds of MB; some installs won't play non-H.264 | [Embedding video](reference/MEDIA.md#embedding-video-remotion-output) |
| Chaining effects with "After Previous" | One slow effect shifts every later one; builds drift | [Native animation traps](reference/ANIMATION.md#native-animation-traps) |
| Rebuilding an encrypted / labelled deck with python-pptx or `Presentations.Add()` | Output carries no sensitivity label — confidential content leaks unlabelled | [Sensitivity labels](reference/LABELS.md#sensitivity-labels) |
| Calling `ExportAsFixedFormat` positionally from pywin32 | `TypeError: The Python instance can not be converted to a COM object` — no PDF | [Presenter prep](reference/PRESENTING.md#presenter-prep) |
| `for p in app.Presentations: if ...: target = p` without `break` | Picks the *last* matching presentation in enumeration order (effectively random when multiple match the substring) | [Multi-presentation safety](reference/COM.md#multi-presentation-safety--never-trust-activepresentation) |

When one of these bites, fix it and **add a row here** if it's a new variant. The signal is: "I lost an hour to a silent failure" → it belongs in this table.

Files in this skill

  • CHANGELOG.md5.1 KB
  • CONTRIBUTING.md3.7 KB
  • NOTICE952 B
  • SKILL.md15.1 KB
  • evals/README.md1 KB
  • evals/trigger-evals.json3.4 KB
  • reference/ANIMATION.md2.9 KB
  • reference/AUDIT.md14.2 KB
  • reference/AUTOMATION.md4 KB
  • reference/BUILDER.md5.9 KB
  • reference/COM.md13.3 KB
  • reference/CONTENT.md6.5 KB
  • reference/DESIGN.md5.9 KB
  • reference/LABELS.md1.9 KB
  • reference/LAYOUT.md15.4 KB
  • reference/MEDIA.md21.8 KB
  • reference/PRESENTING.md2 KB
  • reference/SETUP.md8 KB
  • scripts/README.md3.1 KB
  • scripts/_measure.py5.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…