P PasteCode
Prompt

Prompt para Gerar Imagens OG no Momento da Build

Prompt para agente de IA gerar imagens Open Graph por página no momento da build em Astro ou Next.js usando Satori e sharp, sem serviço externo.

CursorClaude CodeCodexWindsurf AstroNext.jsTypeScript
.md .json Dificuldade: Médio Atualizado 8 de jun. de 2026

Entregue este prompt ao seu agente para gerar uma imagem PNG OG única para cada página no momento da build usando Satori e sharp — evitando a latência e o custo de serviços de imagem OG em tempo de execução como Vercel OG.

Prompt Principal

Main Prompt
You are working in an existing Astro 5 static site with TypeScript.
Task: generate a static Open Graph PNG image for every blog post at build time.
Requirements:
- Install `satori` and `sharp`.
- Create `src/lib/generate-og.ts` that exports `generateOgImage({ title, description }: OgData): Promise<Buffer>`.
- Use Satori to render a JSX template (800 x 420 px) with: site name top-left, post title
(large, bold, white), description (smaller, gray), a solid dark background (#0f172a).
- Convert the Satori SVG output to PNG using `sharp(Buffer.from(svg)).png().toBuffer()`.
- Use only system-safe fonts or load `src/fonts/Inter-Bold.ttf` (create a note to add the file).
- Create `src/pages/og/[slug].png.ts` as an Astro endpoint:
- `getStaticPaths`: call `getCollection('blog')` and return a path per post.
- `GET`: call `generateOgImage` with the post's title and description, set
`Content-Type: image/png`, return the buffer.
- In the blog post layout, set `<meta property="og:image" content={ogImageUrl} />` where
`ogImageUrl` is constructed as `/og/${post.slug}.png`.
- Do NOT use `@vercel/og`, `next/og`, or any cloud image generation service.
- Do NOT use Canvas or puppeteer.
Stop and list all planned file changes before writing any code.

Notas de Implementação

  • Satori aceita objetos semelhantes a JSX (sintaxe de elemento React), mas NÃO usa o runtime React. Passe o elemento como uma árvore de objeto simples usando o primeiro argumento do satori diretamente.
  • Carregamento de fontes: Satori requer pelo menos uma fonte. Use fs.readFileSync para carregar o arquivo .ttf no momento da build — isso é tranquilo em uma build estática do Astro.
  • Os PNGs gerados estarão na pasta dist/og/ após astro build. Verifique o tamanho; em 800x420 devem ficar abaixo de 100 KB cada se usando um fundo de cor sólida.
  • Para Next.js em vez de Astro: use um Route Handler em app/og/[slug]/route.ts e chame NextResponse com o buffer PNG.

Alterações Esperadas nos Arquivos

src/lib/generate-og.ts (new)
src/pages/og/[slug].png.ts (new — Astro endpoint)
src/layouts/BlogPost.astro (edited — add og:image meta)
src/fonts/Inter-Bold.ttf (add manually — not auto-generated)
package.json (edited — add satori, sharp)

Critérios de Aceitação

  • astro build gera um arquivo .png dentro de dist/og/ para cada post do blog.
  • Cada PNG tem 800 x 420 pixels.
  • O layout do post do blog inclui og:image apontando para o caminho correto /og/<slug>.png.
  • Abrir a URL da imagem OG em um navegador mostra um card estilizado com o título do post.

Comandos de Teste

Terminal window
bun add satori sharp
bun run build
ls dist/og/
file dist/og/my-first-post.png # should output "PNG image data, 800 x 420"
curl -I http://localhost:4321/og/my-first-post.png | grep content-type

Erros Comuns de IA

  • Importar React e tentar renderizar com ReactDOMServer — Satori não usa o runtime do React.
  • Esquecer de carregar uma fonte, o que faz o Satori lançar "No font found for the first character".
  • Definir og:image para um caminho relativo como ./og/slug.png — deve ser uma URL absoluta em produção.
  • Usar o pacote canvas que requer bindings nativos incompatíveis com muitos ambientes de CI.

Prompt de Correção

Fix Prompt
Satori throws a font error or the PNG is blank. Fix in order:
1. Add font loading: `const fontData = fs.readFileSync('src/fonts/Inter-Bold.ttf'); fonts: [{ name: 'Inter', data: fontData, weight: 700 }]` in the satori call.
2. Make sure the JSX-like element passed to satori is a plain object, not a JSX expression — call `satori(element, options)` directly.
3. For the og:image meta tag, use an absolute URL: `const base = import.meta.env.SITE; ogImageUrl = new URL(\`/og/\${slug}.png\`, base).toString();`
Show only the corrected diff.