skills/instagram-thread-carousel/SKILL.md
Use when the user wants to turn a text thread into an Instagram carousel that looks like tweet/X post screenshots. Generates slide images with profile pic, name, verified badge, handle, and tweet text. Supports embedded images and combining short tweets on one slide.
npx skillsauth add kennyolofsson23-netizen/claude-code-config instagram-thread-carouselInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Convert a text thread into Instagram carousel slides styled as tweet/X post mockups. Each slide renders a clean tweet card with profile picture, display name, verified badge, handle, and the tweet text. Optionally embed images in tweets and combine short tweets 2-per-slide.
Get the thread content from the user. They may:
If writing the thread, use the voice and tone from CLAUDE.md. Each tweet in the thread should be a self-contained thought that flows into the next.
Ask for anything not already known:
@itstylergermainls .claude/skills/instagram-thread-carousel/headshots/ and let the user pick, or use the first one found.If CLAUDE.md has been personalized (audit has been run), pull the name and handle from there.
Rules for slide layout:
One tweet per slide (default):
Two tweets per slide:
Walk through the thread and decide the slide breakdown. Present it to the user before generating:
Slide 1: Tweet 1 (hook) - own slide
Slide 2: Tweet 2 + Tweet 3 - combined (both short)
Slide 3: Tweet 4 - own slide (has image)
Slide 4: Tweet 5 + Tweet 6 - combined (both short)
Slide 5: Tweet 7 (CTA) - own slide
Images make carousels significantly more engaging. For each tweet that could benefit from a visual, determine how to source the image:
User-provided images:
ref/ subfolder firstSearch for images with Tavily: If the user doesn't provide images (or asks you to find them), use the Tavily image search script to find relevant visuals:
python3 .claude/skills/instagram-thread-carousel/scripts/tavily-image-search.py "search query" workspace/<date>/<title>/ref --count 5
This downloads images and creates a manifest JSON. Review the downloaded images and pick the best ones for each tweet. Good search queries are specific - e.g., "YouTube thumbnail example tech channel" not just "thumbnail".
Requires TAVILY_API_KEY in .env. If not set, skip image search and proceed with text-only slides.
Search for GIFs with Giphy: When the carousel calls for animated content (reaction GIFs, demonstrations, etc.):
python3 .claude/skills/instagram-thread-carousel/scripts/giphy-search.py "search query" workspace/<date>/<title>/ref --count 5
Downloads GIFs and creates a manifest JSON. The thread-to-carousel script automatically handles animated GIFs by outputting both an MP4 (for Instagram) and a PNG (static preview).
Requires GIPHY_API_KEY in .env.
Website screenshots: When the carousel is about a website, product, or tool, take a fresh screenshot instead of relying on Tavily (which often returns outdated images):
python3 .claude/skills/instagram-thread-carousel/scripts/website-screenshot.py "https://example.com" workspace/<date>/<title>/ref/homepage.png --width 1280 --height 800
Options: --width and --height set the viewport, --full-page captures the entire scrollable page. Requires playwright (pip install playwright && playwright install chromium).
Always prefer a live screenshot over a Tavily image search result when the carousel is about a specific website or product.
Website recordings with Steel: When you need a video recording of browsing a website (for animated carousel slides or reference), use the Steel browser:
python3 .claude/skills/instagram-thread-carousel/scripts/steel-browse.py browse-plan.json workspace/<date>/<title>/ref
Create a browse-plan.json with a list of actions:
{
"viewport": { "width": 1920, "height": 1080 },
"actions": [
{ "action": "navigate", "url": "https://example.com", "label": "Open homepage", "wait": 2000 },
{ "action": "click", "selector": "button.cta", "label": "Click CTA", "wait": 1500 },
{ "action": "click_at", "x": 960, "y": 540, "label": "Click center", "wait": 1000 },
{ "action": "scroll", "y": 500, "label": "Scroll down", "wait": 1000 },
{ "action": "hover", "selector": ".card", "label": "Hover card", "wait": 1000 },
{ "action": "type", "selector": "input.search", "text": "query", "label": "Type search", "wait": 1000 },
{ "action": "keyboard_type", "text": "hello world", "label": "Type text", "wait": 1000 },
{ "action": "keyboard_press", "key": "Enter", "label": "Press Enter", "wait": 1000 }
]
}
Outputs recording.mp4 and moments.json to the output directory. Requires STEEL_API_KEY in .env and pip install steel-sdk playwright.
Image rules:
Each carousel gets its own folder under workspace/ organized by date and title. Pick a short, descriptive name based on the topic (e.g., thumbnail-generator, claude-youtube, ai-agents-101).
Folder structure:
workspace/<date>/<title>/
├── config.json # Slide config
├── ref/ # Reference images used in slides
│ ├── screenshot.png
│ └── ...
├── slide-01.png # Generated slides
├── slide-02.png
└── ...
Create the config file at workspace/<date>/<title>/config.json:
{
"profile": {
"name": "Display Name",
"handle": "@handle",
"verified": true,
"headshot": ".claude/skills/instagram-thread-carousel/headshots/tyler-headshot.png"
},
"theme": "light",
"slides": [
{
"tweets": [
{
"text": "This is the first tweet.\n\nIt can have multiple paragraphs.\n\nUse \\n for line breaks.",
"image": null
}
]
},
{
"video": "workspace/<date>/<title>/ref/demo.mp4"
},
{
"tweets": [
{ "text": "Short tweet one.", "image": null },
{ "text": "Short tweet two.", "image": null }
]
},
{
"tweets": [
{
"text": "Tweet with an image below it.",
"image": "workspace/<date>/<title>/ref/screenshot.jpg"
}
]
}
]
}
Config options:
theme - "light" (white background, dark text) or "dark" (black background, light text). Default: "light".Video slides:
"video": "path/to/video.mp4" at the slide level (no tweets needed)slide-XX.mp4 and extracts a slide-XX.png previewText formatting tips:
\n for line breaks within a tweet\n\n for paragraph breaks (adds extra spacing)→ Point one\n→ Point twopython3 .claude/skills/instagram-thread-carousel/scripts/thread-to-carousel.py workspace/<date>/<title>/config.json workspace/<date>/<title>
This generates numbered PNG files: slide-01.png, slide-02.png, etc. inside the carousel folder.
Show the user:
Read and display the generated slide images so the user can see them inline.
Animated slides: When a slide contains an animated GIF, the script outputs both an .mp4 (full-color video for Instagram) and a .png (a static preview of the first frame). Always display the .png preview - never try to read the .mp4 file directly. Tell the user the MP4 version is saved alongside it for posting.
When writing threads for the user, follow these patterns from high-performing tweet-style carousels:
The hook makes or breaks the entire carousel. A bad hook means zero impressions; a great hook stops the scroll. The thread hook must work as a standalone tweet - if it wouldn't perform on its own, it won't perform as a carousel opener either.
Core principles:
Proven hook frameworks (master these first, then experiment):
Borrowed Authority - Open with a well-known person's name, then follow with a surprising claim or hot take. The name grabs attention; the claim holds it.
Surprising Statistic - Lead with a specific, hard-to-ignore number. Stats create instant credibility and curiosity.
Direct Listicle - State exactly what the list is about. No cleverness needed - the format itself stops the scroll. Listicles and how-tos are the two highest-performing written content formats on the internet.
High-TAM "Everyone" Hook - Cast the widest possible net, but ONLY if the content genuinely delivers for that audience. A bad "everyone" hook claims breadth but delivers niche content.
Numbers Up Front - Start the hook with a number. Specific numbers outperform vague claims.
Direct "You" Address - Point directly at the reader. Make them feel personally called out.
What kills a hook:
→ People stare at you
→ Kids like you
→ Animals feel safe around you
→ Strangers tell you their life story
→ You walk into a room and the energy shifts
Chess: manage their energy
Checkers: manage their time
Chess: optimize their psychology
Checkers: optimize their funnel
Each slide is 1080x1350px (Instagram 4:5 portrait).
Single tweet slide:
Two-tweet slide:
If the user doesn't have enough screenshots or reference images to fill out a carousel, generate them with Gemini. The script produces 16:9 landscape images designed to embed inside carousel slides below the tweet text. It has a built-in style guide that ensures dark, moody, cinematic results matching the carousel aesthetic.
python3 .claude/skills/instagram-thread-carousel/scripts/generate_carousel_image.py \
--prompt "description of the image you need" \
--output workspace/<date>/<title>/ref/generated-image.png
Options:
--reference path/to/screenshot.png - Pass existing images for context (e.g., a raw screenshot to stylize into a mockup)--headshot .claude/skills/instagram-thread-carousel/headshots/tyler-headshot.png - Include a person in the generated image--examples path/to/style-ref.png - Style inspiration imagesThen reference the generated image in the slide config:
{"text": "slide text here", "image": "workspace/<date>/<title>/ref/generated-image.png"}
--reference and prompt: "Render this UI screenshot on an elegant floating device mockup with dramatic dark lighting and subtle shadow"Requires GEMINI_API_KEY in .env.
Fonts look wrong: The script tries SF Pro → Helvetica → Arial → DejaVu Sans. If none are found, it falls back to Pillow's default. Install a clean sans-serif font for best results.
Text overflows the slide: Break long tweets into multiple shorter ones. The script wraps text automatically, but very long tweets with images may push content off the bottom.
Images look stretched: Images maintain their aspect ratio. Very tall images will take up a lot of slide space - crop them to landscape or square before using.
Profile pic not found: Check the path in the config. Headshots should be in .claude/skills/instagram-thread-carousel/headshots/. The script draws a gray circle as a placeholder if no headshot is found.
Animated slides look wrong or crash the session: The script outputs .mp4 (via ffmpeg) for animated slides instead of GIF, preserving full color. A .png preview is also saved for chat display. If ffmpeg is not installed, it falls back to GIF (which has color limitations). Install ffmpeg with brew install ffmpeg.
Emoji rendering: The script uses pilmoji with AppleEmojiSource for native Apple emoji rendering. If pilmoji is not installed (pip3 install pilmoji), emoji will render as blank squares. The emoji vertical alignment is corrected with emoji_position_offset=(0, -6) in the script.
When a slide has both text AND an embedded image, the text must be short enough that the image isn't cut off or shrunk too small. Follow these rules:
Slides with images should have SHORT text:
When the user provides their own images:
Splitting content for image slides: Instead of cramming a long explanation + image onto one slide, do this:
This keeps image slides clean and readable at carousel-swiping speed.
development
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
testing
Full QA pass: run all tests, check types, catch regressions, write missing tests. Use when the user says "run tests", "QA", "verify changes", "check for regressions", "test everything", or "make sure it works".
development
Provides guidance for property-based testing across multiple languages and smart contracts. Use when writing tests, reviewing code with serialization/validation/parsing patterns, designing features, or when property-based testing would provide stronger coverage than example-based tests.
development
Initialize a new project with Kenny's universal conventions and stack-appropriate infrastructure. Use this skill whenever: setting up a new project, creating a new repo, scaffolding a new app, starting fresh on a new idea, 'init project', 'new project', 'set up a new app', 'create a project for X', or any variant of starting a new codebase from scratch. Also trigger when the user says 'bootstrap', 'scaffold', or 'kickstart'. This skill ensures every project gets the same quality gates and conventions while adapting infrastructure to the chosen stack.