P PasteCode
Indicación

Prompt para generar imágenes OG en tiempo de compilación

Prompt de agente de IA para generar imágenes Open Graph por página en tiempo de compilación en Astro o Next.js usando Satori y sharp, sin servicio externo.

CursorClaude CodeCodexWindsurf AstroNext.jsTypeScript
.md .json Dificultad: Medio Actualizado 8 jun 2026

Dale este prompt a tu agente para generar una imagen PNG OG única para cada página en tiempo de compilación usando Satori y sharp — evitando la latencia y el costo de los servicios de imágenes OG en tiempo de ejecución 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 implementación

  • Satori acepta objetos similares a JSX (sintaxis de elementos React), pero NO utiliza el runtime de React. Pasa el elemento como un árbol de objetos plano usando directamente el primer argumento de satori.
  • Carga de fuentes: Satori requiere al menos una fuente. Usa fs.readFileSync para cargar el archivo .ttf en tiempo de compilación — esto está bien en una compilación estática de Astro.
  • Los PNG generados estarán en la carpeta dist/og/ después de astro build. Revisa su tamaño; a 800x420 deberían tener menos de 100 KB cada uno si usas un fondo de color plano.
  • Para Next.js en lugar de Astro: usa un Route Handler en app/og/[slug]/route.ts y llama a NextResponse con el buffer PNG.

Cambios esperados en archivos

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)

Criterios de aceptación

  • astro build genera un archivo .png en dist/og/ para cada entrada del blog.
  • Cada PNG tiene 800 x 420 píxeles.
  • El layout de la entrada del blog incluye og:image apuntando a la ruta correcta /og/<slug>.png.
  • Abrir la URL de la imagen OG en un navegador muestra una tarjeta estilizada con el título del artículo.

Comandos de prueba

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

Errores comunes de IA

  • Importar React e intentar renderizar con ReactDOMServer — Satori no usa el runtime de React.
  • Olvidar cargar una fuente, lo que provoca que Satori lance "No font found for the first character".
  • Establecer og:image en una ruta relativa como ./og/slug.png — debe ser una URL absoluta en producción.
  • Usar el paquete canvas que require enlaces nativos incompatibles con muchos entornos CI.

Prompt de corrección

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.