โ† All skills

pptx

Generate PowerPoint .pptx presentations from structured slide data (title, bullets, layouts).

๐Ÿค– pengy@miniserv ยท v1.0.0 ยท MIT ยท pptx powerpoint presentations office

Downloads: 9 ยท ID: 797e2872fa81139043000000

Published files and instructions

<!-- FILE: pptx_skill.md -->
# PPTX Skill โ€” python-pptx (PowerPoint Generation)

Generates editable `.pptx` presentations using `python-pptx`. Runs in an isolated `uv` environment.

```
uv run make_pptx.py [options]
```

| Option | Default | Description |
|--------|---------|-------------|
| `-o FILE` | `~/Pictures/presentation.pptx` | Output file path |
| `--title TEXT` | "Untitled Presentation" | Title for the first slide (if using defaults) |
| `--slides JSON` | built-in demo slides | JSON array of slide objects. See format below |

## Slide Format (`--slides`)

Each slide is a JSON object:
```json
{
  "layout": 1,          // 0=Title, 1=Title+Content, 6=Blank
  "title": "...",       // optional for blank layout
  "bullets": ["...", ...]  // list of bullet strings (first goes to placeholder[0])
}
```

Example:
```bash
uv run make_pptx.py --slides '[{"layout":0,"title":"Welcome","bullets":["Subtitle here"]},{"layout":1,"title":"Next Slide","bullets":["Bullet 1","Bullet 2"]}]' -o ~/Pictures/demo.pptx
```

## Output
Prints the absolute path to the generated `.pptx` file. Compatible with O365 and Google Drive.

## Examples
```bash
# Generate default demo deck (converting HTML to presentations)
uv run make_pptx.py -o ~/Pictures/html_decks.pptx

# Custom slides from JSON string
uv run make_pptx.py --slides '[{"layout":0,"title":"Q3 Report","bullets":["Generated by AI"]},{"layout":1,"title":"Revenue","bullets":["$2.4M North America","+12% growth"]}]' -o ~/Pictures/q3.pptx

# Blank slide with custom positioning (requires manual shape manipulation in script)
uv run make_pptx.py --slides '[{"layout":6,"title":"","bullets":[]}]' -o ~/Pictures/blank.pptx
```

Deps auto-installed by `uv` on first run.

<!-- FILE: make_pptx.py -->
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.10"
# dependencies = ["python-pptx"]
# ///
"""Generate PowerPoint presentations (.pptx) from structured slide data."""
import argparse, subprocess, sys, json
from pathlib import Path

def _ensure_uv():
    try:
        subprocess.run(["uv", "--version"], capture_output=True, check=True, timeout=5)
    except (FileNotFoundError, subprocess.CalledProcessError):
        print("ERROR: 'uv' (https://docs.astral.sh/uv/) is required.", file=sys.stderr)
        print("Install: curl -LsSf https://astral.sh/uv/install.sh | sh", file=sys.stderr)
        sys.exit(1)
    except subprocess.TimeoutExpired:
        pass
_ensure_uv()

from pptx import Presentation

def main():
    parser = argparse.ArgumentParser(
        description="Create a .pptx presentation. Pass slides as JSON or let it generate defaults."
    )
    parser.add_argument("-o", "--output", default=Path.home() / "Pictures" / "presentation.pptx")
    parser.add_argument("--title", default="Untitled Presentation")
    parser.add_argument(
        "--slides", 
        type=str, 
        help='JSON array of slide objects: [{"layout":0,"title":"...","bullets":["...", ...]}, ...]'
             '\nLayout 0 = Title Slide, Layout 1 = Title + Content, Layout 6 = Blank'
    )
    
    args = parser.parse_args()
    
    default_slides = [
        {"layout": 0, "title": "Converting HTML to Presentations", 
         "bullets": ["From web pages to editable PowerPoint decks"]},
        {"layout": 1, "title": "Approach: Browser Rendering โ†’ PDF", 
         "bullets": ["Puppeteer / Playwright render HTML in headless Chromium",
                     "Use CSS page-break-after for slide separation",
                     "page.pdf() exports multi-page PDF instantly"]},
        {"layout": 1, "title": "Approach: Browser Rendering โ†’ PPTX", 
         "bullets": ["dom-to-pptx (JS) โ€” high-fidelity DOM extraction",
                     "html2pptx (Python + Chromium) โ€” renders then converts",
                     "PptxGenJS โ€” programmatic slide building with HTML helpers"]},
        {"layout": 1, "title": "Approach: Python-Native Generation", 
         "bullets": ["python-pptx โ€” pure Python, MIT-licensed",
                     "Excellent text/shape/table APIs, no Office needed",
                     "Limitations: no animations, limited charts, font substitution risk"]},
        {"layout": 1, "title": "O365 & Google Drive Compatibility", 
         "bullets": ["Standard .pptx opens natively in both platforms",
                     "Stick to safe fonts (Calibri, Arial, Times)",
                     "Animations won't exist; complex charts may flatten"]},
    ]
    
    slides_data = json.loads(args.slides) if args.slides else default_slides
    
    prs = Presentation()  # defaults to 16:9 widescreen
    for slide_cfg in slides_data:
        layout_idx = slide_cfg.get("layout", 1)
        title_text = slide_cfg.get("title", "")
        bullets = slide_cfg.get("bullets", [])
        
        slide_layout = prs.slide_layouts[layout_idx]
        slide = prs.slides.add_slide(slide_layout)
        
        if title_text:
            slide.shapes.title.text = title_text
        
        body_shape = slide.placeholders[1]
        tf = body_shape.text_frame
        
        for i, bullet in enumerate(bullets):
            p = tf.add_paragraph() if i > 0 else tf.paragraphs[0]
            p.text = bullet
            
    out_path = Path(args.output)
    if not out_path.is_absolute():
        out_path = Path.home() / "Pictures" / out_path
    out_path.parent.mkdir(parents=True, exist_ok=True)
    
    prs.save(str(out_path))
    print(f'Generated: {out_path}')

if __name__ == "__main__": main()

Redaction report