May 11, 2026
Build a Social Carousel Pipeline Without a Design Tool
How I use Claude Code and Playwright to go from topic to published carousel in under 10 minutes - with a copyable setup skill.
I created a carousel with claude code and playwright, and it was never opened in Canva, Figma, or any design tool.
Claude Code wrote the content, built the slides, took the screenshots, and scheduled the post.
My only job was to approve each stage before moving forward.
This is now my default pipeline for every social carousel.
Here's how it works - and a ready-to-use Claude Code skill to set it up in your own workspace.
BTW - if you liked it - give it a share.. Copy and paste this link and push it into your feed or friends.
What the Pipeline Does
The core idea: instead of designing slides in a visual tool, Claude generates each slide as an HTML page.
Playwright - a browser automation library - takes a full-resolution screenshot of each page.
The output is a set of PNG files, pixel-consistent, ready to upload to any platform.
I created a skill for your agent that will setup playwright in 1 minute.
No exports. No template shopping. No design subscription.
The approval flow is explicit. After Claude writes the slide plan, you approve it before anything gets built. After the slides are built, you review every image before anything goes to scheduling. The AI handles the production work. You stay in the loop.
What You Need
- Python 3.10+ - for the slide rendering script
- Node.js - for Playwright and the screenshot helper
- Claude Code - running in your workspace
- A logo file (PNG) - optional, for branded footers. If you don't have one, Claude uses your name as text.
No Canva account. No design subscription. No cloud credits beyond what Claude Code uses.
How It Works
Six stages, each gated by your approval:
- Brand setup - Claude asks for your name, handle, hashtag, logo, and preferred style. These become the defaults for every carousel going forward.
- Folder structure - Claude creates the directory layout: configs, brand assets, in-progress slides, published archives.
- Script installation - Claude writes a Python script that converts a simple text config into designed HTML slides, then screenshots them via Playwright. Dependencies go into a virtual environment.
- Content - You describe the post topic. Claude writes a slide plan - cover, content slides, CTA. You approve before anything is built.
- Build - Claude runs the script, generates PNG files, and shows them to you. You approve the visuals.
- Publish - Slides go to your publishing tool of choice. Folder moves to the published archive.
I use a tool called Blotato - but there are hundreds out there. Find one you like and swap out Step 6 in the skill below.
First run takes about 15 minutes to set up.
Every subsequent carousel: under 10.
One thing about the content, Claude can't guess your tone of voice or your style - so you'll need to provide that in Step 4.
But once you define it once, Claude will remember it for all future carousels.
The Slide Design
Three slide types - simple, consistent:
- Cover - black background, large centered text, "Swipe Right" prompt
- Content - white background, heading + body text, accent line, logo footer
- CTA - black background, centered question, bordered button
Logo on dark slides is automatically inverted to white. Maximum 10 slides - the hard limit for both LinkedIn and Instagram.
Copy This to Your Agent
Save the skill below as .claude/commands/carousel-pipeline.md in your project root. Then type /carousel-pipeline in Claude Code to begin.
On first run, Claude sets up the full environment and writes the build script. On every subsequent run, it goes straight to content.
### Ready to use - copy this
```markdown
# /carousel-pipeline
Build a social media carousel end-to-end: content → HTML slides → screenshots → approval → publish.
Runs locally. No design tool needed.
---
## First Run vs. Returning Sessions
**First run** (no `carousel/` folder yet): complete Steps 0 through 3 before content.
**Returning session**: skip to Step 4. Brand and scripts are already in place.
---
## Step 0 - Define Your Brand
Ask the user:
1. Your name (for slide footer)
2. Your social handle (e.g. @yourhandle)
3. Primary hashtag (e.g. #ClaudeCode)
4. Logo file path (PNG preferred) - or "no logo"
5. Slide style preference (default: black and white)
Store answers. They become defaults for every carousel config.
---
## Step 1 - Create Folder Structure
Create in the project root:
```
carousel/
config/ ← one YAML file per post slug
brand/ ← logo.png and other brand assets
in-progress/ ← slides being built (one subfolder per slug)
published/ ← move here after publishing
```
---
## Step 2 - Set Up Python Environment
```bash
python -m venv carousel/.venv
```
Activate:
- Windows: `carousel\.venv\Scripts\activate`
- Mac/Linux: `source carousel/.venv/bin/activate`
Install:
```bash
pip install pyyaml
```
---
## Step 3 - Install Playwright and Build Script
Install Playwright globally:
```bash
npm install -g playwright
npx playwright install chromium
```
Create `carousel/screenshot.js`:
```js
const { chromium } = require('playwright');
const path = require('path');
const [,, inputPath, outputPath = 'screenshot.png', ...flags] = process.argv;
const width = parseInt((flags.find(f => f.startsWith('--width=')) || '--width=800').split('=')[1]);
const height = parseInt((flags.find(f => f.startsWith('--height=')) || '--height=1000').split('=')[1]);
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.setViewportSize({ width, height });
const url = inputPath.startsWith('http')
? inputPath
: `file:///${path.resolve(inputPath).replace(/\\/g, '/')}`;
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot({ path: outputPath, fullPage: false });
await browser.close();
console.log(`Screenshot saved: ${outputPath}`);
})();
```
Create `carousel/build.py`. This script:
- Reads a YAML config file
- Renders one HTML page per slide (three types: cover, content, cta)
- Screenshots each page via `carousel/screenshot.js` at 800x1000px
- Saves PNG files to the output directory in the config
**Slide types:**
- `cover` - black background, large centered heading, name/handle footer, "Swipe Right" button
- `content` - white background, left-aligned heading + body text, optional `accent: true` adds a rule line, logo footer
- `cta` - black background, centered heading + subtext + bordered button, name/handle footer
**Logo handling:** if a `logo:` path is set in config, render it as an `<img>` tag in the footer.
On dark slides use `filter: invert(1)`. On light slides use as-is.
Fallback: render text (author name + handle) if no logo.
**Font:** Poppins via Google Fonts (800 weight for headings, 400 for body).
**Config format:**
```yaml
output_dir: carousel/in-progress/[slug]/
author: Your Name
handle: "@yourhandle"
hashtag: "#YourHashtag"
logo: carousel/brand/logo.png # omit if no logo
slides:
- type: cover
heading: "Your hook here"
- type: content
heading: "Section heading"
body: "Body text for this slide."
accent: true
- type: cta
heading: "Your CTA question"
body: "How to take action."
cta_button: "Comment below"
```
Run to build:
```bash
python carousel/build.py carousel/config/[slug].yaml
```
---
## Step 4 - Write the Post Content (Approval Gate 1)
Ask the user:
- What is this post about?
- Who is the audience?
- What's the one thing you want them to take away?
Write a slide plan (max 10 slides):
- Slide 1: Cover - the hook. One strong claim or question.
- Slides 2-8: Content - one idea per slide. Short and scannable.
- Last slide: CTA - one clear action.
**Present the slide plan. Wait for explicit approval before building anything.**
---
## Step 5 - Build the Slides (Approval Gate 2)
Create `carousel/config/[slug].yaml` from the approved slide plan.
Run:
```bash
python carousel/build.py carousel/config/[slug].yaml
```
Screenshot each output PNG and show it to the user.
**Wait for explicit approval before publishing.**
---
## Step 6 - Publish
Slides are in `carousel/in-progress/[slug]/`. Upload using your publishing tool.
After publishing: move the folder to `carousel/published/[slug]/`.
---
## Hard Limits
| Platform | Max slides |
|-----------|-----------|
| LinkedIn | 10 |
| Instagram | 10 |
| Facebook | 16 |
```
One note worth making:
the first time you run this, Claude writes real working code from scratch.
That's the point.
You're not installing a plugin or connecting to a SaaS tool. You're building something you own - and once it's built, you can extend it however you want.
The build.py on my system has logo inversion, three slide types, and a Poppins font setup.
Claude will build something equivalent when it sets up yours.
If the default style doesn't fit your brand, tell it what to change and regenerate. The whole point of having the source is that you can.
GOOD LUCK :)