mcpField
T
threads-carousel

threads-carousel

github.com/itchernetskiMarketing & growth11885 installsUpdated 27w ago
Repository

About threads-carousel

threads-carousel is a skill that turns text into visual slides for social carousels or presentations. It offers platform-specific size presets, 12 slide types, and styles composed from independent font, surface, accent, and purpose choices.

Key features

  1. 01Turn text into carousel slides
  2. 02Use presets for multiple platform formats
  3. 03Choose from 12 slide types
  4. 04Combine font, surface, and accent styles
  5. 05Export individual PNGs or a PDF

Use cases

  1. 01Convert a post into a social carousel
  2. 02Create vertical slides for TikTok or Stories
  3. 03Arrange content as a widescreen presentation
  4. 04Export shareable PNGs or a PDF

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/itchernetski/threads-carousel-claude-skill --skill threads-carousel

After installing, type/threads-carouselin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

LICENSE
README.md
.gitignore
template/
bun.lock
package.json
next.config.ts
postcss.config.mjs
next-env.d.ts
tsconfig.json
template/public/
.gitkeep
template/src/
slides.ts
template/src/app/
CarouselApp.tsx
page.tsx
layout.tsx
globals.css
template/src/lib/
presets.ts
types.ts

Details

From the project README

Threads Carousel Generator

Converts a text post into a set of visual carousel slides for Threads, Instagram, LinkedIn, TikTok, Stories, YouTube, or a standalone presentation deck. Composable design system with three independent style axes (font × color × purpose) and 12 slide types.

Invocation

/threads-carousel <post text>
/threads-carousel path/to/post.md

Format presets (choose target platform)

PresetSizePlatforms
threads-4x5 (default)1080×1350Threads, Instagram feed (portrait)
instagram-square1080×1080Instagram, Facebook, LinkedIn feed
linkedin-square1080×1080LinkedIn document post (PDF)
tiktok-9x161080×1920TikTok Photo Mode, Reels, Shorts
story-9x161080×1920Instagram Stories, Threads Stories
wide-16x91920×1080Presentations, YouTube, desktop decks

Slide types (12)

TypePurposeRequired fields
hookOpening slide — the catchiest linetext
bodyTitle + paragraphtitle, text
body (points)Pros/cons list with ✓/✗ SVG iconstitle, points[] (instead of text)
listNumbered items (ordered list)title, items[]
statsBig numbers with labelstitle, stats[]
quoteLarge pulled quotetext, author
checklistCheckmark bulletstitle, items[]
processNumbered steps with connector linetitle, steps[]
comparisonTwo-column VS / before-afterleftLabel, leftItems[], rightLabel, rightItems[]
ctaFinal call to actiontext, handle
imageTitle + screenshot/photo + optional captionimageSrc, optional title, imageCaption
emojiGiant emoji illustration + title + textemoji, optional title, text
numberHuge hero number/string + title + textbigNumber, optional title, text

points shape: Array<{ type: "plus" | "minus"; text: string }> — green ✓ for plus, muted ✗ for minus. Adaptive sizing (44–62px) based on item count and longest line.

All types also support optional:

  • badge — small outlined tag above title (e.g. "01", "TIP")
  • highlight — a word or phrase within text/title that will be colored in the preset's highlight color (yellow for dark themes)
  • highlightStyle: "italic-box" — renders the highlighted word in Playfair italic on a colored rectangle (instead of plain color)
Images in slides

image slides expect imageSrc as a path served by Next.js under /public/. Workflow when a user gives you a local file:

  1. User drops a file path like /Users/me/Desktop/screenshot.png (or passes a file via the chat).
  2. Copy it into template/public/images/ with a safe, lowercase filename — e.g. cp "$USER_PATH" template/public/images/screenshot.png.
  3. In slides.ts reference it as imageSrc: "/images/screenshot.png" (absolute from /public/).

Same-origin serving avoids CORS errors in the PNG export pipeline. Do not use external URLs — html-to-image will often blank them out.

Background decorations (8 types)

Switchable via toolbar in preview. Default: glow.

TypeWhat it is
noneSolid background
blobsOrganic colored shapes
gridDotted grid pattern
linesDiagonal line pattern
paperRuled notebook lines + left margin (use with paper/light/white colors for a literary feel)
noiseSVG grain overlay (overlay blend)
bignumberGiant slide index as watermark (01, 02…)
glow (default)Soft radial gradient in alternating corners

Style system (3 independent axes)

The final style is composed at runtime from three axes via composePreset(font, color, purpose):

Font axis (DEFAULT_FONT), 5 typefaces:

