Lossless Changelog
component

Rural Income gets its Play-UI — and a five-format export pipeline to go with it

The first Play-UI build for any reach-edu-hub deck: eleven static, presentation-ready slides for Rural Income Boosts through Apprenticeship Degrees, plus a script that turns them into a PDF, a PPTX, and a Google-Slides-ready deck on demand. Two real rendering bugs in the shell's /play surface got found and fixed along the way.

Michael StatonMusic Editoraugmented with Claude Code on Claude Sonnet 5

Rural Income's Play-UI, and the export pipeline behind it

Why Care?

A Scroll-UI deck is right for browsing on the site. It's the wrong shape for "open this in Google Slides and present it tomorrow." Rural Income — the first and most-audited of the seven strategy decks — is now the first to have both: eleven Play-UI slides, static and pinned to a real 16:9 canvas, and a script that turns them into whatever format the moment calls for.

What's New?

  • Rural Income's Play-UI is live — /play/rural-income/v1/{01..11}, recreated from the Scroll-UI source per the "recreate, don't extract" discipline, not a mechanical port. Sized up for a wide canvas rather than a scroll column — a literal port of scroll-proportioned spacing reads as sparse on 16:9, so type and card scale are meaningfully larger here.

  • Five export formats, one script — scripts/export-rural-income.mjs (+ a native-shapes companion) produces:

    • Retina PNGs, one per slide

    • An 11-page vector PDF

    • A self-contained HTML snapshot

    • A PPTX with one full-bleed image per slide (what actually opens cleanly in Google Slides today)

    • A PPTX with real, editable text boxes and shapes — same content, genuinely editable in Slides, at the cost of falling back to system fonts and flattening gradient headlines to a solid color

  • Two real shell bugs found and fixed, both root-caused rather than patched around:

    • The /play route's stage never scaled its content to fit — a fixed 1920×1080 slide would bleed off the page in any container that wasn't exactly that size. Fixed by wrapping every slide in the same "fixed design-space + transform: scale() via container-query units" technique the shell's own SlideCanvas uses elsewhere, applied directly since this particular route didn't provide it.

    • /play sets no default data-mode at all — a bare viewer would see black text on a transparent background until they manually toggled a mode. Fixed with explicit light-mode fallback values on every color/ font token this deck's styles reference, so "no mode set" now renders as light mode instead of unstyled.

How it Works

The scale-to-fit fix, concretely: .play-canvas is a responsive outer box that fills whatever the shell's .ddd-frame__stage hands it and paints the page background across the whole thing (so no dark shell default peeks through in the gaps). .play-section is the fixed 1920×1080 design stage inside it, scaled down — never up — via transform: scale(min(100cqw/1920px, 100cqh/1080px)). Verified by shrinking the browser viewport to 960×720 (a different aspect ratio entirely) and confirming the slide scaled proportionally with no bleed, rather than just trusting the CSS on paper.

The export script leans on the shell's existing /play/{deck}/{variant}/print route for the PDF and HTML exports — it already lays out all eleven slides with page-break-after CSS, so page.pdf() and page.content() just work against it. The image-based PPTX reuses the same PNGs the images export produces; the native-shapes PPTX is hand-mapped from the eleven source files rather than scraped from the DOM, which was faster and more reliable than building a generic converter for an 11-slide one-off.

What's Next

The other six strategy decks don't have Play-UI yet — same recipe applies per deck, rated and scaffolded through /toc/{deck} first. exports/ is gitignored (matching the calmstorm-decks convention); regenerate via node scripts/run-export-rural-income.mjs against a running pnpm dev.