P PasteCode
Prompt

Prompt pour générer des images OG au moment de la construction

Prompt d'agent IA pour générer des images Open Graph par page au moment de la construction dans Astro ou Next.js en utilisant Satori et sharp, sans service externe.

CursorClaude CodeCodexWindsurf AstroNext.jsTypeScript
.md .json Difficulté: Moyen Mis à jour 8 juin 2026

Donnez ce prompt à votre agent pour générer une image PNG OG unique pour chaque page au moment de la construction avec Satori et sharp — évitant ainsi la latence et le coût des services d’image OG en temps réel comme 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.

Notes d’implémentation

  • Satori accepte des objets de type JSX (syntaxe d’élément React), mais il n’utilise PAS le runtime React. Passez l’élément comme un arbre d’objets simple en utilisant directement le premier argument de satori.
  • Chargement de polices : Satori nécessite au moins une police. Utilisez fs.readFileSync pour charger le fichier .ttf au moment de la construction — c’est acceptable dans une construction statique Astro.
  • Les PNG générés se trouveront dans le dossier dist/og/ après astro build. Vérifiez leur taille ; à 800x420, ils devraient peser moins de 100 Ko chacun si vous utilisez un fond de couleur unie.
  • Pour Next.js au lieu d’Astro : utilisez un gestionnaire de route dans app/og/[slug]/route.ts et appelez NextResponse avec le tampon PNG.

Modifications de fichiers attendues

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ères d’acceptation

  • astro build génère un fichier .png sous dist/og/ pour chaque article de blog.
  • Chaque PNG fait 800 x 420 pixels.
  • La disposition de l’article de blog inclut og:image pointant vers le chemin correct /og/<slug>.png.
  • L’ouverture de l’URL de l’image OG dans un navigateur affiche une carte stylisée avec le titre de l’article.

Commandes de test

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

Erreurs courantes de l’IA

  • Importer React et essayer de rendre avec ReactDOMServer — Satori n’utilise pas le runtime React.
  • Oublier de charger une police, ce qui provoque l’erreur "No font found for the first character" de Satori.
  • Définir og:image avec un chemin relatif comme ./og/slug.png — il doit s’agir d’une URL absolue en production.
  • Utiliser le package canvas qui nécessite des liaisons natives incompatibles avec de nombreux environnements CI.

Prompt de correction

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.