Files
hoelee-blog/scripts/og-gen/README.md
T
hoelee a41448bb4a feat(og-gen): check in the v2 art pipeline and its batch renderer
The consultant-approved "one art, four targets" work existed only in the
working tree. Commit it so the 72-post rollout is reproducible from the repo
instead of from one session's scratch files.

- template-v2.html / v2.1 / v2.2: the iteration the consultant reviewed, plus
  the accepted frosted-bento layout (736x536 card, blueprint grid, full-width
  evidence bar, self-fitting headline script that reports "FIT <n>px").
- render_sample_suite{,_v2,_v3}.mjs + fit-title-probe.mjs: how the two sample
  posts were rendered for rounds 2-4 (kept for provenance).
- generate_prompts_catalog.py + prompts_catalog.json: the 72 per-post prompts
  and their visual metaphors, extracted from the posts themselves.
- render_from_art.mjs (new): the batch renderer. One zero-text base frame per
  post -> banner 1600x900 webp (+jpg fallback), social card 1200x630 (EN and
  zh-<slug>), thumbs 800x420 and 400x210. Cards are filled from frontmatter +
  art-meta.json; a missing evidence line or a headline that never settles is a
  hard failure, never a silently-degraded card.
- art-meta.json: the per-slug input contract. Two slugs wired; 70 still need
  base art (GPU) and a hand-written evidence line.
- README: documents the pipeline, the measured format choice (558 KB PNG ->
  84 KB mozjpeg q85) and the PostList thumb-helper trap when ogImage moves to
  .jpg.

Proof the renderer reproduces the accepted output: re-rendering the two sample
posts yields banner + 800px thumb files BYTE-IDENTICAL to the consultant's
delivery (sha256 16e6a7b0, f3b29f38, c4e28291, 8095ec6c), and all four cards
report FIT, 2-3 title lines, 2 description lines, 0 overflow in x and y.
2026-10-18 16:32:58 +08:00

87 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <post-slug>
```
Reads frontmatter (`title`, `category`, `tags`) from
`src/content/posts/<slug>.md`, fills `template.html`, renders with headless
Chrome, and writes `public/og/<slug>.png`.
The post's frontmatter needs `ogImage: /og/<slug>.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
<div class="line"><span class="prompt">$</span><span class="cmd">command</span></div>
<div class="line"><span class="prompt">&nbsp;</span><span class="err">error line</span></div>
<div class="line"><span class="prompt">$</span><span class="cmd">fix</span><span class="fix">→ done ✓</span></div>
```
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/<slug>.webp` (+ `.jpg` fallback from frontmatter) | 1600×900 |
| social card | `public/og/<slug>.jpg` (EN), `public/og/zh-<slug>.jpg` (ZH) | 1200×630 |
| bento/list thumb | `public/og/thumb/<slug>-800.webp` | 800×420 |
| small thumb | `public/og/thumb/<slug>-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 <n>px` through `<title>`, 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.