diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d38f503..59cad0835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog +## [1.52.2.0] - 2026-05-29 + +## **Emoji render in make-pdf PDFs on every platform. Linux stops printing tofu boxes, and setup installs the font for you.** + +make-pdf used to render emoji code points as `.notdef` tofu (▯) on Linux. The cause was a missing fallback: the print CSS font stacks had no emoji family, and most Linux distros and containers ship no color-emoji font at all, so Skia drew empty boxes in every header and table that used emoji. Now the body and running-header stacks fall back through Apple Color Emoji, Segoe UI Emoji, and Noto Color Emoji, and `./setup` best-effort installs `fonts-noto-color-emoji` on Linux (apt, with dnf/pacman/apk fallbacks), refreshes the font cache, and restarts a running browser daemon so the next render picks it up. macOS and Windows already shipped an emoji font and are unchanged. Non-emoji Unicode (em dash, times, arrow, bullet, ellipsis) always worked and still does. + +## The numbers that matter + +Source: the emoji render gate, `bun test make-pdf/test/e2e/emoji-gate.test.ts`, rendering a fixture of color emoji at 100 dpi. + +| Metric | Before | After | Δ | +|---|---|---|---| +| Saturated (color) pixels in the rendered emoji region | ~0 (tofu) | ~1,650 | real color render | +| Platforms that render emoji correctly | macOS, Windows | macOS, Windows, Linux | +Linux | +| Emoji-bearing font stacks with a fallback family | 0 | 2 | body + running header | +| Deterministic render-proof gates | 0 | 1 | pdffonts + pixel | + +A tofu box is a near-monochrome outline (close to zero colored pixels). A real emoji render lands about 1,650 saturated pixels. The gate asserts both that an emoji font embedded (`pdffonts`) and that the page actually rasterizes to color (`pdftoppm`), because PDF text extraction passes even when the glyph drew as tofu, so it cannot be trusted as the proof. + +## What this means for builders + +If you generate PDFs on Linux or inside a container, emoji in section headers and table status columns now render instead of ▯. Run `./setup` once on Linux to install the font; there is nothing to do on macOS or Windows. Set `GSTACK_SKIP_FONTS=1` to opt out on locked-down or offline machines. + +### Itemized changes + +#### Added +- `ensure_emoji_font()` in `setup`: Linux color-emoji install across apt/dnf/pacman/apk, `fc-match` color-font detection (idempotent, skips when a real color font already resolves), `fc-cache` refresh under sudo, and a browse-daemon restart so a running render server sees the new font. Opt out with `GSTACK_SKIP_FONTS=1`. Non-interactive `sudo -n` and timeout-bound package calls so it never hangs setup. +- Emoji render gate (`make-pdf/test/e2e/emoji-gate.test.ts`) with a variation-selector (`❤️`, FE0F) fixture: asserts an emoji font embeds and the page rasterizes to color. Hard-fails in CI when poppler or the font is missing, so prerequisite drift can't hide a regression behind a green build. +- `resolvePopplerTool()` resolver for `pdffonts` / `pdfimages` / `pdftoppm`. +- The Ubuntu make-pdf CI gate installs `fonts-noto-color-emoji` before Chromium launches. + +#### Changed +- Print CSS body and `@top-center` running-header font stacks fall back through Apple Color Emoji, Segoe UI Emoji, and Noto Color Emoji, placed before the generic `sans-serif`. All font stacks are now composed from shared constants. + +#### Fixed +- make-pdf no longer renders emoji as `.notdef` tofu (▯) on Linux. + ## [1.52.0.0] - 2026-05-27 ## **`/plan-tune` settings actually do something now. Hooks make capture deterministic, preferences binding, and free-text answers loop back as memory.** diff --git a/VERSION b/VERSION index f339f27b1..d7f9d8f6c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.52.0.0 +1.52.2.0 diff --git a/package.json b/package.json index e69ab42fa..a08f31dc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.52.0.0", + "version": "1.52.2.0", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module",