IdFontFeel
minimal (default)Unbounded (body + hook)Geometric display, bold, distinctive
editorialPlayfair DisplayClassic serif, literary
cleanInterNeutral sans-serif, most standard
monoJetBrains MonoMonospace, tech/dev feel
condensedOswaldNarrow + tall, editorial poster

Surface axis (DEFAULT_SURFACE) — bg + text neutrals, 8 options:

IdBgTextFeel
dark (default)#0A0A0Awhitedefault bold
whitepure #FFFFFFnear-blacksharp clinical, Apple-style
lightcool zinc #F4F4F5near-blackneutral cool grey, Vercel-style
papercream #ECE2C8warm brownnotebook / literary warm
gradientpurple→pink→amberwhitebright gradient
pastellilac #EDE9FEindigosoft
neondark gradientlight cyantech dark
emberblack→red radialnear-whitedramatic

Accent axis (DEFAULT_ACCENT) — pop color for highlighted words, 8 options:

IdHexMatches surfaces
yellow (default)#FACC15dark, ember
red#DC2626pure red — white, light, paper
teal#14B8A6versatile — dark, white, light, paper
coral#FB7185pink-family — paper, light, white
orange#F97316pumpkin — paper, light, dark
violet#A78BFAdark, neon, ember
lime#D9F056ember, dark
blue#3B82F6white, light, paper, dark
fuchsia#C026D3pastel, white, dark
pink#EC4899pastel, dark, light
amber#F59E0Bgradient, dark, paper

Total combinations: 8 surfaces × 8 accents × 5 fonts × 2 purposes = 640 valid styles. Pick surface for neutral base, accent for pop color — independently.

Reference combos (inspired by design refs):

  • dark + teal — noir / minimalist tech
  • paper + orange — literary warm
  • ember + lime — dramatic announcement
  • white + coral — sharp editorial
  • light + teal — calm informational

Purpose axis (DEFAULT_PURPOSE):

IdTitleBodyDivider
carousel (default)44px, weight 800, UPPERCASEweight 600, textColor, line-height 1.2visible (96×4px accent)
presentation72px, weight 700, sentence caseweight 400, textSecondary, line-height 1.45hidden

Pick purpose: "presentation" + format: "wide-16x9" for a desktop / YouTube presentation deck. Any 3 × 8 × 2 = 48 combinations are valid.


Workflow

Step 1 — Get the text
  • If passed inline — use it.
  • If a file path (.md, .txt) — read it.
  • If text is long (>500 chars) — confirm it's complete before planning.
Step 2 — Clarify parameters (optional, can assume defaults)

Ask once, combined:

  1. Number of slides (3–10, default 6)
  2. Format (see table above, default threads-4x5; use wide-16x9 for a presentation deck)
  3. Purpose (carousel or presentation, default carousel)
  4. Font (minimal / editorial / clean, default minimal)
  5. Color (8 palettes, default dark)
  6. Handle for CTA slide (e.g. @username)

Shortcut: if user says "presentation" / "презентация" / "slide deck" → default to purpose: presentation, format: wide-16x9, font: clean, color: white.

If user says "your call" — apply defaults, do not block.

Step 3 — Plan the slide breakdown

Show the user a preview list before generation:

Slide 1 (hook): "Headline..."  [highlight: "word"]
Slide 2 (body): badge 01 — "Title" / "Text..."
Slide 3 (list): badge 02 — "iOS stack" / 3 items
Slide 4 (stats): badge 03 — "Growth" / 3 stats
Slide 5 (quote): "Quote..." — Author
Slide 6 (cta): "Final message" @username
Rules for splitting text into slides
  1. Hook = single most intriguing line from the post. 1–3 short lines. Works as a standalone thumbnail.
  2. Body slides = one idea each. Max 40 words. Max 5 lines. Never join two ideas with "and".
  3. Mix slide types for visual variety: prefer list for enumerations, stats for numbers, quote for direct speech, comparison for VS/before-after. Don't make every slide a body.
  4. CTA = conclusion + follow handle. Centered, short.
Step 4 — Generate
Prepare working copy
WORK_DIR="/tmp/carousel-$(date +%s)"
rsync -a --exclude=node_modules ~/.claude/skills/threads-carousel/template/ "$WORK_DIR/"
ln -s ~/.claude/skills/threads-carousel/template/node_modules "$WORK_DIR/node_modules"
cd "$WORK_DIR"

Symlinking node_modules avoids the 350MB copy per run.

Inject content into src/slides.ts

