LinkedIn Carousel Generator
Generates LinkedIn carousel PDFs from content briefs. Four HTML templates rendered through Playwright. Output is a single multi-page PDF ready for upload as a LinkedIn document post.
First-Run Setup (ALWAYS check first)
Before generating any carousel, verify the user has personalized brand-config.yaml. Look for these placeholder values:
owner_name: "Your Name"
company: "Your Company"
website: "yourwebsite.com"
footer_line: "your name | yourwebsite.com"
If ANY of those are still at placeholder defaults, pause and ask the user to fill them in. Offer to:
- Update
brand-config.yaml for them (ask for: name, company, website, professional tagline, preferred primary color in hex)
- Have them drop a logo at
assets/logo.svg (or .png) and a square headshot at assets/headshot.png (500x500 minimum)
Only after brand setup is complete, proceed to carousel generation.
Why HTML/CSS (not PPTX, not image generation)
Code is reproducible. Image generation is not. PPTX text rendering is inconsistent across viewers. Controlled HTML + Playwright gives pixel-perfect consistency across runs and slides.
Design Rules
- No floating text over shapes. Text lives inside its container with proper padding and vertical alignment.
- Merge related text. Title and body in the same content block, not two stacked separate blocks.
- Executive voice. Before rendering, pass slide text through these filters:
- No em dashes. Replace with periods, colons, or parentheses.
- No AI filler phrases: "delve into", "navigate", "landscape", "leverage", "moreover", "furthermore", "additionally".
- Short sentences. Vary length naturally.
- Accessible beats impressive. Clarity wins.
Inputs
The user provides one of:
| Input type |
What to do |
| Raw text / bullets |
Parse directly into slide structure |
| URL |
Fetch with WebFetch, extract the core argument, then structure |
| Uploaded docx / pdf |
Read the file, extract the argument, then structure |
They may also specify:
- Template:
executive-minimal (default), training-breakdown, quote-forward, mobile-optimized
- Slide count: 5, 7, 10 (default 7)
- Palette variant:
brand (default) or mobile (higher contrast for small screens)
Carousel Structure (Standard Arc)
- Hook slide: one bold sentence that creates tension or curiosity
- Context slide: why this matters, who it's for
- Body slides (3-7): one idea per slide, no crowding
- Takeaway slide: the one thing to remember
- CTA slide: simple ask plus website
Templates
| Template |
Visual feel |
Best for |
executive-minimal |
Clean typography, generous whitespace, muted accents |
C-suite content, strategy takes |
training-breakdown |
Numbered steps, structured grid. Dual-purpose: also works as in-room training slides |
Workshop recaps, frameworks |
quote-forward |
Alternating full-bleed slides with big pull quotes |
Thought leadership, manifestos |
mobile-optimized |
Oversized type (min 48px body), highest contrast |
Feed-first content, mobile readers |
Workflow
- Verify brand setup (see First-Run Setup).
- Parse the input. If URL, fetch it. If file, read it. If raw text, proceed.
- Draft the slide content as structured JSON:
{
"template": "executive-minimal",
"palette": "brand",
"cover": {"hook": "...", "subline": "..."},
"slides": [
{"title": "...", "body": "..."}
],
"takeaway": {"title": "...", "body": "..."},
"cta": {"primary": "Follow for more on X", "secondary": "yourwebsite.com"}
}
- Scrub the copy. Apply executive voice filters.
- Show the user the JSON before rendering. They may tweak a slide.
- Render:
python3 <skill-directory>/scripts/render.py \
--content /path/to/content.json \
--brand-config <skill-directory>/brand-config.yaml \
--output /path/to/output.pdf
- Deliver the PDF.
Slide Count Logic
- 5 slides: cover + 2 body + takeaway + CTA
- 7 slides: cover + context + 3 body + takeaway + CTA (default)
- 10 slides: cover + context + 5-6 body + takeaway + CTA
LinkedIn allows up to 20 slides per document post. Rarely exceed 12.
Dimensions
Each slide renders at 1080x1350 px (4:5 portrait). LinkedIn's recommended document post ratio.
Dependencies
One-time install:
pip install playwright jinja2 pyyaml --break-system-packages
python3 -m playwright install chromium
Important
- Never use em dashes in slide text. Never.
- The footer line appears on every slide. Edit it in
brand-config.yaml.
- Always render to PDF. Not PNG. LinkedIn document posts need PDF.
- If
assets/headshot.png is missing, the CTA slide falls back to the user's initials on a colored circle. Acceptable but personalization is stronger.
1---2name: linkedin-carousel3description: Generates on-brand LinkedIn carousel PDFs (1080x1350 per slide) from raw text, URLs, or uploaded documents. Four templates: executive-minimal, training-breakdown, quote-forward, and mobile-optimized. Fully brandable: colors, fonts, logo, headshot, and footer text come from brand-config.yaml. Triggers on: 'make a LinkedIn carousel', 'build a LinkedIn swipe post', 'turn this article into a carousel', 'create slides for LinkedIn', 'carousel post about X', 'convert this post to a carousel', 'repurpose this for LinkedIn'.4---56# LinkedIn Carousel Generator78Generates LinkedIn carousel PDFs from content briefs. Four HTML templates rendered through Playwright. Output is a single multi-page PDF ready for upload as a LinkedIn document post.910## First-Run Setup (ALWAYS check first)1112Before generating any carousel, verify the user has personalized `brand-config.yaml`. Look for these placeholder values:1314- `owner_name: "Your Name"`15- `company: "Your Company"`16- `website: "yourwebsite.com"`17- `footer_line: "your name | yourwebsite.com"`1819If ANY of those are still at placeholder defaults, pause and ask the user to fill them in. Offer to:20211. Update `brand-config.yaml` for them (ask for: name, company, website, professional tagline, preferred primary color in hex)222. Have them drop a logo at `assets/logo.svg` (or `.png`) and a square headshot at `assets/headshot.png` (500x500 minimum)2324Only after brand setup is complete, proceed to carousel generation.2526## Why HTML/CSS (not PPTX, not image generation)2728Code is reproducible. Image generation is not. PPTX text rendering is inconsistent across viewers. Controlled HTML + Playwright gives pixel-perfect consistency across runs and slides.2930## Design Rules31321. **No floating text over shapes.** Text lives inside its container with proper padding and vertical alignment.332. **Merge related text.** Title and body in the same content block, not two stacked separate blocks.343. **Executive voice.** Before rendering, pass slide text through these filters:35 - No em dashes. Replace with periods, colons, or parentheses.36 - No AI filler phrases: "delve into", "navigate", "landscape", "leverage", "moreover", "furthermore", "additionally".37 - Short sentences. Vary length naturally.384. **Accessible beats impressive.** Clarity wins.3940## Inputs4142The user provides one of:4344| Input type | What to do |45|------------|------------|46| Raw text / bullets | Parse directly into slide structure |47| URL | Fetch with WebFetch, extract the core argument, then structure |48| Uploaded docx / pdf | Read the file, extract the argument, then structure |4950They may also specify:5152- **Template**: `executive-minimal` (default), `training-breakdown`, `quote-forward`, `mobile-optimized`53- **Slide count**: 5, 7, 10 (default 7)54- **Palette variant**: `brand` (default) or `mobile` (higher contrast for small screens)5556## Carousel Structure (Standard Arc)57581. **Hook slide**: one bold sentence that creates tension or curiosity592. **Context slide**: why this matters, who it's for603. **Body slides (3-7)**: one idea per slide, no crowding614. **Takeaway slide**: the one thing to remember625. **CTA slide**: simple ask plus website6364## Templates6566| Template | Visual feel | Best for |67|----------|-------------|----------|68| `executive-minimal` | Clean typography, generous whitespace, muted accents | C-suite content, strategy takes |69| `training-breakdown` | Numbered steps, structured grid. Dual-purpose: also works as in-room training slides | Workshop recaps, frameworks |70| `quote-forward` | Alternating full-bleed slides with big pull quotes | Thought leadership, manifestos |71| `mobile-optimized` | Oversized type (min 48px body), highest contrast | Feed-first content, mobile readers |7273## Workflow74751. **Verify brand setup** (see First-Run Setup).762. **Parse the input.** If URL, fetch it. If file, read it. If raw text, proceed.773. **Draft the slide content** as structured JSON:78 ```json79 {80 "template": "executive-minimal",81 "palette": "brand",82 "cover": {"hook": "...", "subline": "..."},83 "slides": [84 {"title": "...", "body": "..."}85 ],86 "takeaway": {"title": "...", "body": "..."},87 "cta": {"primary": "Follow for more on X", "secondary": "yourwebsite.com"}88 }89 ```904. **Scrub the copy.** Apply executive voice filters.915. **Show the user the JSON** before rendering. They may tweak a slide.926. **Render:**93 ```bash94 python3 <skill-directory>/scripts/render.py \95 --content /path/to/content.json \96 --brand-config <skill-directory>/brand-config.yaml \97 --output /path/to/output.pdf98 ```997. **Deliver** the PDF.100101## Slide Count Logic102103- **5 slides**: cover + 2 body + takeaway + CTA104- **7 slides**: cover + context + 3 body + takeaway + CTA (default)105- **10 slides**: cover + context + 5-6 body + takeaway + CTA106107LinkedIn allows up to 20 slides per document post. Rarely exceed 12.108109## Dimensions110111Each slide renders at **1080x1350 px** (4:5 portrait). LinkedIn's recommended document post ratio.112113## Dependencies114115One-time install:116117```bash118pip install playwright jinja2 pyyaml --break-system-packages119python3 -m playwright install chromium120```121122## Important123124- Never use em dashes in slide text. Never.125- The footer line appears on every slide. Edit it in `brand-config.yaml`.126- Always render to PDF. Not PNG. LinkedIn document posts need PDF.127- If `assets/headshot.png` is missing, the CTA slide falls back to the user's initials on a colored circle. Acceptable but personalization is stronger.