Agent Skills: PowerPoint Generation (pptx)

PowerPoint presentation generation using python-pptx. Create slides from Claude output, data analysis, or structured content. Covers slide templates, shapes, charts, tables, and themed presentations. Use for generating .pptx files programmatically.

UncategorizedID: oimiragieo/agent-studio/pptx

Install this agent skill to your local

pnpm dlx add-skill https://github.com/oimiragieo/agent-studio/tree/HEAD/.claude/skills/pptx

Skill Files

Browse the full folder contents for pptx.

Download Skill

Loading file tree…

.claude/skills/pptx/SKILL.md

Skill Metadata

Name
pptx
Description
PowerPoint presentation generation using python-pptx. Create slides from Claude output, data analysis, or structured content. Covers slide templates, shapes, charts, tables, and themed presentations. Use for generating .pptx files programmatically.

PowerPoint Generation (pptx)

Overview

Generate .pptx files programmatically using python-pptx. Convert Claude output, data analysis results, research reports, and structured data into polished PowerPoint presentations.

When to Invoke

Skill({ skill: 'pptx' }) when:

  • User asks to "create a presentation", "generate slides", or "make a PowerPoint"
  • Converting a report, analysis, or structured document into slide format
  • Generating recurring report slides from data
  • Creating template-based presentations programmatically

Installation

pip install python-pptx
# or
uv add python-pptx

Quick Start

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

# Create presentation
prs = Presentation()

# Set slide dimensions (widescreen 16:9)
prs.slide_width = Inches(13.33)
prs.slide_height = Inches(7.5)

# Add title slide using layout 0
title_layout = prs.slide_layouts[0]
slide = prs.slides.add_slide(title_layout)
title = slide.shapes.title
subtitle = slide.placeholders[1]

title.text = "Q1 2026 Business Review"
subtitle.text = "Prepared by Claude Agent"

# Add content slide using layout 1 (title + content)
content_layout = prs.slide_layouts[1]
slide = prs.slides.add_slide(content_layout)
slide.shapes.title.text = "Key Findings"

tf = slide.placeholders[1].text_frame
tf.text = "Revenue grew 23% YoY"
p = tf.add_paragraph()
p.text = "Customer retention at 94%"
p.level = 1  # Indent level

prs.save("presentation.pptx")

Slide Layouts Reference

Standard layouts available in default template:

| Index | Name | Use For | | ----- | --------------------- | --------------------------- | | 0 | Title Slide | Opening slide | | 1 | Title and Content | Main content slides | | 2 | Title and Two Content | Side-by-side comparison | | 5 | Title Only | Charts or images with title | | 6 | Blank | Custom layouts |

# List all layouts in a template
for i, layout in enumerate(prs.slide_layouts):
    print(f"{i}: {layout.name}")

Text Formatting

from pptx.util import Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN

def format_paragraph(paragraph, text, size=18, bold=False, color=None, align=PP_ALIGN.LEFT):
    run = paragraph.add_run()
    run.text = text
    font = run.font
    font.size = Pt(size)
    font.bold = bold
    if color:
        font.color.rgb = RGBColor(*color)  # e.g., (0x1F, 0x49, 0x7D) for dark blue
    paragraph.alignment = align
    return run

# Usage
tf = slide.placeholders[1].text_frame
tf.clear()  # Clear existing content
p = tf.paragraphs[0]
format_paragraph(p, "Important Metric: 94%", size=24, bold=True, color=(0x1F, 0x49, 0x7D))

Tables

from pptx.util import Inches

def add_table_slide(prs, title, headers, rows):
    """Add a slide with a formatted table."""
    slide = prs.slides.add_slide(prs.slide_layouts[5])  # Title Only
    slide.shapes.title.text = title

    # Position: left, top, width, height
    left = Inches(0.5)
    top = Inches(1.5)
    width = Inches(12.3)
    height = Inches(0.8 * (len(rows) + 1))

    table = slide.shapes.add_table(
        len(rows) + 1, len(headers), left, top, width, height
    ).table

    # Header row
    for col_idx, header in enumerate(headers):
        cell = table.cell(0, col_idx)
        cell.text = header
        cell.text_frame.paragraphs[0].runs[0].font.bold = True

    # Data rows
    for row_idx, row in enumerate(rows):
        for col_idx, value in enumerate(row):
            table.cell(row_idx + 1, col_idx).text = str(value)

    return slide

# Usage
headers = ["Product", "Revenue", "Growth"]
rows = [
    ("Widget A", "$1.2M", "+23%"),
    ("Widget B", "$890K", "+15%"),
    ("Widget C", "$450K", "-5%"),
]
add_table_slide(prs, "Revenue by Product", headers, rows)

Charts

from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches

def add_bar_chart(slide, title, categories, series_name, values):
    """Add a bar chart to a slide."""
    chart_data = ChartData()
    chart_data.categories = categories
    chart_data.add_series(series_name, values)

    chart = slide.shapes.add_chart(
        XL_CHART_TYPE.COLUMN_CLUSTERED,
        Inches(1), Inches(1.5),   # left, top
        Inches(11), Inches(5.5),  # width, height
        chart_data
    ).chart

    chart.has_title = True
    chart.chart_title.text_frame.text = title
    chart.has_legend = False

    return chart

# Usage
slide = prs.slides.add_slide(prs.slide_layouts[5])
slide.shapes.title.text = "Monthly Revenue"
add_bar_chart(
    slide,
    "Revenue by Month (2026)",
    ["Jan", "Feb", "Mar"],
    "Revenue ($K)",
    (450, 520, 610)
)

Images

from pptx.util import Inches

def add_image_slide(prs, title, image_path, caption=None):
    slide = prs.slides.add_slide(prs.slide_layouts[5])
    slide.shapes.title.text = title

    # Center image on slide
    pic = slide.shapes.add_picture(
        image_path,
        left=Inches(1.5),
        top=Inches(1.5),
        width=Inches(10),
    )

    if caption:
        txBox = slide.shapes.add_textbox(
            Inches(1.5), Inches(6.8), Inches(10), Inches(0.5)
        )
        tf = txBox.text_frame
        tf.text = caption
        tf.paragraphs[0].alignment = PP_ALIGN.CENTER

    return slide

Agent Workflow: Claude Output → Slides

import json
from pptx import Presentation
from pptx.util import Inches, Pt

def claude_output_to_slides(slide_data: list[dict], output_path: str):
    """
    Convert Claude structured output to a PowerPoint file.

    Expected slide_data format:
    [
      {"type": "title", "title": "...", "subtitle": "..."},
      {"type": "content", "title": "...", "bullets": ["...", "..."]},
      {"type": "table", "title": "...", "headers": [...], "rows": [[...], ...]},
    ]
    """
    prs = Presentation()
    prs.slide_width = Inches(13.33)
    prs.slide_height = Inches(7.5)

    for slide_spec in slide_data:
        if slide_spec["type"] == "title":
            slide = prs.slides.add_slide(prs.slide_layouts[0])
            slide.shapes.title.text = slide_spec["title"]
            if "subtitle" in slide_spec:
                slide.placeholders[1].text = slide_spec["subtitle"]

        elif slide_spec["type"] == "content":
            slide = prs.slides.add_slide(prs.slide_layouts[1])
            slide.shapes.title.text = slide_spec["title"]
            tf = slide.placeholders[1].text_frame
            tf.text = slide_spec["bullets"][0]
            for bullet in slide_spec["bullets"][1:]:
                p = tf.add_paragraph()
                p.text = bullet
                p.level = 1

        elif slide_spec["type"] == "table":
            add_table_slide(
                prs,
                slide_spec["title"],
                slide_spec["headers"],
                slide_spec["rows"]
            )

    prs.save(output_path)
    return output_path

# Example: Generate from Claude JSON output
slide_data = [
    {"type": "title", "title": "Q1 2026 Report", "subtitle": "Generated by Claude"},
    {"type": "content", "title": "Key Highlights", "bullets": [
        "Revenue up 23% YoY",
        "New customer acquisition: +450",
        "NPS score improved to 72",
    ]},
    {"type": "table", "title": "Regional Performance",
     "headers": ["Region", "Revenue", "Target", "Variance"],
     "rows": [["North", "$2.1M", "$2.0M", "+5%"], ["South", "$1.8M", "$2.0M", "-10%"]]},
]
claude_output_to_slides(slide_data, "q1-report.pptx")

Using Existing Templates

# Load existing branded template
prs = Presentation("company-template.pptx")

# Add slide using template's layouts
# Template layouts preserve branding (fonts, colors, logos)
slide = prs.slides.add_slide(prs.slide_layouts[1])
slide.shapes.title.text = "New Content Slide"

Output Location

Save generated .pptx files to:

  • User-specified path, or
  • .claude/context/artifacts/ for agent-generated presentations

Anti-Patterns

  • Never use raw integer values for sizes — always Pt(), Inches(), or Emu()
  • Never add text directly to slide (use placeholder shapes for layout consistency)
  • Never hardcode colors without using RGBColor — inconsistent on dark/light themes
  • Never forget tf.clear() before setting text on a reused placeholder
  • Never use slide_layouts[6] (blank) for content — placeholder positions will be missing

Related Skills

  • xlsx — Excel spreadsheet generation (tabular data export)
  • diagram-generator — Mermaid diagrams (for embedding architecture diagrams)
  • markitdown-converter — Convert existing files to Markdown for Claude processing

Memory Protocol (MANDATORY)

Before starting: Read .claude/context/memory/learnings.md

After completing: Record any python-pptx version compatibility issues or slide layout gotchas.

ASSUME INTERRUPTION: Your context may reset. If it's not in memory, it didn't happen.