All content + defaults live in src/slides.ts — never touch the engine (src/app/CarouselApp.tsx, src/lib/*). Edit the SLIDES array and the 5 default constants.

Full injection example:

import type { SlideData, BgType, FormatId, FontId, ColorThemeId, PurposeId } from "./lib/types";

export const SLIDES: SlideData[] = [
  { type: "hook", text: "Line one\nline two", highlight: "two" },
  { type: "body", badge: "01", title: "Title", text: "Body text...", highlight: "key" },
  { type: "body", badge: "02", title: "Pros & Cons", points: [
    { type: "plus",  text: "One click to register" },
    { type: "plus",  text: "Works on any background" },
    { type: "minus", text: "Requires provider setup" },
  ]},
  { type: "list", badge: "03", title: "Steps", items: ["First", "Second", "Third"] },
  { type: "stats", title: "Numbers", stats: [
    { value: "10×", label: "Faster" },
    { value: "50%", label: "Smaller" },
  ]},
  { type: "quote", text: "Big idea\nin few words", author: "Someone", role: "2026" },
  { type: "checklist", title: "Pre-flight", items: ["One", "Two", "Three"] },
  { type: "cta", text: "Last word", handle: "@username" },
];

export const DEFAULT_FONT: FontId = "minimal";
export const DEFAULT_COLOR: ColorThemeId = "dark";
export const DEFAULT_PURPOSE: PurposeId = "carousel";
export const DEFAULT_BG: BgType = "glow";
export const DEFAULT_FORMAT: FormatId = "threads-4x5";
Launch preview and export
bun dev --port 3333

Tell the user to open http://localhost:3333. They can:

  • Switch Format / Mode / Font / Color / Background live via toolbar rows
  • Toggle UI language RU / EN in the top-right
  • Click PDF to download all slides in one file (JPEG-compressed, ~5–8 MB for 10 slides)
  • Click PNG (a.k.a. "Export All") to download every slide as 01-hook.png, 02-body.png, …
  • Click an individual slide thumbnail to export just that one as PNG

After export, stop the dev server.

Parallel carousels

If making multiple carousels at once: create multiple work dirs and launch on ports 3333, 3334, 3335 — they run side by side without conflict.


Design system

Canonical look (font: minimal, color: dark, purpose: carousel):

  • Display typeface: Unbounded (Google Fonts), for hooks — applied only when the font axis provides hookFontFamily
  • Body typeface: Space Grotesk (minimal) / Playfair (editorial) / Inter (clean) — everything else uses preset.fontFamily
  • Palette (dark): #0A0A0A bg, #FFFFFF text, #FACC15 highlight
  • Layout: 80px padding, left-aligned, slide counter bottom-center
  • Title discipline: carousel purpose — title → a 96×4px accent divider → body, with ≥64px breathing room above body. Presentation purpose — no divider, sentence case, 72px.
  • Hook size: 104–140px, adaptive by character/line count
  • Body text size: 48–88px, adaptive
  • Text balance: textWrap: "balance" on hook + title (no orphan words)
Typography table (carousel purpose)

The presentation purpose overrides titles to 72px / 700 / sentence case and body to 400 / textSecondary / line-height 1.45.

ElementSizeWeightFont source
Hook104–140px800hookFontFamily ?? fontFamily
Title44px800 uppercasefontFamily
Body48–88px600fontFamily
Points (pros/cons)44–62px600fontFamily
Badge26px800 uppercasefontFamily
Stats value140–170px900fontFamily
Stats label32px500 uppercasefontFamily
Quote62px600fontFamily
List item46px600fontFamily (numbers 48px)
Checklist item44px600fontFamily
Process step title36px700fontFamily
Handle36px500fontFamily

Common mistakes

MistakeFix
Too much text on a slideMax 40 words, max 5 lines
Two ideas on one slideSplit into two slides
All slides are body typeMix in list, stats, quote, checklist for visual variety
No hook on first slideSlide 1 must be the catchiest line
No CTA on last slideSlide N must end with a handle or call to action
Highlight word too longKeep highlight to 1–2 words, not whole phrase
Badge has too many charactersMax 2–4 characters (01, TIP, NEW)

Future work / TODOs

  • Satori server-side export — replace browser-based html-to-image with Satori + Resvg for CLI export (bun run export → out/*.png). Enables headless runs. See Slashgear/linkedin-carousel-gen for reference.
  • Per-slide background override — currently DEFAULT_BG is global; could accept a per-slide bg field to mix decorations across a deck.
  • Cyrillic-optimized adaptive sizing — current thresholds are calibrated for Latin; Russian copy tends to be 20–30% longer at the same font size.
  • Pencil MCP mode — previous skill version had a manual design mode via Pencil; not currently implemented in the template.

Comments

Markdown supported