PPTX Editor
Edit PowerPoint files programmatically using python-pptx while preserving visual consistency with the existing deck.
Why this skill exists
PowerPoint editing through code is error-prone because small mismatches in background color, font inheritance, shape positioning, or line styling make new slides look obviously wrong next to existing ones. This skill enforces a "inspect first, match exactly" workflow that prevents those mismatches.
Core workflow
Every PPTX edit follows three phases: Inspect, Edit, Verify. Never skip the inspect phase - it is what prevents visual mismatches.
Phase 1: Inspect the existing deck
Before making any changes, run the inspect script to extract the deck's design system. This is non-negotiable because presentations vary wildly in how they're built - some use layouts, some use manual shapes, some mix both.
python3 .claude/skills/pptx-editor/scripts/inspect-deck.py <path-to-pptx>
The script extracts every shape, text style, color, position, and font across all slides, then prints a design token summary at the end.
From this output, build a mental model of the deck's design tokens:
| Token |
What to capture |
Why it matters |
| Background |
Solid color RGB or theme reference |
New slides without this look white against dark decks |
| Accent color |
The color used for bars, separators, labels |
Usually one dominant accent throughout |
| Heading style |
Font size, bold, color, position |
Titles must match exactly |
| Body style |
Font size, bold/None, color |
Subtle: bold=None is different from bold=False |
| Font typeface |
Explicit name or THEME inheritance |
If existing slides use THEME, new slides must NOT set font.name |
| Decorative shapes |
Top bars, separators - exact position, size, fill, line style |
These define the visual rhythm of the deck |
| Text positions |
Left margin, top positions for titles, bodies, footers |
Consistent alignment across slides |
Phase 2: Edit the deck
Build new or modified slides using the exact values from Phase 1.
Critical rules:
Set the slide background explicitly. The Blank layout does not inherit the master slide background in python-pptx. Always set it:
slide.background.fill.solid()
slide.background.fill.fore_color.rgb = RGBColor(0x0D, 0x0D, 0x0D)
Match font inheritance. If existing slides use theme fonts (no explicit typeface), do NOT set font.name on new text. Setting it forces an explicit typeface that may render differently:
# CORRECT - inherits theme font
run = p.add_run()
run.text = "Hello"
run.font.size = Emu(457200)
run.font.bold = True
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
# Do NOT set run.font.name
# WRONG - overrides theme font
run.font.name = "Calibri" # Don't do this if originals use theme
Reproduce decorative shapes exactly. Copy the position, size, fill color, and line style from the inspection. Pay special attention to:
# Line style must match - most decks use background (invisible) lines
shape.line.fill.background()
shape.line.width = 0
Use Emu units consistently. The inspection gives values in EMUs. Use them directly - do not convert to Inches or Pt and back, because rounding errors accumulate.
Preserve bold=None vs bold=True vs bold=False. In python-pptx, None means "inherit from style", False means "explicitly not bold", and True means "explicitly bold". Match what existing slides use.
Add hyperlinks correctly. Use run.hyperlink.address, not shape-level links:
run = p.add_run()
run.text = "linkedin.com/in/someone"
run.font.size = Emu(228600)
run.font.color.rgb = WHITE
run.hyperlink.address = "https://www.linkedin.com/in/someone"
Delete slides properly when replacing them:
from pptx.oxml.ns import qn
rId = prs.slides._sldIdLst[index].get(qn('r:id'))
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[index]
Delete from highest index first when removing multiple slides.
Phase 3: Verify
After saving, run a verification script that compares the new slides against existing ones:
# Check that new slides match the design system
for idx in [<new_slide_indices>]:
slide = prs.slides[idx]
bg_color = slide.background.fill.fore_color.rgb if slide.background.fill.type else "MISSING"
print(f"Slide {idx+1}: background={bg_color}")
Confirm:
- Background color matches existing slides
- Top decorative shapes are present with correct position/size/color
- Text colors and sizes match equivalent elements on other slides
- No explicit font names set when originals use theme fonts
Common operations
Adding slides to the end
Use prs.slides.add_slide(layout). Always use the same layout as existing slides (inspect first to find which one).
Editing text on existing slides
Find the shape by name or by iterating, then modify shape.text_frame.paragraphs[n].runs[m].
Reordering slides
python-pptx does not have a native reorder API. To move a slide, you need to manipulate the XML directly by reordering elements in prs.slides._sldIdLst.
Changing styling across all slides
Use replace_all-style loops. Extract the current value first to avoid changing things that shouldn't change.
Dependencies
Requires python-pptx. Install with:
pip3 install python-pptx
Reference
scripts/inspect-deck.py - Run this in Phase 1 to extract design tokens from any PPTX file.
references/design-tokens-checklist.md - Copy-paste checklist to fill in during the inspect phase.
1---2name: pptx-editor3description: Edit, update, and add slides to PowerPoint (.pptx) files using python-pptx. Use this skill whenever the user wants to modify a presentation - adding slides, editing text, changing styling, reordering slides, inserting links, or fixing design consistency. Trigger on any mention of "slide", "presentation", "PowerPoint", "pptx", "deck", "add a slide", "update the slide", "fix the slides", "last slide", "thank you slide", or any request involving .pptx files - even if the user just references a .pptx path without explicitly saying "edit".4---56# PPTX Editor78Edit PowerPoint files programmatically using python-pptx while preserving visual consistency with the existing deck.910## Why this skill exists1112PowerPoint editing through code is error-prone because small mismatches in background color, font inheritance, shape positioning, or line styling make new slides look obviously wrong next to existing ones. This skill enforces a "inspect first, match exactly" workflow that prevents those mismatches.1314## Core workflow1516Every PPTX edit follows three phases: **Inspect, Edit, Verify**. Never skip the inspect phase - it is what prevents visual mismatches.1718### Phase 1: Inspect the existing deck1920Before making any changes, run the inspect script to extract the deck's design system. This is non-negotiable because presentations vary wildly in how they're built - some use layouts, some use manual shapes, some mix both.2122```bash23python3 .claude/skills/pptx-editor/scripts/inspect-deck.py <path-to-pptx>24```2526The script extracts every shape, text style, color, position, and font across all slides, then prints a design token summary at the end.2728From this output, build a mental model of the deck's design tokens:2930| Token | What to capture | Why it matters |31|-------|----------------|----------------|32| Background | Solid color RGB or theme reference | New slides without this look white against dark decks |33| Accent color | The color used for bars, separators, labels | Usually one dominant accent throughout |34| Heading style | Font size, bold, color, position | Titles must match exactly |35| Body style | Font size, bold/None, color | Subtle: bold=None is different from bold=False |36| Font typeface | Explicit name or THEME inheritance | If existing slides use THEME, new slides must NOT set font.name |37| Decorative shapes | Top bars, separators - exact position, size, fill, line style | These define the visual rhythm of the deck |38| Text positions | Left margin, top positions for titles, bodies, footers | Consistent alignment across slides |3940### Phase 2: Edit the deck4142Build new or modified slides using the exact values from Phase 1.4344**Critical rules:**45461. **Set the slide background explicitly.** The Blank layout does not inherit the master slide background in python-pptx. Always set it:47 ```python48 slide.background.fill.solid()49 slide.background.fill.fore_color.rgb = RGBColor(0x0D, 0x0D, 0x0D)50 ```51522. **Match font inheritance.** If existing slides use theme fonts (no explicit typeface), do NOT set `font.name` on new text. Setting it forces an explicit typeface that may render differently:53 ```python54 # CORRECT - inherits theme font55 run = p.add_run()56 run.text = "Hello"57 run.font.size = Emu(457200)58 run.font.bold = True59 run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)60 # Do NOT set run.font.name6162 # WRONG - overrides theme font63 run.font.name = "Calibri" # Don't do this if originals use theme64 ```65663. **Reproduce decorative shapes exactly.** Copy the position, size, fill color, and line style from the inspection. Pay special attention to:67 ```python68 # Line style must match - most decks use background (invisible) lines69 shape.line.fill.background()70 shape.line.width = 071 ```72734. **Use Emu units consistently.** The inspection gives values in EMUs. Use them directly - do not convert to Inches or Pt and back, because rounding errors accumulate.74755. **Preserve bold=None vs bold=True vs bold=False.** In python-pptx, `None` means "inherit from style", `False` means "explicitly not bold", and `True` means "explicitly bold". Match what existing slides use.76776. **Add hyperlinks correctly.** Use `run.hyperlink.address`, not shape-level links:78 ```python79 run = p.add_run()80 run.text = "linkedin.com/in/someone"81 run.font.size = Emu(228600)82 run.font.color.rgb = WHITE83 run.hyperlink.address = "https://www.linkedin.com/in/someone"84 ```85867. **Delete slides properly** when replacing them:87 ```python88 from pptx.oxml.ns import qn89 rId = prs.slides._sldIdLst[index].get(qn('r:id'))90 prs.part.drop_rel(rId)91 del prs.slides._sldIdLst[index]92 ```93 Delete from highest index first when removing multiple slides.9495### Phase 3: Verify9697After saving, run a verification script that compares the new slides against existing ones:9899```python100# Check that new slides match the design system101for idx in [<new_slide_indices>]:102 slide = prs.slides[idx]103 bg_color = slide.background.fill.fore_color.rgb if slide.background.fill.type else "MISSING"104 print(f"Slide {idx+1}: background={bg_color}")105```106107Confirm:108- Background color matches existing slides109- Top decorative shapes are present with correct position/size/color110- Text colors and sizes match equivalent elements on other slides111- No explicit font names set when originals use theme fonts112113## Common operations114115### Adding slides to the end116Use `prs.slides.add_slide(layout)`. Always use the same layout as existing slides (inspect first to find which one).117118### Editing text on existing slides119Find the shape by name or by iterating, then modify `shape.text_frame.paragraphs[n].runs[m]`.120121### Reordering slides122python-pptx does not have a native reorder API. To move a slide, you need to manipulate the XML directly by reordering elements in `prs.slides._sldIdLst`.123124### Changing styling across all slides125Use `replace_all`-style loops. Extract the current value first to avoid changing things that shouldn't change.126127## Dependencies128129Requires `python-pptx`. Install with:130```bash131pip3 install python-pptx132```133134## Reference135136- `scripts/inspect-deck.py` - Run this in Phase 1 to extract design tokens from any PPTX file.137- `references/design-tokens-checklist.md` - Copy-paste checklist to fill in during the inspect phase.