Markdown

Editing Presentations

Template-Based Workflow

When using an existing presentation as a template:

  1. **Analyze existing slides**:
   python scripts/thumbnail.py template.pptx
   python -m markitdown template.pptx

Review `thumbnails.jpg` to see layouts, and markitdown output to see placeholder text.

  1. **Plan slide mapping**: For each content section, choose a template slide.

⚠️ **USE VARIED LAYOUTS** — monotonous presentations are a common failure mode. Don't default to basic title + bullet slides. Actively seek out:

  • Multi-column layouts (2-column, 3-column)
  • Image + text combinations
  • Full-bleed images with text overlay
  • Quote or callout slides
  • Section dividers
  • Stat/number callouts
  • Icon grids or icon + text rows

**Avoid:** Repeating the same text-heavy layout for every slide.

Match content type to layout style (e.g., key points → bullet slide, team info → multi-column, testimonials → quote slide).

  1. **Unpack**: `python scripts/office/unpack.py template.pptx unpacked/`
  1. **Build presentation** (do this yourself, not with subagents):
  • Delete unwanted slides (remove from `<p:sldIdLst>`)
  • Duplicate slides you want to reuse (`add_slide.py`)
  • Reorder slides in `<p:sldIdLst>`
  • **Complete all structural changes before step 5**
  1. **Edit content**: Update text in each `slide{N}.xml`.

**Use subagents here if available** — slides are separate XML files, so subagents can edit in parallel.

  1. **Clean**: `python scripts/clean.py unpacked/`
  1. **Pack**: `python scripts/office/pack.py unpacked/ output.pptx --original template.pptx`

---

Scripts

| Script | Purpose | |--------|---------| | `unpack.py` | Extract and pretty-print PPTX | | `add_slide.py` | Duplicate slide or create from layout | | `clean.py` | Remove orphaned files | | `pack.py` | Repack with validation | | `thumbnail.py` | Create visual grid of slides |

unpack.py

python scripts/office/unpack.py input.pptx unpacked/

Extracts PPTX, pretty-prints XML, escapes smart quotes.

add_slide.py

python scripts/add_slide.py unpacked/ slide2.xml      # Duplicate slide
python scripts/add_slide.py unpacked/ slideLayout2.xml # From layout

Prints `<p:sldId>` to add to `<p:sldIdLst>` at desired position.

clean.py

python scripts/clean.py unpacked/

Removes slides not in `<p:sldIdLst>`, unreferenced media, orphaned rels.

pack.py

python scripts/office/pack.py unpacked/ output.pptx --original input.pptx

Validates, repairs, condenses XML, re-encodes smart quotes.

thumbnail.py

python scripts/thumbnail.py input.pptx [output_prefix] [--cols N]

Creates `thumbnails.jpg` with slide filenames as labels. Default 3 columns, max 12 per grid.

**Use for template analysis only** (choosing layouts). For visual QA, use `soffice` + `pdftoppm` to create full-resolution individual slide images—see SKILL.md.

---

Slide Operations

Slide order is in `ppt/presentation.xml` → `<p:sldIdLst>`.

**Reorder**: Rearrange `<p:sldId>` elements.

**Delete**: Remove `<p:sldId>`, then run `clean.py`.

**Add**: Use `add_slide.py`. Never manually copy slide files—the script handles notes references, Content_Types.xml, and relationship IDs that manual copying misses.

---

Editing Content

**Subagents:** If available, use them here (after completing step 4). Each slide is a separate XML file, so subagents can edit in parallel. In your prompt to subagents, include:

  • The slide file path(s) to edit
  • **"Use the Edit tool for all changes"**
  • The formatting rules and common pitfalls below

For each slide:

  1. Read the slide's XML
  2. Identify ALL placeholder content—text, images, charts, icons, captions
  3. Replace each placeholder with final content

**Use the Edit tool, not sed or Python scripts.** The Edit tool forces specificity about what to replace and where, yielding better reliability.

Formatting Rules

  • **Bold all headers, subheadings, and inline labels**: Use `b="1"` on `<a:rPr>`. This includes:
  • Slide titles
  • Section headers within a slide
  • Inline labels like (e.g.: "Status:", "Description:") at the start of a line
  • **Never use unicode bullets (•)**: Use proper list formatting with `<a:buChar>` or `<a:buAutoNum>`
  • **Bullet consistency**: Let bullets inherit from the layout. Only specify `<a:buChar>` or `<a:buNone>`.

---

Common Pitfalls

Template Adaptation

When source content has fewer items than the template:

  • **Remove excess elements entirely** (images, shapes, text boxes), don't just clear text
  • Check for orphaned visuals after clearing text content
  • Run visual QA to catch mismatched counts

When replacing text with different length content:

  • **Shorter replacements**: Usually safe
  • **Longer replacements**: May overflow or wrap unexpectedly
  • Test with visual QA after text changes
  • Consider truncating or splitting content to fit the template's design constraints

**Template slots ≠ Source items**: If template has 4 team members but source has 3 users, delete the 4th member's entire group (image + text boxes), not just the text.

Multi-Item Content

If source has multiple items (numbered lists, multiple sections), create separate `<a:p>` elements for each — **never concatenate into one string**.

**❌ WRONG** — all items in one paragraph:

<a:p>
  <a:r><a:rPr .../><a:t>Step 1: Do the first thing. Step 2: Do the second thing.</a:t></a:r>
</a:p>

**✅ CORRECT** — separate paragraphs with bold headers:

<a:p>
  <a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
  <a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 1</a:t></a:r>
</a:p>
<a:p>
  <a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
  <a:r><a:rPr lang="en-US" sz="2799" .../><a:t>Do the first thing.</a:t></a:r>
</a:p>
<a:p>
  <a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
  <a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 2</a:t></a:r>
</a:p>
<!-- continue pattern -->

Copy `<a:pPr>` from the original paragraph to preserve line spacing. Use `b="1"` on headers.

Smart Quotes

Handled automatically by unpack/pack. But the Edit tool converts smart quotes to ASCII.

**When adding new text with quotes, use XML entities:**

<a:t>the &#x201C;Agreement&#x201D;</a:t>

| Character | Name | Unicode | XML Entity | |-----------|------|---------|------------| | `“` | Left double quote | U+201C | `&#x201C;` | | `”` | Right double quote | U+201D | `&#x201D;` | | `‘` | Left single quote | U+2018 | `&#x2018;` | | `’` | Right single quote | U+2019 | `&#x2019;` |

Other

  • **Whitespace**: Use `xml:space="preserve"` on `<a:t>` with leading/trailing spaces
  • **XML parsing**: Use `defusedxml.minidom`, not `xml.etree.ElementTree` (corrupts namespaces)