| name | pptx |
| description | Use this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting |
PPTX creation, editing, and analysis
A .pptx is a ZIP archive of XML files. Choose your approach by task:
| Task | Approach |
|---|
| Create a new deck | Write a pptxgenjs script — see gotchas below |
| Edit an existing deck, or build from a template | unzip → edit ppt/slides/slideN.xml → zip |
| Read content | markitdown deck.pptx (one block per slide under <!-- Slide number: N --> markers); visual grid: python scripts/thumbnail.py deck.pptx |
Scripts
Paths are relative to this skill's directory. Everything else is plain Python, node, or shell.
| Script | What it does |
|---|
scripts/thumbnail.py deck.pptx [prefix] | Labeled grid of every slide, for picking template layouts. .pptx only. Pass prefix — it defaults to thumbnails, which overwrites the grids of any other deck done in the same directory |
scripts/add_slide.py unpacked/ slide2.xml [--after slideN.xml] | Duplicate a slide (or a slideLayoutN.xml) with all the package bookkeeping. Also takes a .pptx directly with -o out.pptx |
scripts/clean.py unpacked/ | Delete slides, media, and rels no longer referenced. Run after <p:sldIdLst> is final |
scripts/office/validate.py deck.pptx [--original src.pptx] | Schema, relationship, content-type, chart and slide checks; each failure names its fix. Pass --original for any template-derived deck — it baselines the schema checks against the template, so the template's own XSD errors don't read as yours |
scripts/office/soffice.py --headless --convert-to pdf deck.pptx | LibreOffice wrapper — bare soffice hangs in this sandbox |
Creating with pptxgenjs — gotchas
pptxgenjs is preinstalled — do not run npm install first; write the script and require('pptxgenjs') directly. Only if that require fails: npm install pptxgenjs. The model knows the API; these are the footguns:
- Set
pres.layout before adding slides. The default canvas is LAYOUT_16x9 = 10" × 5.625", not 13.3" wide. Coordinates past the edge are written, not clamped — the shape just isn't on the slide. (LAYOUT_WIDE is 13.3" × 7.5".)
- Hex colors: never
#, never 8 digits. color: "FF0000". Both "#FF0000" and alpha baked into the hex ("00000020") corrupt the file. For translucency: transparency: 0-100 on fills and images, opacity: 0.0-1.0 on shadows — each is silently ignored on the other.
- pptxgenjs mutates option objects in place (converts values to EMU on first use). Never share one
shadow/options object across two add* calls — build a fresh object each time.
- Shadow
offset must be ≥ 0 — a negative offset corrupts the file. To cast a shadow upward, use angle: 270 with a positive offset.
letterSpacing is silently ignored — the real option is charSpacing.
- Lists:
bullet: true on each item, never a literal • (renders double bullets). Set breakLine: true on every array item except the last. Space bulleted paragraphs with paraSpaceAfter, not lineSpacing (huge gaps).
- One
new pptxgen() per output file — never reuse an instance.
rectRadius only works on ROUNDED_RECTANGLE, not RECTANGLE.
- Gradient fills aren't supported — use a gradient image as the background instead.
- Text boxes have built-in internal padding — set
margin: 0 whenever text must align with a shape, line, or icon at the same x.
- Speaker notes go in
slide.addNotes("...") (plain text, once per slide), never in a text box on the slide.
- Keep charts native. Use
addChart() for everything PowerPoint can chart (pass an array of {type, data, options} for combos). For PowerPoint-native features the library doesn't expose (trendlines, error bars), compute the extra series yourself or post-process the generated OOXML — do not fall back to a rendered image. Only chart types PowerPoint has no native form for (Sankey, network, chord) go in as images.