findIndex(t > now) - 1 returned -1 before the first line started, which the
`if (i < 0) i = lines.length - 1` guard turned into the LAST line — so playback
began scrolled to the bottom. Use a last-passed-index scan instead (-1 = before
the first line), centre the active line inside the box (so upcoming lyrics are
visible), and scroll the box itself rather than scrollIntoView(), which dragged
the whole page. Also bumps the box to 250px. Fixes yue2 post + both Suno posts.
Every post now carries one unique local-ComfyUI/Ideogram 4 base frame, composited
into EN + ZH share cards, a banner and list thumbs.
- the shipped prompts_catalog held only 21 distinct metaphors for 72 posts (16
shared one visual), so all 72 were rewritten as unique object+state metaphors
and 10 frames re-rolled after OCR found pseudo-text rendered at legible size
- render_from_art.mjs emits JPEG by default (558 KB PNG -> 84 KB mozjpeg q85);
the ZH 1200x630 card did not exist before this batch
- 288 frontmatter fields migrated; the 144 v1 PNGs are gone
- PostList's thumb helper keys off the base slug (a ZH card is zh-<slug>.jpg while
the thumb is <slug>-800.webp, which 404'd the whole ZH listing)
- [...slug].astro's <picture> regex accepts .jpg
- the repo now carries the art inputs (metaphors.json, captions/<slug>.json,
refreshed prompts_catalog.json) so a frame is reproducible from git alone