---
name: code-saurabh/pptx
source: https://app.decimal.ai/s/code-saurabh-pptx@1/SKILL.md
source_sha256: 526e2fd8e4f5
---

# PowerPoint Presentation (.pptx)

A `.pptx` file is a ZIP archive of XML files. You can create, edit, and read them programmatically. Choose the right approach for the task:

| Task | Approach |
|---|---|
| **Create** a new deck | `pptxgenjs` (Node) or `python-pptx` (Python) |
| **Edit** an existing deck | Unzip → edit slide XML → rezip |
| **Read** content from a deck | `markitdown deck.pptx` or unzip and parse XML |
| **Convert** to PDF | LibreOffice headless |

---

## Presentation Principles

- **Every slide has one job.** A slide that makes three points makes zero. Split ruthlessly.
- **Text-only slides are forgettable.** Every slide needs at least one visual element — chart, image, icon, data callout, or diagram.
- **The deck must work without the speaker.** Async decks (sent via email, read without a presenter) need more text and context than live-presentation decks.
- **Visual hierarchy over bullet points.** A large number + small label communicates faster than a sentence. A 2x2 grid communicates relationships better than a list.
- **Commit to a visual direction and hold it.** One font pair. One color palette. One layout style. Inconsistency signals lack of polish.
- **AI slop is obvious.** Cream backgrounds, accent stripes along card edges, Inter/Roboto with no rationale, blue CTA buttons, centered body text — these are trust killers. Avoid all of them.

---

## Step 0: Before Creating

Ask the user:

1. **What is the deck for?** (investor pitch, all-hands, client presentation, technical review, sales demo)
2. **Who is the audience?** (technical, executive, external client, general team)
3. **How many slides?** Or: what content needs to be covered?
4. **Brand constraints?** (specific colors, fonts, logo to include)
5. **Output format?** (.pptx to edit further, or PDF to send)
6. **Presenting live or sending async?** (changes text density and speaker notes needs)

---

## Creating with pptxgenjs (Node/TypeScript)

### Setup
```bash
# pptxgenjs is often pre-installed — try require first
node -e "require('pptxgenjs')" 2>/dev/null && echo "installed" || npm install pptxgenjs
```

### Basic Structure
```javascript
const pptx = require("pptxgenjs");
const pres = new pptx();

// ALWAYS set layout before adding slides
pres.layout = "LAYOUT_16x9"; // 10" × 5.625" — standard widescreen

// Define theme colors (never use # prefix, never 8-digit hex)
const COLORS = {
  primary:    "1E3A5F",  // Deep navy
  accent:     "2E86AB",  // Electric blue
  light:      "F8F9FA",  // Near white
  dark:       "212529",  // Near black
  muted:      "6C757D",  // Gray
};

// Title slide
const titleSlide = pres.addSlide();
titleSlide.background = { color: COLORS.primary };
titleSlide.addText("Your Presentation Title", {
  x: 0.5, y: 1.8, w: 9, h: 1.2,
  fontSize: 40, bold: true, color: "FFFFFF",
  align: "left",
});
titleSlide.addText("Subtitle or date", {
  x: 0.5, y: 3.0, w: 9, h: 0.5,
  fontSize: 18, color: "A8C6E8",
  align: "left",
});

await pres.writeFile({ fileName: "presentation.pptx" });
```

### Common Layout Patterns

#### Data callout slide (big numbers)
```javascript
const slide = pres.addSlide();
slide.addText("Key Metrics", {
  x: 0.5, y: 0.3, w: 9, h: 0.6,
  fontSize: 28, bold: true, color: COLORS.dark
});

// Three metric blocks
const metrics = [
  { value: "810×", label: "Productivity increase" },
  { value: "40+",  label: "Features shipped" },
  { value: "3",    label: "Products launched" },
];

metrics.forEach((m, i) => {
  const x = 0.5 + i * 3.2;
  // Big number
  slide.addText(m.value, {
    x, y: 1.2, w: 2.8, h: 1.4,
    fontSize: 60, bold: true, color: COLORS.primary, align: "center"
  });
  // Label
  slide.addText(m.label, {
    x, y: 2.7, w: 2.8, h: 0.5,
    fontSize: 14, color: COLORS.muted, align: "center"
  });
});
```

#### Two-column slide
```javascript
const slide = pres.addSlide();
// Left column — text
slide.addText("Problem", {
  x: 0.5, y: 0.3, w: 4.2, h: 0.5,
  fontSize: 24, bold: true, color: COLORS.dark
});
slide.addText("The current checkout flow has a 23% drop-off rate on mobile...", {
  x: 0.5, y: 1.0, w: 4.2, h: 3.5,
  fontSize: 14, color: COLORS.dark, valign: "top"
});
// Right column — image or chart
slide.addImage({ path: "chart.png", x: 5.2, y: 0.5, w: 4.3, h: 4.5 });
```

#### Critical gotchas
```javascript
// ❌ WRONG — # prefix corrupts the file
color: "#FF0000"

// ✅ CORRECT — 6 hex chars, no #
color: "FF0000"

// ❌ WRONG — sharing option objects causes corruption
const shadow = { type: "outer", blur: 3, offset: 2, color: "000000" };
slide1.addShape(pptx.ShapeType.rect, { shadow }); // mutates shadow object
slide2.addShape(pptx.ShapeType.rect, { shadow }); // now uses corrupted values

// ✅ CORRECT — fresh object per call
const makeShadow = () => ({ type: "outer", blur: 3, offset: 2, color: "000000" });
slide1.addShape(pptx.ShapeType.rect, { shadow: makeShadow() });
slide2.addShape(pptx.ShapeType.rect, { shadow: makeShadow() });

// ❌ WRONG — shadow offset must be >= 0
shadow: { offset: -2 }  // corrupts file

// ✅ CORRECT
shadow: { offset: 2 }
```

