# 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.

**Type:** Prompt  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** Astro, Next.js, TypeScript  
**Difficulty:** medium  
**Updated:** 2026-06-08

---

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

```txt title="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

```txt
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

```bash
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

```txt title="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.
```