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" - "use the [workflow] workflow" / "qa-report workflow" / "rca-report workflow" - 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).
From presentationsnpx claudepluginhub danielscholl/claude-sdlc --plugin presentationsThis skill uses the workspace's default tool permissions.
brands/template/README.mdbrands/template/brand-system.mdbrands/template/brand.jsonbrands/template/config.jsonbrands/template/tone-of-voice.mdcookbook/agenda-slide.pycookbook/bold-diagonal-slide.pycookbook/carousels/cta-slide.pycookbook/carousels/hook-slide.pycookbook/carousels/numbered-point-slide.pycookbook/carousels/quote-slide.pycookbook/carousels/single-point-slide.pycookbook/chart-slide.pycookbook/circular-hero-slide.pycookbook/closing-slide.pycookbook/code-slide.pycookbook/comparison-matrix-slide.pycookbook/content-slide.pycookbook/corner-anchor-slide.pycookbook/environment-status-slide.pyGuides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Details PluginEval's skill quality evaluation: 3 layers (static, LLM judge), 10 dimensions, rubrics, formulas, anti-patterns, badges. Use to interpret scores, improve triggering, calibrate thresholds.
Generate professional, on-brand presentation slides using python-pptx. This skill supports:
brands/IMPORTANT: Plugin resources (cookbook, workflows, template brand) are at ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/. User brands are at .claude/brands/. Always use the correct base path.
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 |
| After ALL batches | COMBINE into single file and DELETE part files |
This prevents token limit errors and catches quality issues early.
CRITICAL: Always clean up part files after combining. The user should only see ONE final PPTX file, not multiple part files.
Before generating slides, check if any brands exist.
Glob: .claude/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.
When no brands exist or user requests a new brand:
Read: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/brands/template/README.md
Read: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/brands/template/brand.json
Read: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/brands/template/config.json
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 |
Create the brand folder:
mkdir -p .claude/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": "hex-without-hash"
},
"fonts": {
"heading": "Font Name",
"body": "Font Name",
"code": "Monospace Font"
},
"assets": {
"logo": "assets/logo.png",
"logo_dark": null,
"icon": null
}
}
Create config.json with output settings:
{
"output": {
"directory": "output/{brand}",
"naming": "{name}-{date}",
"keep_parts": false
},
"generation": {
"slides_per_batch": 5,
"auto_combine": true,
"open_after_generate": false
},
"defaults": {
"slide_width_inches": 13.333,
"slide_height_inches": 7.5
}
}
Create brand-system.md - Copy from template and fill in brand guidelines
Create tone-of-voice.md - Copy from template and fill in voice guidelines
Add assets - Copy logo/images to .claude/brands/{brand-name}/assets/
After creating the brand, verify with:
Glob: .claude/brands/{brand-name}/*
Then proceed to slide generation.
This skill operates in four modes:
User wants presentation slides (16:9) created using a brand's styling.
→ Follow: Brand Discovery → Layout Selection → Content Adaptation → Execute
→ Layouts in: cookbook/*.py
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
User wants to create, edit, or improve layout templates. → Follow: Layout CRUD Operations section
User wants to generate slides from a specific report type (QA report, RCA report, etc.).
→ Follow: Workflow Discovery → Read Workflow → Extract Data → Generate Slides
→ Workflows in: workflows/*.md
Workflows are pre-defined presentation patterns for common use cases. They specify:
When user mentions a workflow or provides a report that matches a workflow type:
Glob: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/workflows/*.md
Available Workflows:
| Workflow | Triggers | Use Case |
|---|---|---|
qa-report | "QA report", "smoke test", "gate validation", "environment health" | QA test analysis reports |
rca-report | "RCA", "root cause", "incident", "postmortem", "pipeline failure" | Root cause analysis reports |
Read: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/workflows/{workflow-name}.md
The workflow file contains:
Follow the workflow's "Data Extraction Guide" to identify:
Use the workflow's "Slide Structure" section to choose the appropriate template:
Follow Mode 1 (Generate Presentation Slides) using:
User Input:
Create slides for azure-engineering brand from this QA report:
[paste report with environment status, test results, actions]
Use the qa-report workflow.
Process:
workflows/qa-report.mdUser Input:
Create slides for azure-engineering brand from this RCA:
[paste report with root cause, resolution steps, recommendations]
Use the rca-report workflow.
Process:
workflows/rca-report.mdTo add a new workflow:
Create the workflow file:
${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/workflows/{workflow-name}.md
Include required sections:
---
name: workflow-name
description: What this workflow is for
triggers:
- "trigger phrase 1"
- "trigger phrase 2"
brand: default-brand
---
# Workflow Name
## Purpose
## When to Use
## Required Input
## Slide Structure
## Data Extraction Guide
## Example Prompts
## Layout Selection Logic
## Color Mapping
## Output
Test the workflow with a sample report
List available brands:
Glob: .claude/brands/*/brand.json
Extract unique brand names from paths (e.g., brands/rasmus/... → "rasmus")
Read the brand configuration files:
Read: .claude/brands/{brand-name}/brand.json
Read: .claude/brands/{brand-name}/config.json
brand.json - Colors, fonts, assetsconfig.json - Output directory, generation settingsRead supporting markdown files for context:
Glob: .claude/brands/{brand-name}/*.md
These provide voice, tone, and design philosophy.
Extract from brand files:
If brand not found, list available brands and ask user to choose.
⚠️ 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_PLUGIN_ROOT}/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:
purpose, best_for)avoid_when)max_*, min_*, *_max_chars)The frontmatter block looks like this:
# /// layout
# name = "floating-cards-slide"
# purpose = "Feature highlights, process steps, multiple equal items with depth"
# best_for = [
# "Exactly 3 related features or concepts",
# "Process with 3 steps",
# ]
# avoid_when = [
# "More than 3 items - use multi-card-slide instead",
# "Long card titles (over 15 characters)",
# ]
# max_cards = 3
# card_title_max_chars = 15
# instructions = [
# "EXACTLY 3 cards required - no more, no less",
# "Card titles must be SHORT: 1-2 words, max 15 characters",
# ]
# ///
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:
best_for criteriaavoid_when → Don't use a layout in situations it warns againstmax_*, use a different layoutExample selection process:
floating-cards-slide: max_cards = 3 → Won't workmulti-card-slide: max_cards = 5 → Perfect fitmulti-card-slideWhy read ALL frontmatters?
avoid_when (e.g., "use multi-card-slide instead")🎨 DEFAULT TO VISUAL LAYOUTS. Content-slide is the LAST RESORT, not the default.
The biggest mistake in presentation generation is defaulting to content-slide (title + bullets) whenever you have information to convey. This creates repetitive, boring presentations.
Common failure pattern:
HARD LIMITS:
Ask these questions IN ORDER before defaulting to content-slide:
Do I have 3-5 equal items?
YES → Use multi-card-slide (not content-slide)
Do I have 2-4 big numbers/metrics?
YES → Use stats-slide (not content-slide)
Am I comparing two things?
YES → Use two-column-slide (not content-slide)
Do I have a central concept with surrounding items?
YES → Use circular-hero-slide (not content-slide)
Do I have exactly 3 related items?
YES → Use floating-cards-slide (not content-slide)
Do I have 1-3 words I want to emphasize dramatically?
YES → Use giant-focus-slide or bold-diagonal-slide (not content-slide)
Do I have a powerful quote or principle?
YES → Use quote-slide (not content-slide)
Is this the ONLY way to present this information?
YES → NOW you can use content-slide
NO → Go back through the decision tree
Example 1: "Validation Patterns"
❌ BAD (content-slide):
Title: Validation Patterns
Bullets:
- Run comprehensive test suites
- Type checking and linting
- Code review by humans and AI
- Deployment previews
✅ GOOD (multi-card-slide):
Title: Validation Patterns
Cards:
1. Testing | Run comprehensive test suites after every change
2. Linting | Type checking and formatting as guardrails
3. Review | Human and AI code review process
4. Preview | Deployment previews for visual regression
Example 2: "Why PIV Works"
❌ BAD (content-slide):
Title: Why PIV Works
Bullets:
- Forces planning before implementation
- Validation catches issues immediately
- Iterative improvements compound
- System gets smarter with every bug
✅ GOOD (floating-cards-slide with 3 cards):
Title: Why PIV Works
Cards:
1. Plan First | Forces architectural thinking before coding
2. Fast Feedback | Validation catches issues immediately
3. Compounds | System improves with every bug
(Note: Reduced from 4 to 3 items to fit floating-cards-slide max_cards limit)
Example 3: "Human-in-the-Loop Strategy"
❌ BAD (content-slide):
Title: Human-in-the-Loop Strategy
Bullets:
- In-the-loop: Human approves before execution
- On-the-loop: Human reviews after completion
- Code review remains critical
- AI generates, humans validate
✅ GOOD (two-column-slide):
Title: Human-in-the-Loop Strategy
Left: In-the-Loop
- Human approves before execution
- Critical for production changes
- Quality gateway
Right: On-the-Loop
- Human reviews after completion
- Faster iteration cycles
- AI generates, human validates
Before planning any slide, ask yourself:
Use content-slide ONLY when:
Never use content-slide as your default thinking.
| Content Type | Best Layout | Why |
|---|---|---|
| 3-5 equal features/steps | multi-card-slide | Cards create visual hierarchy |
| Exactly 3 featured items | floating-cards-slide | Elevated cards add depth |
| 2-4 metrics/KPIs | stats-slide | Big numbers grab attention |
| Before/after comparison | two-column-slide | Side-by-side shows contrast |
| Hub concept with types | circular-hero-slide | Radiating pattern shows relationships |
| Dramatic emphasis (1-3 words) | giant-focus-slide | Scale creates impact |
| High-energy warning | bold-diagonal-slide | Dynamic shapes convey urgency |
| Powerful quote/principle | quote-slide | Attribution adds authority |
| List of related items | multi-card-slide | Better than bullets |
| Process with steps | floating-cards-slide | Visual flow beats text |
| Technical comparison | two-column-slide | Structured comparison |
Only use content-slide when:
Before generating ANY slides, create a written plan.
This applies to single slides, batches, and full presentations. Planning prevents:
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:
Planning checklist:
After planning, briefly present the plan before generating.
Example of good variety distribution for 30-slide presentation:
For each slide in your plan:
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:
Exception: Full sentence descriptions or quotes may use appropriate punctuation.
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)
MAXIMUM 5 SLIDES PER BATCH. This is a hard limit.
When generating multiple slides:
Why batching matters:
⚠️ CRITICAL BACKGROUND BUG FIX:
EVERY slide MUST have its background explicitly set. If you don't set slide.background.fill.solid() and slide.background.fill.fore_color.rgb, the slide will use PowerPoint's default WHITE background, making text unreadable on dark-themed brands.
Mandatory for every slide:
slide = prs.slides.add_slide(prs.slide_layouts[6])
slide.background.fill.solid() # ← REQUIRED
slide.background.fill.fore_color.rgb = hex_to_rgb(BRAND_BG) # ← REQUIRED
This is especially critical when:
Execution:
PREFERRED: Use heredoc (no files created):
uv run --with python-pptx==1.0.2 python << 'EOF'
# [Adapted code with brand values and content]
EOF
IF heredoc fails (Windows issues): Use temp directory:
# Create temp directory if needed
mkdir -p .tmp
# Write script to temp directory
# (create file at .tmp/gen.py)
# Execute
uv run --with python-pptx==1.0.2 python .tmp/gen.py
# MANDATORY: Clean up immediately after execution
rm .tmp/gen.py
CRITICAL: Never create Python files in the repository root. Always use heredoc or temp directory within the skill folder.
After EVERY batch, validate before continuing:
| Issue | What to Look For | Fix |
|---|---|---|
| White background | Slide has white background instead of brand color | Add slide.background.fill.solid() and set fore_color.rgb |
| 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:
If validation passes:
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)# Create output directory from config
mkdir -p {resolved-output-directory}
Batched generation workflow:
{name}-part1.pptx, {name}-part2.pptx, etc.auto_combine is true)keep_parts is false)🚨 CRITICAL BUG WARNING: BACKGROUND MUST BE SET WHEN COMBINING 🚨
When combining presentations, add_slide() creates slides with DEFAULT WHITE BACKGROUNDS. Shape copying does NOT copy the slide background property. You MUST explicitly set the background immediately after creating each new slide.
This is the most common source of white slides in combined 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 pptx.dml.color import RGBColor
from pathlib import Path
import shutil
def hex_to_rgb(hex_color: str) -> RGBColor:
h = hex_color.lstrip("#")
return RGBColor(int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16))
# Brand background color (get from brand.json)
BRAND_BG = "REPLACE_WITH_BRAND_BACKGROUND" # e.g., "07090F"
# List all part files in order
output_dir = Path("output/{brand-name}")
part_files = sorted(output_dir.glob("{name}-part*.pptx"))
if len(part_files) > 1:
# Start with first part as base
combined = Presentation(part_files[0])
# Add slides from remaining parts
for part_file in part_files[1:]:
part_prs = Presentation(part_file)
for slide in part_prs.slides:
# Copy slide layout and add to combined
blank_layout = combined.slide_layouts[6]
new_slide = combined.slides.add_slide(blank_layout)
# 🚨 CRITICAL: Set background IMMEDIATELY after creating slide
# PowerPoint defaults to WHITE background - this MUST be set before copying shapes
new_slide.background.fill.solid()
new_slide.background.fill.fore_color.rgb = hex_to_rgb(BRAND_BG)
# Copy all shapes from source slide
for shape in slide.shapes:
# Clone shape to new slide
el = shape.element
new_slide.shapes._spTree.insert_element_before(
el, 'p:extLst'
)
# Save combined file
combined.save(output_dir / "{name}-final.pptx")
print(f"Combined {len(part_files)} parts into {name}-final.pptx")
# MANDATORY: Clean up part files - user should only see final file
for part_file in part_files:
part_file.unlink()
print(f"Deleted {part_file.name}")
else:
# Single part, just rename
shutil.move(part_files[0], output_dir / "{name}-final.pptx")
SCRIPT
Final output: output/{brand-name}/{name}-final.pptx
Why this bug happens:
combined.slides.add_slide() creates a NEW slide object with PowerPoint's default white backgroundshapes._spTree.insert_element_before() copies shapes (text, rectangles, images) but NOT the backgroundTesting checklist after combining:
LinkedIn carousels are multi-page PDFs in square (1:1) format. Each page is a swipeable slide.
| 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 |
Same as Mode 1 - read brand.json, config.json, and tone-of-voice.md.
Discover carousel-specific layouts:
Glob: ${CLAUDE_PLUGIN_ROOT}/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.
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:
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'
# Carousel generation code with 7.5" x 7.5" dimensions
SCRIPT
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
Save both files:
output/{brand}/{name}-carousel.pptx - Editable sourceoutput/{brand}/{name}-carousel.pdf - LinkedIn-readycookbook/carousels/When user requests a new layout type:
Study existing layouts for patterns:
Glob: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/cookbook/*.py
Read 2-3 layouts to understand:
Design with these quality standards:
MUST be production-ready:
Use appropriate elements:
Avoid:
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:
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "python-pptx==1.0.2",
# ]
# ///
# /// layout
# name = "layout-name"
# purpose = "When to use this layout - be specific"
# best_for = [
# "Ideal use case 1",
# "Ideal use case 2",
# ]
# avoid_when = [
# "Situation to avoid 1 - and what to use instead",
# "Situation to avoid 2 - and what to use instead",
# ]
# max_items = 5 # or other relevant limits
# instructions = [
# "Specific tip 1",
# "Specific tip 2",
# ]
# ///
"""
LAYOUT: [Name]
PURPOSE: [When to use this layout - be specific]
CUSTOMIZE:
- [List customizable elements]
"""
# ... implementation
Required frontmatter fields (be DETAILED and SPECIFIC):
| Field | Description | Example |
|---|---|---|
name | Layout identifier (matches filename) | "multi-card-slide" |
purpose | Clear one-line description | "Multiple items as cards in a row, 3-5 cards" |
best_for | Detailed array of ideal scenarios | ["Exactly 3 related features", "Process with 3 steps"] |
avoid_when | Specific situations with alternatives | ["More than 3 items - use multi-card-slide instead"] |
instructions | Actionable tips for correct usage | ["Card titles must be SHORT: 1-2 words, max 15 chars"] |
Optional but recommended fields:
| Field | Description | Example |
|---|---|---|
max_* / min_* | Hard limits on items | max_cards = 3, min_surrounding_items = 4 |
*_max_chars | Character limits for text | card_title_max_chars = 15 |
Writing good frontmatter:
✅ DO: Be specific and actionable
# avoid_when = [
# "More than 3 items - use multi-card-slide instead",
# "Long card titles (over 15 characters) - abbreviate or use content-slide",
# ]
# instructions = [
# "EXACTLY 3 cards required - no more, no less",
# "Card titles must be SHORT: 1-2 words, max 15 characters",
# "If titles are too long, abbreviate or use different layout",
# ]
❌ DON'T: Be vague or unhelpful
# avoid_when = ["Too many items", "Wrong content"]
# instructions = ["Use correctly", "Follow the pattern"]
Think of frontmatter as teaching a colleague - what would they need to know to use this layout correctly without asking you questions?
Save to cookbook:
${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/cookbook/{layout-name}-slide.py
Test by generating a sample with the new layout
Find the layout:
Glob: ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/cookbook/*{name}*.py
Read and understand current structure including the frontmatter
Make modifications while preserving:
Update the frontmatter if your changes affect:
best_for)avoid_when)max_*, min_*)instructions)Save back to the same file
Test the modified layout
When asked to improve layout quality:
Analyze current weaknesses:
Apply improvements:
Preserve functionality - Don't break what works
Review and enhance frontmatter:
best_for and avoid_when still accurate?instructions reflect any new constraints?Simply remove the file:
rm ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/cookbook/{layout-name}.py
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)
Slide dimensions (16:9):
Always use:
prs.slide_layouts[6]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 chartXL_CHART_TYPE.DOUGHNUT - Doughnut chartXL_CHART_TYPE.BAR_CLUSTERED - Horizontal barsXL_CHART_TYPE.COLUMN_CLUSTERED - Vertical columnsXL_CHART_TYPE.LINE - Line chartAdding 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) # Height auto-calculated
)
To see all available layouts:
uv run ${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/generate-cookbook-preview.py
This generates cookbook-preview.pptx with every layout.
For Slide Generation:
${CLAUDE_PLUGIN_ROOT}/skills/pptx-generator/cookbook/*.py# /// layout blocksbest_for, avoid_when, limitsbest_for criteriaavoid_when warningsmax_* / min_* limitsinstructions for chosen layoutsslides_per_batch from config)auto_combine is true)keep_parts is false)For Creating Layouts:
name, purposebest_for, avoid_when arraysinstructions array with usage tipsmax_* / min_* limits as needed