| name | pptx-generator |
| description | Generate and edit presentation slides as PPTX files. Also create LinkedIn carousels and manage reusable slide layouts.
TRIGGERS - Use this skill when user says:
- "create slides for [brand]" / "generate presentation for [brand]" / "make slides for [brand]"
- "create a carousel for [brand]" / "linkedin carousel" / "make a carousel about [topic]"
- "edit this pptx" / "update the slides" / "modify this presentation"
- "create a new layout" / "add a layout to the cookbook" / "make a [type] layout template"
- "edit the [name] layout" / "update the cookbook" / "improve the [name] template"
- Any request mentioning slides, presentations, carousels, PPTX, or layouts with a brand name
Creates .pptx files compatible with PowerPoint, Google Slides, and Keynote.
Creates PDF carousels for LinkedIn (square 1:1 format).
|
PPTX Slide Generator
Generate professional, on-brand presentation slides using python-pptx. This skill supports:
- Slide Generation - Create presentations for any brand in
brands/
- Carousel Generation - Create LinkedIn carousels (square format, exports to PDF)
- Slide Editing - Modify existing PPTX files
- Layout Management - Create, edit, update cookbook layouts
IMPORTANT: All skill resources are in .claude/skills/pptx-generator/. Always use Glob patterns starting with .claude/skills/pptx-generator/ to find files.
⚠️ CRITICAL: Batch Generation Rules
NEVER generate more than 5 slides at once.
| Rule | Details |
|---|
| Max slides per batch | 5 (can be 1, 2, 3, 4, or 5) |
| After each batch | STOP and validate output |
| Validation required | Check: no duplicate titles, proper spacing, correct colors |
| Continue when | Validation passes |
This prevents token limit errors and catches quality issues early.
⚠️ PREREQUISITE: Brand Check
Before generating slides, check if any brands exist.
Glob: .claude/skills/pptx-generator/brands/*/brand.json
If NO brands found (only template/ exists):
-
STOP - Do not proceed with slide generation
-
Ask the user:
"No brands are configured yet. Would you like me to help you create a brand first?
I'll need your brand colors, fonts, and style guidelines to set this up."
-
If user wants to create a brand, follow the Creating a New Brand section below.
-
If user declines, explain that slides require a brand configuration and offer to use generic styling as a fallback.
Creating a New Brand
When no brands exist or user requests a new brand:
Step 1: Read the Template
Read: .claude/skills/pptx-generator/brands/template/README.md
Read: .claude/skills/pptx-generator/brands/template/brand.json
Read: .claude/skills/pptx-generator/brands/template/config.json
Step 2: Gather Brand Information
Ask the user for (or extract from provided materials):
| Required | Description |
|---|
| Brand name | Folder name (lowercase, no spaces) |
| Colors | Background, text, accent colors (hex codes) |
| Fonts | Heading font, body font, code font |
| Optional | Description |
|---|
| Output directory | Where to save generated files (default: output/{brand}) |
| Logo | Path to logo file (PNG/SVG) |
| Brand guidelines | Existing style guide or website to reference |
| Tone of voice | Writing style, vocabulary preferences |
Step 3: Create Brand Files
-
Create the brand folder:
mkdir -p .claude/skills/pptx-generator/brands/{brand-name}
-
Create brand.json with the gathered values:
{
"name": "Brand Name",
"description": "One-line description",
"colors": {
"background": "hex-without-hash",
"background_alt": "hex-without-hash",
"text": "hex-without-hash",
"text_secondary": "hex-without-hash",
"accent": "hex-without-hash",
"accent_secondary": "hex-without-hash",
"accent_tertiary": "hex-without-hash",
"code_bg": "hex-without-hash",
"card_bg": "hex-without-hash",
"card_bg_alt"
Step 4: Verify
After creating the brand, verify with:
Glob: .claude/skills/pptx-generator/brands/{brand-name}/*
Then proceed to slide generation.
Skill Modes
This skill operates in three modes:
Mode 1: Generate Presentation Slides
User wants presentation slides (16:9) created using a brand's styling.
→ Follow: Brand Discovery → Layout Selection → Content Adaptation → Execute
→ Layouts in: cookbook/*.py
Mode 2: Generate LinkedIn Carousels
User wants a LinkedIn carousel (square 1:1 format) for social media.
→ Follow: Brand Discovery → Carousel Planning → Generate → Export PDF
→ Layouts in: cookbook/carousels/*.py
Mode 3: Manage Cookbook Layouts
User wants to create, edit, or improve layout templates.
→ Follow: Layout CRUD Operations section
Mode 1: Generate Presentation Slides
Step 1: Brand Discovery
-
List available brands:
Glob: .claude/skills/pptx-generator/brands/*/brand.json
Extract unique brand names from paths (e.g., brands/rasmus/... → "rasmus")
-
Read the brand configuration files:
Read: .claude/skills/pptx-generator/brands/{brand-name}/brand.json
Read: .claude/skills/pptx-generator/brands/{brand-name}/config.json
brand.json - Colors, fonts, assets
config.json - Output directory, generation settings
-
Read supporting markdown files for context:
Glob: .claude/skills/pptx-generator/brands/{brand-name}/*.md
These provide voice, tone, and design philosophy.
-
Extract from brand files:
- From brand.json: Colors (hex without #), fonts, asset paths
- From config.json: Output directory, slides per batch, naming convention
- From markdown: Voice, tone, vocabulary, visual principles
If brand not found, list available brands and ask user to choose.
Step 2: Layout Discovery (READ ALL FRONTMATTERS)
⚠️ MANDATORY: Read ALL layout frontmatters before selecting any layout.
This step is critical for making informed layout decisions. You must understand what ALL layouts offer before choosing.
Step 2a: Discover all layouts:
Glob: .claude/skills/pptx-generator/cookbook/*.py
Step 2b: Read EVERY layout file (not just one or two):
For each .py file found, read the first 40 lines to extract the # /// layout frontmatter block. Build a mental map of:
- What each layout is for (
purpose, best_for)
- What each layout should NOT be used for (
avoid_when)
- Limits and constraints (
max_*, min_*, *_max_chars)
The frontmatter block looks like this:
Key frontmatter fields:
| Field | Description |
|---|
name | Layout identifier |
purpose | What this layout is for |
best_for | Ideal use cases (array) |
avoid_when | When NOT to use this layout (array) |
max_* / min_* | Item limits (cards, bullets, stats) |
instructions | Specific tips for using this layout |
Step 2c: Select layouts (only AFTER reading all frontmatters):
Now that you know all available layouts and their constraints:
- User specifies layout → Use that layout (but verify it fits the content)
- User describes content → Match to best-fitting
best_for criteria
- Check
avoid_when → Don't use a layout in situations it warns against
- Respect limits → If content exceeds
max_*, use a different layout
- Multiple slides needed → Select appropriate layout for each
- No good fit → Create a custom layout (see Mode 2)
Example selection process:
- User wants "5 pillars of AI infrastructure"
- You've read all frontmatters and know:
floating-cards-slide: max_cards = 3 → Won't work
multi-card-slide: max_cards = 5 → Perfect fit
- Select
multi-card-slide
Why read ALL frontmatters?
- Layouts reference each other in
avoid_when (e.g., "use multi-card-slide instead")
- You can't make the right choice without knowing all options
- Prevents backtracking when a layout doesn't fit
Step 3: Slide Planning (ALWAYS DO THIS)
Before generating ANY slides, create a written plan.
This applies to single slides, batches, and full presentations. Planning prevents:
- Duplicate content across slides
- Wrong layout choices
- Missing key information
- Poor flow and structure
Create a slide plan table:
| # | Layout | Title | Key Content | Notes |
|---|--------|-------|-------------|-------|
| 1 | title-slide | [Title] | [Subtitle, author] | Opening slide |
| 2 | content-slide | [Title] | [3-4 bullet points] | Main concepts |
| 3 | stats-slide | [Title] | [2-3 metrics] | Impact data |
| ... | ... | ... | ... | ... |
For each slide, specify:
- Slide number - Position in presentation
- Layout - Which cookbook layout to use
- Title - Exact title text (check for duplicates!)
- Key content - Bullet points, stats, quotes, etc.
- Notes - Any special considerations
Planning checklist:
After planning, briefly present the plan before generating.
Step 4: Content Adaptation
For each slide in your plan:
Presentation Text Formatting Rules
IMPORTANT: Follow these rules for ALL slide text.
| Element | Rule | Example |
|---|
| Titles | No trailing periods or commas | "Why AI Matters" not "Why AI Matters." |
| Subtitles | No trailing punctuation | "The future of coding" not "The future of coding." |
| Bullet points | No trailing periods (unless full sentences) | "Faster development" not "Faster development." |
| Headlines | Minimal punctuation, no ellipsis | "What's Next" not "What's Next..." |
| Stats/Numbers | Clean format, no trailing punctuation | "50%" not "50%." |
| CTAs | No trailing punctuation | "Get Started" not "Get Started." |
| Labels | Short, no punctuation | "Step 1" not "Step 1:" |
Avoid:
- Trailing periods on titles, bullets, labels
- Ellipsis (...) in headlines
- Excessive commas in short phrases
- Colons at end of labels/headers
- Semicolons in bullet points
Exception: Full sentence descriptions or quotes may use appropriate punctuation.
Brand Value Mapping
-
Map brand.json values to layout placeholders:
| Layout Placeholder | brand.json Path |
|---|
BRAND_BG | colors.background |
BRAND_BG_ALT | colors.background_alt |
BRAND_TEXT | colors.text |
BRAND_TEXT_SECONDARY | colors.text_secondary |
BRAND_ACCENT | colors.accent |
BRAND_ACCENT_SECONDARY | colors.accent_secondary |
BRAND_ACCENT_TERTIARY | colors.accent_tertiary |
BRAND_CODE_BG | colors.code_bg |
BRAND_CARD_BG | colors.card_bg |
BRAND_CARD_BG_ALT | colors.card_bg_alt |
BRAND_HEADING_FONT | fonts.heading |
BRAND_BODY_FONT | fonts.body |
BRAND_CODE_FONT | fonts.code |
Note: All color values in brand.json are hex WITHOUT the # prefix.
-
Write content in brand's voice (from tone-of-voice.md)
-
Preserve layout structure (decorative elements, spacing, hierarchy)
Step 5: Batch Generation (CRITICAL)
MAXIMUM 5 SLIDES PER BATCH. This is a hard limit.
When generating multiple slides:
- Generate 1-5 slides in a single PPTX file
- STOP and review the output before generating more
- Only after validation passes, continue with the next batch
- Repeat until all slides are generated
Why batching matters:
- Prevents token limit errors
- Allows quality checks between batches
- Catches issues early before they propagate
Execution (do not save Python script files):
uv run --with python-pptx==1.0.2 python << 'SCRIPT'
SCRIPT
Step 6: Quality Validation (MANDATORY)
After EVERY batch, validate before continuing:
- Open the generated PPTX and visually inspect it
- Check for these common issues:
| Issue | What to Look For | Fix |
|---|
| Duplicate titles | Same title text appearing twice on a slide | Remove duplicate text boxes |
| Spacing problems | Title too close to subtitle/content | Increase Y position of lower elements |
| Text overflow | Content extending beyond slide bounds | Reduce font size or split content |
| Missing elements | Decorative elements not rendering | Check shape positions and colors |
| Wrong colors | Colors not matching brand | Verify hex values (no # prefix in code) |
| Bad punctuation | Trailing periods/commas on titles/bullets | Remove unnecessary punctuation |
-
If issues found:
- Fix the current batch before continuing
- Note the issue to avoid repeating in future batches
-
If validation passes:
- Continue to next batch of slides
Step 7: Output
Use the output settings from config.json:
| Config Setting | Default | Description |
|---|
output.directory | output/{brand} | Where to save files |
output.naming | {name}-{date} | File naming pattern |
output.keep_parts | false | Keep part files after combining |
Resolve placeholders:
{brand} → Brand folder name
{name} → Presentation name from user request
{date} → Current date (YYYY-MM-DD)
mkdir -p {resolved-output-directory}
Batched generation workflow:
- Generate each batch as
{name}-part1.pptx, {name}-part2.pptx, etc.
- Validate each batch before continuing
- After ALL batches complete, combine into final file (if
auto_combine is true)
- Delete part files (if
keep_parts is false)
Step 8: Combine Batches (for multi-batch presentations)
After all batches are validated, combine them into a single PPTX:
uv run --with python-pptx==1.0.2 python << 'SCRIPT'
from pptx import Presentation
from pathlib import Path
import shutil
output_dir = Path("output/{brand-name}")
part_files = sorted(output_dir.glob("{name}-part*.pptx"))
if len(part_files) > 1:
combined = Presentation(part_files[0])
for part_file in part_files[1:]:
part_prs = Presentation(part_file)
for slide in part_prs.slides:
blank_layout = combined.slide_layouts[6]
new_slide = combined.slides.add_slide(blank_layout)
for shape in slide.shapes:
el = shape.element
new_slide.shapes._spTree.insert_element_before(
el, 'p:extLst'
)
combined.save(output_dir / "{name}-final.pptx")
print(f"Combined {len(part_files)} parts into {name}-final.pptx")
else:
shutil.move(part_files[0], output_dir / "{name}-final.pptx")
SCRIPT
Final output: output/{brand-name}/{name}-final.pptx
Mode 2: Generate LinkedIn Carousels
LinkedIn carousels are multi-page PDFs in square (1:1) format. Each page is a swipeable slide.
Carousel vs Presentation
| Aspect | Presentation | Carousel |
|---|
| Dimensions | 16:9 (13.333" × 7.5") | 1:1 (7.5" × 7.5") |
| Layouts | cookbook/*.py | cookbook/carousels/*.py |
| Output | PPTX | PDF (via PPTX conversion) |
| Slides | 10-50+ typical | 5-10 optimal |
| Text size | Standard | Larger (mobile readable) |
| Content | Detailed | One idea per slide |
Step 1: Brand Discovery
Same as Mode 1 - read brand.json, config.json, and tone-of-voice.md.
Step 2: Carousel Layout Discovery
Discover carousel-specific layouts:
Glob: .claude/skills/pptx-generator/cookbook/carousels/*.py
Available carousel layouts:
| Layout | Purpose | Best For |
|---|
hook-slide | Opening attention-grabber | First slide only |
single-point-slide | One key point with explanation | Body content |
numbered-point-slide | Numbered list item with big number | Listicles, steps |
quote-slide | Quote with attribution | Social proof, insights |
cta-slide | Call to action | Last slide only |
Read frontmatters to understand limits and constraints for each.
Step 3: Carousel Planning
Typical carousel structure (5-10 slides):
| # | Layout | Content |
|---|--------|---------|
| 1 | hook-slide | Attention-grabbing hook |
| 2-8 | single-point or numbered-point | Body content |
| 9/10 | cta-slide | Call to action |
Carousel content rules:
- One idea per slide - Don't cram multiple points
- Large text - Must be readable on mobile
- Short copy - Max 50 chars for headlines, 150 for body
- Clear flow - Each slide should make sense if viewed alone
- Strong hook - First slide stops the scroll
- Clear CTA - Last slide tells them what to do
Step 4: Generate Carousel
Carousel dimensions (square 1:1):
prs.slide_width = Inches(7.5)
prs.slide_height = Inches(7.5)
Generate all slides as a single PPTX file (carousels are typically 5-10 slides, so batching rarely needed).
Execution:
uv run --with python-pptx==1.0.2 python << 'SCRIPT'
SCRIPT
Step 5: Export to PDF
LinkedIn requires PDF for carousel posts. Convert the PPTX to PDF:
Option A: Using LibreOffice (recommended)
libreoffice --headless --convert-to pdf --outdir output/rasmus output/rasmus/carousel.pptx
Option B: Using soffice
soffice --headless --convert-to pdf output/rasmus/carousel.pptx
Note: LibreOffice must be installed. On macOS: brew install --cask libreoffice
Step 6: Output
Save both files:
output/{brand}/{name}-carousel.pptx - Editable source
output/{brand}/{name}-carousel.pdf - LinkedIn-ready
Carousel Checklist
Mode 3: Layout CRUD Operations
Creating New Layouts
When user requests a new layout type:
-
Study existing layouts for patterns:
Glob: .claude/skills/pptx-generator/cookbook/*.py
Read 2-3 layouts to understand:
- Code structure and imports
- How brand variables are used
- Decorative element patterns
- Positioning conventions
-
Design with these quality standards:
MUST be production-ready:
- Professional, polished appearance
- Visually engaging (not plain or generic)
- Distinctive decorative elements
- Strong visual hierarchy
- Proper use of whitespace
Use appropriate elements:
- Charts - Pie, doughnut, bar, column for data visualization
- Images - Placeholder shapes for screenshots, photos
- Shapes - Circles, rectangles, parallelograms for visual interest
- Cards - Floating cards with shadows for depth
- Geometric patterns - Bold shapes anchored to corners/edges
Avoid:
- Plain text-only layouts
- Generic bullet points without styling
- Tiny decorative elements that don't make impact
- Centered-everything boring compositions
-
Write the layout file with detailed frontmatter:
⚠️ CRITICAL: The frontmatter is documentation for future AI agents.
Every layout MUST include comprehensive frontmatter that teaches future AI agents:
- WHEN to use this layout (and when NOT to)
- HOW to use it correctly
- WHAT limits and constraints exist
- WHY certain choices matter
Editing Existing Layouts
-
Find the layout:
Glob: .claude/skills/pptx-generator/cookbook/*{name}*.py
-
Read and understand current structure including the frontmatter
-
Make modifications while preserving:
- The script header format
- Brand variable naming conventions
- Docstring format (LAYOUT, PURPOSE, CUSTOMIZE)
-
Update the frontmatter if your changes affect:
- What the layout is best for (
best_for)
- When to avoid it (
avoid_when)
- Item limits (
max_*, min_*)
- Usage instructions (
instructions)
-
Save back to the same file
-
Test the modified layout
Updating/Improving Layouts
When asked to improve layout quality:
-
Analyze current weaknesses:
- Is it visually engaging?
- Does it have enough decorative elements?
- Is there good visual hierarchy?
- Does it use space well?
-
Apply improvements:
- Add bold geometric shapes
- Improve color usage
- Add depth (shadows, overlapping)
- Better typography sizing
- More distinctive decorative elements
-
Preserve functionality - Don't break what works
-
Review and enhance frontmatter:
- Are
best_for and avoid_when still accurate?
- Do
instructions reflect any new constraints?
- Add any lessons learned from the improvements
- Update limits if element sizes/counts changed
Deleting Layouts
Simply remove the file:
rm .claude/skills/pptx-generator/cookbook/{layout-name}.py
Editing Existing PPTX Files
When user provides an existing PPTX:
-
Read the file:
from pptx import Presentation
prs = Presentation("path/to/existing.pptx")
-
Analyze: Number of slides, styling, content structure
-
Apply changes: Add/remove slides, update content, modify styling
-
Save to output directory (don't overwrite original unless requested)
Technical Reference
Slide dimensions (16:9):
- Width: 13.333 inches
- Height: 7.5 inches
- Safe margins: 0.5 inches
Always use:
- Blank layout:
prs.slide_layouts[6]
- python-pptx version: 1.0.2
Common imports:
from pptx import Presentation
from pptx.chart.data import CategoryChartData
from pptx.dml.color import RGBColor
from pptx.enum.chart import XL_CHART_TYPE, XL_LEGEND_POSITION
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.util import Inches, Pt
Chart types available:
XL_CHART_TYPE.PIE - Pie chart
XL_CHART_TYPE.DOUGHNUT - Doughnut chart
XL_CHART_TYPE.BAR_CLUSTERED - Horizontal bars
XL_CHART_TYPE.COLUMN_CLUSTERED - Vertical columns
XL_CHART_TYPE.LINE - Line chart
Adding charts:
chart_data = CategoryChartData()
chart_data.categories = ["A", "B", "C"]
chart_data.add_series("Values", [10, 20, 30])
slide.shapes.add_chart(
XL_CHART_TYPE.DOUGHNUT,
Inches(x), Inches(y),
Inches(width), Inches(height),
chart_data
)
Adding images:
slide.shapes.add_picture(
"path/to/image.png",
Inches(x), Inches(y),
width=Inches(w)
)
Preview All Layouts
To see all available layouts:
uv run .claude/skills/pptx-generator/generate-cookbook-preview.py
This generates cookbook-preview.pptx with every layout.
Checklist
For Slide Generation:
For Creating Layouts: