# og-gen — per-post OG image generator Generates a branded 1200×630 social-share image for a blog post, matching the site's cobalt-blue `#295cff` branding, the `logo-square.png` mark, and the "terminal / debugging" visual style. ## Usage ```bash node scripts/og-gen/generate.mjs ``` Reads frontmatter (`title`, `category`, `tags`) from `src/content/posts/.md`, fills `template.html`, renders with headless Chrome, and writes `public/og/.png`. The post's frontmatter needs `ogImage: /og/.png` so the blog serves it (layout already renders `og:image` + width/height; PostList shows it as a card thumbnail). ## Customizing the terminal box Each post shows a "terminal" panel (the red error / green fix lines). Add an entry keyed by slug in `TERMINALS` inside `generate.mjs`, using these tokens: ```html
$command
 error line
$fix→ done ✓
``` No entry → a generic default terminal. ## Requirements - Google Chrome at `C:\Program Files\Google\Chrome\Application\chrome.exe` (override with `CHROME_PATH` env var). - Node 20+. ## Notes - PNG (not JPG) is intentional: for flat UI/terminal art, PNG is smaller and sharper than JPG (see commit history). - The `logo-square.png` referenced lives at `public/logo-square.png`. --- ## v2 pipeline ("one art, four targets") — `render_from_art.mjs` The consultant-approved redesign replaces the generated terminal panels with **one zero-text base-art frame per post**, composited into four assets: | Target | Path | Size | |---|---|---| | hero banner | `public/banners/.webp` (+ `.jpg` fallback from frontmatter) | 1600×900 | | social card | `public/og/.jpg` (EN), `public/og/zh-.jpg` (ZH) | 1200×630 | | bento/list thumb | `public/og/thumb/-800.webp` | 800×420 | | small thumb | `public/og/thumb/-400.webp` | 400×210 | The card is `template-v2.2.html` (frosted bento + blueprint grid + full-width evidence bar) filled from the post's own frontmatter plus `art-meta.json`; the self-fitting headline script reports `FIT px` through ``, and a render that does not settle fails instead of shipping a silently-shrunken card. ```bash # metadata first: art path (default <art-dir>/<slug>.png) + a HAND-WRITTEN evidence line $EDITOR scripts/og-gen/art-meta.json node scripts/og-gen/render_from_art.mjs --only <slug>[,<slug>] --out /tmp/og-check node scripts/og-gen/render_from_art.mjs --all # writes into public/ ``` - `--format jpg` (default) or `png`. **JPEG is the default because it is measured**: a composited card renders 558 KB as PNG and lands at **84 KB at mozjpeg q85** (256-colour PNG = 240 KB). The default site card already ships as JPG for the same reason. - `evidence` is **required and never derived** — it is editorial text, and inventing one from the description is the "invented specificity" failure the blog avoids. A missing entry aborts with the slug list. - `ogTitle_en` / `ogTitle_zh` shorten only the card's headline (the article keeps its real title) — the consultant's answer to the English headline-rag problem. - Reproducibility check: re-rendering the two sample posts produced banners and 800px thumbs **byte-identical** to the consultant's accepted delivery (sha256 16e6a7b0…, f3b29f38…, c4e28291…, 8095ec6c…). - ⚠ Changing `ogImage` from `.png` to `.jpg` also needs `PostList.astro`'s thumb helper updated (`/\.(png|jpe?g)$/`), or the listing derives `…-800.webp` from `slug.jpg` and every thumb 404s.