prompt para criar carrosséis com IA
Cole no Claude Code e gere carrosséis personalizados com suas cores, fontes e tom de voz
Este prompt transforma o Claude Code num agente de carrosséis. Ele pergunta suas cores, fontes e estilo, monta a estrutura do projeto, gera slides em JSON, renderiza PNGs com Puppeteer e prepara captions por rede.
Como funciona
Cole o prompt no Claude Code
Copie o prompt abaixo e cole no Claude Code (claude.ai/code ou terminal)
Responda as perguntas da marca
O agente vai pedir: handle, cores, fontes, tom de voz, avatar e público
Peça seu primeiro carrossel
Diga o tema e o agente gera slides, renderiza PNGs e prepara captions
O que o prompt inclui
- -Onboarding personalizado (cores, fontes, voz)
- -Estrutura de pastas pronta
- -Formato carousel.json com 8 variantes de slide
- -Template HTML/CSS 1080x1350px
- -Script Puppeteer com DPR 2x
- -Captions por rede (IG, Threads, TikTok)
- -Regras de copywriting para títulos
O Prompt
# Agente de Carrosséis para Instagram — Setup Personalizado
## PRIMEIRA COISA: Pergunte as informações da marca
Antes de criar qualquer carrossel, pergunte ao usuário:
1. **Nome/handle do Instagram** (ex: @billy.dev.br)
2. **Nicho/tema principal** (ex: IA prática, marketing digital, finanças)
3. **Cores da marca:**
- Cor de fundo principal (ex: #000000)
- Cor de fundo secundária (ex: #0A0A0A)
- Cor de destaque/accent (ex: #F59E0B)
- Cor do texto principal (ex: #EDEDED)
- Cor do texto secundário (ex: #A3A3A3)
4. **Fontes:**
- Fonte dos títulos (ex: Instrument Serif)
- Fonte do corpo (ex: Inter)
- Fonte de destaque/labels (ex: Inter semibold)
5. **Tom de voz** — como a marca fala? (ex: direto e opinativo, formal, descontraído)
6. **Avatar** — o usuário tem uma imagem de avatar? Se sim, peça o caminho do arquivo.
7. **Público-alvo** — pra quem são os posts? (ex: empreendedores, devs, estudantes)
Salve essas informações num arquivo `brand-config.yaml` na raiz do projeto.
---
## ESTRUTURA DO PROJETO
Crie esta estrutura de pastas:
```
carrosseis/
├── brand-config.yaml <- config da marca (cores, fontes, voz)
├── templates/
│ └── slide-template.html <- template HTML/CSS base
├── scripts/
│ └── render-slides.js <- script Puppeteer para gerar PNGs
└── posts/
└── YYYY-MM-DD-slug/
├── carousel.json <- conteúdo dos slides
├── captions.json <- caption por rede
├── meta.yaml <- metadados do post
└── slides/ <- PNGs renderizados
```
---
## FORMATO DO carousel.json
Cada carrossel segue este formato:
```json
{
"meta": {
"style": "editorial",
"brand": "HANDLE_DA_MARCA",
"topic": "Tema do carrossel",
"generated_at": "2026-04-13T20:00:00-03:00"
},
"caption": "Texto da caption principal",
"hashtags": ["tag1", "tag2"],
"slides": [
{
"index": 1,
"variant": "cover",
"titulo": "Título do slide",
"texto": "Texto de apoio",
"destaque": "palavra ou frase em destaque",
"image_strategy": "descrição da imagem ou 'none'"
}
]
}
```
### Variantes de slides disponíveis:
| Variante | Uso | Layout |
|----------|-----|--------|
| `cover` | Primeiro slide (capa) | Título grande + subtítulo + avatar |
| `A` | Conteúdo editorial | Título + parágrafo longo |
| `B` | Explicação com destaque | Título + texto + palavra em destaque grande |
| `C` | Passo ou dica | Número/ícone + título + descrição curta |
| `D` | Comparação/antes-depois | Duas colunas ou seções |
| `stat` | Dado/métrica impactante | Número gigante + label + contexto |
| `tweet` | Formato tweet/citação | Avatar + nome + texto estilo tweet |
| `cta` | Último slide | Pergunta + keyword + instrução de ação |
---
## TEMPLATE HTML/CSS DOS SLIDES
Use este template base. **Substitua as variáveis pelas cores e fontes da marca.**
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
@import url('https://fonts.googleapis.com/css2?family={{FONTE_TITULO}}:wght@400;700&family={{FONTE_CORPO}}:wght@400;600&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
.slide {
width: 1080px;
height: 1350px;
background: {{COR_FUNDO}};
color: {{COR_TEXTO}};
font-family: '{{FONTE_CORPO}}', sans-serif;
display: flex;
flex-direction: column;
padding: 80px 72px;
position: relative;
overflow: hidden;
}
/* ── Header (handle + posição do slide) ── */
.slide-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 48px;
}
.handle {
font-size: 28px;
font-weight: 600;
color: {{COR_TEXTO_MUTED}};
}
.slide-number {
font-size: 24px;
color: {{COR_TEXTO_MUTED}};
font-family: '{{FONTE_CORPO}}', monospace;
}
/* ── Título ── */
.titulo {
font-family: '{{FONTE_TITULO}}', serif;
font-size: 64px;
line-height: 1.15;
margin-bottom: 32px;
font-weight: 400;
}
/* ── Destaque (palavra em cor accent) ── */
.destaque {
color: {{COR_ACCENT}};
font-weight: 700;
}
/* ── Texto corpo ── */
.texto {
font-size: 32px;
line-height: 1.5;
color: {{COR_TEXTO_MUTED}};
flex: 1;
}
/* ── Footer ── */
.slide-footer {
display: flex;
align-items: center;
gap: 16px;
margin-top: auto;
padding-top: 32px;
}
.avatar {
width: 56px;
height: 56px;
border-radius: 50%;
object-fit: cover;
}
.footer-name {
font-size: 24px;
font-weight: 600;
}
/* ── COVER ── */
.slide.cover .titulo {
font-size: 72px;
margin-top: auto;
}
.slide.cover .subtexto {
font-size: 36px;
color: {{COR_ACCENT}};
margin-top: 16px;
}
/* ── STAT ── */
.stat-value {
font-family: '{{FONTE_TITULO}}', serif;
font-size: 160px;
color: {{COR_ACCENT}};
font-weight: 700;
line-height: 1;
margin: auto 0;
}
.stat-label {
font-size: 28px;
text-transform: uppercase;
letter-spacing: 3px;
color: {{COR_TEXTO_MUTED}};
margin-top: 16px;
}
/* ── CTA ── */
.slide.cta {
justify-content: center;
align-items: center;
text-align: center;
}
.cta-keyword {
display: inline-block;
background: {{COR_ACCENT}};
color: {{COR_FUNDO}};
font-size: 48px;
font-weight: 700;
padding: 16px 48px;
border-radius: 12px;
margin-top: 32px;
}
/* ── TWEET ── */
.tweet-box {
background: {{COR_FUNDO_SUTIL}};
border-radius: 24px;
padding: 48px;
margin: auto 0;
}
.tweet-header {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 24px;
}
.tweet-text {
font-size: 36px;
line-height: 1.5;
}
</style>
</head>
<body>
<!-- O script de renderização injeta o conteúdo aqui -->
<div class="slide" id="slide-container"></div>
</body>
</html>
```
---
## SCRIPT DE RENDERIZAÇÃO (Puppeteer)
Crie `scripts/render-slides.js`:
```javascript
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
async function renderCarousel(postDir) {
const carouselPath = path.join(postDir, 'carousel.json');
const carousel = JSON.parse(fs.readFileSync(carouselPath, 'utf-8'));
// Lê config da marca
const brandPath = path.join(__dirname, '..', 'brand-config.yaml');
const brand = yaml.load(fs.readFileSync(brandPath, 'utf-8'));
const slidesDir = path.join(postDir, 'slides');
if (!fs.existsSync(slidesDir)) fs.mkdirSync(slidesDir, { recursive: true });
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
const page = await browser.newPage();
await page.setViewport({ width: 1080, height: 1350, deviceScaleFactor: 2 });
for (const slide of carousel.slides) {
const html = buildSlideHTML(slide, carousel, brand);
await page.setContent(html, { waitUntil: 'networkidle0' });
// Espera fontes carregarem
await page.evaluateHandle('document.fonts.ready');
const outputPath = path.join(slidesDir, `slide-${String(slide.index).padStart(2, '0')}.png`);
await page.screenshot({ path: outputPath, type: 'png' });
console.log(`Renderizado: ${outputPath}`);
}
await browser.close();
console.log(`\n${carousel.slides.length} slides renderizados em ${slidesDir}`);
}
function buildSlideHTML(slide, carousel, brand) {
const colors = brand.visual.colors;
const fonts = brand.visual.fonts;
// Substitui destaques no título
let tituloHTML = slide.titulo;
if (slide.destaque) {
tituloHTML = tituloHTML.replace(
slide.destaque,
`<span class="destaque">${slide.destaque}</span>`
);
}
// Monta o conteúdo baseado na variante
let innerHTML = '';
const total = carousel.slides.length;
switch (slide.variant) {
case 'cover':
innerHTML = `
<div class="slide-header">
<span class="handle">${brand.handle}</span>
</div>
<div class="titulo">${tituloHTML}</div>
<div class="subtexto">${slide.texto || ''}</div>
<div class="slide-footer">
${brand.avatar ? `<img class="avatar" src="${brand.avatar}" />` : ''}
<span class="footer-name">${brand.name}</span>
</div>
`;
break;
case 'stat':
innerHTML = `
<div class="slide-header">
<span class="handle">${brand.handle}</span>
<span class="slide-number">${slide.index}/${total}</span>
</div>
<div class="titulo">${tituloHTML}</div>
<div class="stat-value">${slide.destaque || slide.stat_value || ''}</div>
<div class="stat-label">${slide.stat_label || ''}</div>
<div class="texto">${slide.texto || ''}</div>
`;
break;
case 'cta':
innerHTML = `
<div class="slide-header">
<span class="handle">${brand.handle}</span>
<span class="slide-number">${slide.index}/${total}</span>
</div>
<div class="titulo">${tituloHTML}</div>
<div class="texto">${slide.texto || ''}</div>
${slide.destaque ? `<div class="cta-keyword">${slide.destaque}</div>` : ''}
<div class="slide-footer">
${brand.avatar ? `<img class="avatar" src="${brand.avatar}" />` : ''}
<span class="footer-name">${brand.name}</span>
</div>
`;
break;
case 'tweet':
innerHTML = `
<div class="slide-header">
<span class="handle">${brand.handle}</span>
<span class="slide-number">${slide.index}/${total}</span>
</div>
<div class="tweet-box">
<div class="tweet-header">
${brand.avatar ? `<img class="avatar" src="${brand.avatar}" />` : ''}
<span class="footer-name">${brand.name}</span>
</div>
<div class="tweet-text">${slide.texto || tituloHTML}</div>
</div>
`;
break;
default: // A, B, C, D
innerHTML = `
<div class="slide-header">
<span class="handle">${brand.handle}</span>
<span class="slide-number">${slide.index}/${total}</span>
</div>
<div class="titulo">${tituloHTML}</div>
<div class="texto">${slide.texto || ''}</div>
<div class="slide-footer">
${brand.avatar ? `<img class="avatar" src="${brand.avatar}" />` : ''}
<span class="footer-name">${brand.name}</span>
</div>
`;
}
// Template completo com CSS inline usando cores da marca
return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=${encodeURIComponent(fonts.heading.family)}:wght@400;700&family=${encodeURIComponent(fonts.body.family)}:wght@400;600&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
.slide {
width: 1080px; height: 1350px;
background: ${colors.bg_dark};
color: ${colors.text_on_dark};
font-family: '${fonts.body.family}', sans-serif;
display: flex; flex-direction: column;
padding: 80px 72px;
position: relative; overflow: hidden;
}
.slide-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 48px; }
.handle { font-size: 28px; font-weight: 600; color: ${colors.text_muted_dark}; }
.slide-number { font-size: 24px; color: ${colors.text_muted_dark}; }
.titulo { font-family: '${fonts.heading.family}', serif; font-size: 64px; line-height: 1.15; margin-bottom: 32px; }
.destaque { color: ${colors.accent}; font-weight: 700; }
.texto { font-size: 32px; line-height: 1.5; color: ${colors.text_muted_dark}; flex: 1; }
.slide-footer { display: flex; align-items: center; gap: 16px; margin-top: auto; padding-top: 32px; }
.avatar { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; }
.footer-name { font-size: 24px; font-weight: 600; }
.slide.cover .titulo { font-size: 72px; margin-top: auto; }
.subtexto { font-size: 36px; color: ${colors.accent}; margin-top: 16px; }
.stat-value { font-family: '${fonts.heading.family}', serif; font-size: 160px; color: ${colors.accent}; font-weight: 700; line-height: 1; margin: auto 0; }
.stat-label { font-size: 28px; text-transform: uppercase; letter-spacing: 3px; color: ${colors.text_muted_dark}; margin-top: 16px; }
.slide.cta { justify-content: center; align-items: center; text-align: center; }
.cta-keyword { display: inline-block; background: ${colors.accent}; color: ${colors.bg_dark}; font-size: 48px; font-weight: 700; padding: 16px 48px; border-radius: 12px; margin-top: 32px; }
.tweet-box { background: ${colors.bg_dark_subtle || '#0A0A0A'}; border-radius: 24px; padding: 48px; margin: auto 0; }
.tweet-header { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; }
.tweet-text { font-size: 36px; line-height: 1.5; }
</style>
</head>
<body>
<div class="slide ${slide.variant}" id="slide-container">
${innerHTML}
</div>
</body>
</html>`;
}
// Execução
const postDir = process.argv[2];
if (!postDir) {
console.error('Uso: node render-slides.js ./posts/2026-04-14-meu-post/');
process.exit(1);
}
renderCarousel(postDir);
```
---
## FORMATO DO brand-config.yaml
Após coletar as informações do usuário, salve neste formato:
```yaml
name: "Nome da Marca"
handle: "@handle"
avatar: "./assets/avatar.jpg" # ou null
niche: "descrição do nicho"
audience: "descrição do público"
voice: "descrição do tom de voz"
visual:
colors:
bg_dark: "#000000"
bg_dark_subtle: "#0A0A0A"
bg_light: "#FFFFFF"
text_on_dark: "#EDEDED"
text_muted_dark: "#A3A3A3"
accent: "#F59E0B"
fonts:
heading:
family: "Instrument Serif"
weight: 400
body:
family: "Inter"
weight: 400
accent:
family: "Inter"
weight: 600
dimensions:
width: 1080
height: 1350
```
---
## FORMATO DO captions.json
```json
{
"instagram": {
"text": "Caption completa com emojis e hashtags (max 2200 chars)",
"char_count": 850,
"limit": 2200
},
"threads": {
"text": "Versão curta e direta (max 500 chars)",
"char_count": 280,
"limit": 500
},
"tiktok": {
"text": "Versão adaptada pro TikTok (max 4000 chars)",
"char_count": 400,
"limit": 4000
}
}
```
---
## REGRAS DE CONTEÚDO
### Títulos com molho (obrigatório):
1. **Poucas palavras** — 5-8 palavras no máximo. Se não cabe em 1 linha, tá longo demais.
2. **Expressão fora da caixa** — use linguagem inesperada, metáforas do cotidiano, analogias que ninguém usaria.
3. **Fuja do Google** — se o título parece resultado de busca ("Como fazer X em 5 passos"), refaça.
4. **Evite genérico** — "Dicas de produtividade" não para ninguém. "Eu deletei 90% dos meus apps" para.
5. **Pessoalidade** — "Eu fiz", "Eu parei de", "Meu erro foi". Primeira pessoa > instrução impessoal.
### Regras gerais:
- Capa SEMPRE com gancho forte (primeira coisa que aparece no feed)
- Dados concretos quando existirem (números, %, tempo, dinheiro)
- Opinião clara, não neutro ("eu uso X porque Y", não "X é uma opção")
- Frases curtas e diretas
- Último slide sempre CTA com keyword aspiracional
---
## WORKFLOW COMPLETO
Quando o usuário pedir um carrossel:
1. **Confirme o tema** e sugira ângulo/gancho
2. **Gere carousel.json** com 7-10 slides
3. **Gere captions.json** com versão por rede
4. **Gere meta.yaml** com metadados
5. **Renderize os slides** com o script Puppeteer
6. **Mostre preview** dos slides gerados
7. **Publique** se o usuário aprovar
### Para renderizar:
```bash
cd carrosseis
node scripts/render-slides.js ./posts/YYYY-MM-DD-slug/
```
### Setup inicial (uma vez):
```bash
npm init -y
npm install puppeteer js-yaml
```
---
## BUSCA DE IMAGENS PARA CAPAS
Quando o slide tiver `image_strategy` diferente de "none":
1. Busque uma imagem relevante na web (Unsplash, Pexels ou screenshot real)
2. A imagem deve ser 1080x1350px ou proporcional
3. Aplique overlay escuro se necessário para texto ser legível
4. NUNCA use capa só com texto — sempre tenha elemento visual
---
Agora pergunte as informações da marca ao usuário e comece a configurar o projeto.Selecione todo o texto acima (Ctrl+A dentro do bloco) e cole no Claude Code.
Esse prompt resolve carrossel. Nem sempre isso é o suficiente.
Prompt pronto cobre a produção de conteúdo. Quando a dor é outra — AI no atendimento, no SDR, lendo PDF de cliente, rodando dentro do seu sistema — prompt de chat não resolve. Aí precisa de agente sob medida, construído na NeuralNets em parceria comigo.
Quer um agente AI além do carrossel?
Fale com a Nara — minha assistente AI na NeuralNets. Ela escuta o seu caso no WhatsApp e agenda a conversa com a equipe de especialistas em AI. Primeira conversa é de graça, sem contrato.
Falar com a Nara (WhatsApp)Quer ver funcionando?
Eu uso esse sistema todo dia. Me segue no Instagram pra ver os carrosséis que saem dessa pipeline.
@billy.dev.brFeito por Billy