---

## Creating with python-pptx

```python
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN

prs = Presentation()
prs.slide_width  = Inches(13.33)
prs.slide_height = Inches(7.5)

# Add a slide using blank layout
blank_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(blank_layout)

# Add title text box
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.3), Inches(12), Inches(1))
tf = txBox.text_frame
tf.word_wrap = True
p = tf.add_paragraph()
p.text = "Slide Title"
p.font.bold = True
p.font.size = Pt(36)
p.font.color.rgb = RGBColor(0x1E, 0x3A, 0x5F)
p.alignment = PP_ALIGN.LEFT

prs.save("presentation.pptx")
```

---

## Editing an Existing Deck

```bash
# Unzip to inspect/edit
mkdir deck_unpacked && cp deck.pptx deck.zip
unzip deck.zip -d deck_unpacked/

# Slides are at: deck_unpacked/ppt/slides/slide1.xml, slide2.xml, etc.
# Edit XML directly for text replacement, color changes, etc.

# Repack
cd deck_unpacked && zip -r ../deck_edited.pptx . && cd ..
```

For simple text replacement across all slides:
```python
from pptx import Presentation

prs = Presentation("template.pptx")
for slide in prs.slides:
    for shape in slide.shapes:
        if shape.has_text_frame:
            for para in shape.text_frame.paragraphs:
                for run in para.runs:
                    run.text = run.text.replace("{{COMPANY}}", "Acme Corp")
prs.save("output.pptx")
```

---

## Reading / Extracting Content

```bash
# Extract all text, slide by slide
markitdown deck.pptx

# Check for placeholder text (leftover template text)
markitdown deck.pptx | grep -iE "\bx{3,}\b|lorem|ipsum|\bTODO|\[insert"
```

```python
from pptx import Presentation

prs = Presentation("deck.pptx")
for i, slide in enumerate(prs.slides, 1):
    print(f"\n--- Slide {i} ---")
    for shape in slide.shapes:
        if shape.has_text_frame:
            print(shape.text_frame.text)
```

---

## Design Standards

### Color palettes (use one, stay consistent)

| Palette | Primary | Accent | Background |
|---|---|---|---|
| Midnight Executive | `1E2761` | `CADCFC` | `FFFFFF` |
| Forest & Moss | `2C5F2D` | `97BC62` | `F5F5F5` |
| Coral Energy | `F96167` | `F9E795` | `2F3C7E` |
| Charcoal Minimal | `36454F` | `F2F2F2` | `212121` |
| Teal Trust | `028090` | `00A896` | `FFFFFF` |

### Typography
| Element | Size | Weight |
|---|---|---|
| Slide title | 36–44pt | Bold |
| Section header | 20–24pt | Bold |
| Body text | 14–16pt | Regular |
| Captions / labels | 10–12pt | Regular |

**Safe fonts** (render correctly in both PowerPoint and LibreOffice):
Arial, Calibri, Cambria, Times New Roman, Courier New

### What to never do
- ❌ Accent lines or stripes under titles (AI slop signature)
- ❌ Decorative color bars spanning slide width
- ❌ Centered body text (left-align everything except titles)
- ❌ Cream/beige background when not specified — use white
- ❌ Text-only slides — always add a visual element
- ❌ Same layout repeated on every slide
- ❌ `#` prefix in color values (pptxgenjs)
- ❌ Shared option objects across add calls (pptxgenjs)

---

## QA Before Delivering

```bash
# 1. Content check — read all text
markitdown output.pptx

# 2. Check for leftover placeholder text
markitdown output.pptx | grep -iE "\bx{3,}\b|lorem|ipsum|TODO|\[insert"

# 3. Convert to PDF for visual check
libreoffice --headless --convert-to pdf output.pptx

# 4. Visual inspection checklist:
```

Visual QA checklist (check every slide):
- [ ] No text overflowing its box or the slide edge
- [ ] No overlapping elements
- [ ] Minimum 0.5" margin from all slide edges
- [ ] Consistent gaps between content blocks (0.3" or 0.5" — pick one)
- [ ] No low-contrast text (light on light, dark on dark)
- [ ] No leftover template placeholder text
- [ ] Speaker notes added for any slide that needs explanation

---

## Definition of Done — PPTX

- [ ] Deck purpose, audience, and slide count confirmed before starting
- [ ] Layout set before first slide added (`pres.layout = "LAYOUT_16x9"`)
- [ ] Color palette defined — no `#` prefix, no 8-digit hex
- [ ] One font pair used consistently throughout
- [ ] Every slide has at least one visual element (no text-only slides)
- [ ] No accent stripes, decorative bars, or cream backgrounds
- [ ] No AI slop patterns (see list above)
- [ ] Content QA run: `markitdown output.pptx`
- [ ] Placeholder text check: no leftover `lorem`, `TODO`, `[insert]`
- [ ] Visual QA: every slide inspected for overflow, overlap, contrast
- [ ] Speaker notes added where needed
- [ ] File opens without errors in PowerPoint / LibreOffice