diff --git a/CHANGELOG.md b/CHANGELOG.md index 8419635..08a01de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,272 @@ project follows [Semantic Versioning](https://semver.org/). ## [Unreleased] -No threads in flight. v0.20.0 cut on 2026-05-07; CHANGELOG accumulates +No threads in flight. v0.21.0 cut on 2026-05-08; CHANGELOG accumulates the next cycle here. +## [0.21.0] — 2026-05-08 + +Closes the visual-identity arc opened in v0.20.0. Three through-lines +landed: the **card-face / suit / card-back artwork migration** that +v0.20.0 deliberately deferred, the **splash boot-screen + replay- +overlay polish** that closes Resume-prompt Options B and C, and a +late-cycle **`ACCENT_PRIMARY` palette swap** from cyan `#6fc2ef` to +brick red `#a54242` after a quick stakeholder review on the +shipped art. + +The card-face arc is the largest piece by commit count (10 of the +25 post-tag commits) and shape: it ports both rendering paths +production traverses — the PNG fallback at `assets/cards/*.png` +and the bundled-default theme SVGs at +`solitaire_engine/assets/themes/default/*.svg` that +`include_bytes!()`-embed into the binary and override the PNGs at +runtime — to identical Terminal-aesthetic art generated by the +same `face_svg` / `back_svg` builders. A new +`card_face_svg_pin` integration test pins rasteriser output via +FNV-1a on raw RGBA bytes, so future `usvg`/`resvg` upgrades or +intentional builder edits surface as test failures rather than +silent visual drift. The pin test fired three times during the +arc (text→path glyph fix, glyph orientation tweak, palette swap) +and rebaselined cleanly each time via the empty-then-paste +bootstrap pattern baked into the test. + +Three sign-off follow-ups surfaced once a human booted the +running game and they all matched the same shape — "fallback +path the chrome migration walked past": the embedded default +theme overrode the new PNGs at runtime, the table backgrounds +were a separate PNG path that the v0.20.0 chrome migration +didn't touch, and the action-button row's `font_size: 16.0` +literal slipped through the typography migration audit. All +three are recorded under "Fixed" below. + +Phase 8 (sync) and the Phase Android runtime gaps (JNI bridges, +APK launch verification on device) remain open and roll forward. + +### Added + +- **Card-face SVG generator pipeline** (`5623368` plan doc, + `3a4bb63` PoC, `babe5cc` full generator, `48b28d2` pin test). + `solitaire_engine/examples/card_face_generator.rs` writes 52 + face PNGs + 5 back PNGs into `assets/cards/` and 53 theme SVGs + into `solitaire_engine/assets/themes/default/`, all from the + shared `face_svg` / `back_svg` builders in the new + `solitaire_engine::assets::card_face_svg` module. Run with + `cargo run --example card_face_generator --release`. The PoC + (`card_face_poc.rs`) stays alongside as historical record of + the per-card grain proof. Pin test `card_face_svg_pin` + guards rasterised output via inline FNV-1a so the arc has + test-time coverage of both intentional builder edits (rebase + via empty-then-paste) and unintentional dependency-upgrade + drift. +- **Background generator example** (in `8719f77`). + `solitaire_engine/examples/background_generator.rs` emits 5 + flat Terminal-palette play-surface PNGs at 120 × 168, the + same tile size the legacy felt textures used (the runtime + stretches to `window_size * 2.0` so source resolution is + immaterial). All 5 slots stay in the near-black family — + `#151515` canonical, `#0a0a0a` deeper, `#1a1a1a` elevated, + `#121820` cool tint, `#201812` warm tint. +- **Splash boot-screen port** (`cacb19c`). Full mockup-spec + splash: header, boot log, progress bar, palette swatches, + version footer, plus the `SplashFadable` scaffold that lets + any future overlay fade `N >> 3` elements via one marker + + one global lerp query (replaces the `Without, Without` + exclusion pattern that the legacy splash hit at three + siblings). +- **Splash trailing cursor pulse** (`29136d8`). Trailing + 6×12 px Node, sine-pulsed, multiplied with the global splash + fade — the "multiply, don't override" pattern that resolves + the original `cacb19c` skip-rationale. Closes Option B half 1 + from the SESSION_HANDOFF Resume prompt. +- **Splash tiled scanline overlay** (`a27cf5a`). Runtime- + generated 2×2 RGBA8 texture tiled via `NodeImageMode::Tiled`; + per-pixel alpha × tint alpha gives multiplicative fade + integration without new abstractions. Closes Option B + half 2. +- **Replay overlay scrub bar** (`c84d9f4`). 1px accent fill at + the bottom of the banner, mirroring `cursor / total`. Per- + frame updater + scrub-pct unit tests. +- **Replay overlay banner label port** (`6204db8`). The + "▌ replay" headline picks up the cursor-block treatment that + aligns it with the splash boot-screen idiom. +- **Replay overlay GAME caption** (`54005d5`). `GAME #YYYY-DDD` + game-identifier caption beneath the headline. Mirrors the + mockup's right-anchored ID but stays grouped with the headline + so the two pieces of "this is a replay of game X" read as one + unit. +- **Replay overlay MOVE chip** (`e080b49`). `MOVE N/M` progress + readout wrapped in a 1px accent-bordered chip — discrete + callout rather than free-floating text. Closes Option C from + the SESSION_HANDOFF Resume prompt (paired with `54005d5`). +- **Terminal desktop-adaptation spec** (`39b8496`). + `docs/ui-mockups/desktop-adaptation.md` — the rules-based + companion to the 24-mockup library. Closes the spec gap + exposed when 23 of 24 mockups turned out to be mobile-only; + any future plugin port should read this first and apply the + universal rules before consulting the per-screen table. +- **`solitaire_engine::assets::card_face_svg` module** + (`48b28d2`). Public SVG builders (`face_svg`, `back_svg`, + `suit_path_d`) extracted from the example so the pin test + could call them — examples can't be referenced from + `tests/`. The generator and the test now share the same + source-of-truth, so the pin guards both rendering paths + the engine consults. + +### Changed + +- **`ACCENT_PRIMARY` swapped from cyan `#6fc2ef` to brick red + `#a54242`** (`a292a7e`). Project-wide palette decision after + initial rollout. Affects every cyan-accented surface — splash + boot screen, home menu glyphs, action chevrons, replay + overlay banner + scrub fill + chip border, achievement + checkmarks, leaderboard #1 indicator, radial menu fill, focus + ring, card-back canonical badge. `RED_SUIT_COLOUR_CBM` + swapped in lockstep from cyan to lime `#acc267` so the + colour-blind alternative stays hue-distinct from the new + red-family primary. Comment doc strings throughout the + engine retuned from "cyan" to "accent" / "primary-accent" so + future palette changes don't require comment churn. Spec doc + `design-system.md` updated in lockstep with historical + references preserved as audit trail. +- **Card-face / suit / card-back constants migrated to Terminal + palette in lockstep with new artwork** (`e8bf9d7`). Five + constants flipped: `CARD_FACE_COLOUR` → `#1a1a1a` (was + off-white `#fafaf2`), `RED_SUIT_COLOUR` → `#fb9fb1` (was deep + red `#c71f26`), `BLACK_SUIT_COLOUR` → `#d0d0d0` (was near- + black `#141414`), `CARD_FACE_COLOUR_RED_CBM` renamed to + `RED_SUIT_COLOUR_CBM` and repurposed from a face-background + tint to a suit-glyph swap (the Terminal face is uniformly + `CARD_FACE_COLOUR` regardless of CBM; CBM only swaps red + suits to a hue-distinct alternative in the glyph itself). + `card_back_colour()` retuned to the 5 base16-eighties accent + colours matching `BACK_ACCENTS`. `face_colour()` deleted — + the function collapsed to a constant once the Terminal face + became uniform. `text_colour()` gained a `color_blind: bool` + parameter to surface the CBM swap on the constant-fallback + path (the production path bakes glyphs into the PNG, but + tests under `MinimalPlugins` still need the CBM-aware + fallback). Four `face_colour` CBM tests collapsed into two + `text_colour` CBM tests in the same commit. +- **Default-theme SVG art regenerated to Terminal aesthetic** + (`a14200a`). `solitaire_engine/assets/themes/default/*.svg` + — the bundled-default theme that + `include_bytes!()`-embeds into the binary — was still the + legacy vector-playing-cards art post-`e8bf9d7`. The PNG + migration alone didn't change what production rendered + because `apply_theme_to_card_image_set` overrides + `CardImageSet.faces[..]` at startup with the theme's + rasterised SVG handles. Both rendering paths now agree: + same `face_svg` / `back_svg` builders feed both paths, and + the pin test guards both. +- **Card glyphs render upright in both corners** (`dd101b3`). + The traditional 180° inverted-corner-indicator rotation on + the bottom-right glyph was dropped at user preference — + single-orientation digital play doesn't benefit from the + flipped-readback convention. Both glyphs now render in the + same upright orientation. `design-system.md` § Game Cards + line 220 updated in lockstep — the deviation from + traditional playing-card layout is documented in the spec, + not just the code. +- **Action-button row typography aligned to `TYPE_BODY`** + (`ae84dc1`). Was a hardcoded `font_size: 16.0` literal that + the v0.20.0 typography-migration audit walked past. Brings + it in line with the `TYPE_*` token system every other text + element in `hud_plugin` already routes through, and trims + ~12% off label widths so the action-button row no longer + collides with the left-anchored HUD column at portrait / + narrow window widths. Pairs with a horizontal-padding step- + down from `VAL_SPACE_3` to `VAL_SPACE_2`: ~96 px reclaimed + across the 6-button row. +- **Table backgrounds flattened to solid Terminal colours** + (`8719f77`). Replaces the legacy felt-texture PNGs at + `assets/backgrounds/bg_*.png` with 5 flat near-black + variants per design-system.md (Terminal play surface is + flat; no felt, no gradient). On-disk tile weight drops + from ~16 KB average to ~100 bytes per tile; runtime + appearance flips from green felt to flat `#151515`. + +### Fixed + +- **Card suit glyphs rendered as near-invisible "tofu" marks** + (`af414b6`). The bundled `FiraMono` in + `svg_loader::shared_fontdb` doesn't carry usable U+2660-2666 + glyphs at the requested size — usvg silently substituted a + default-size fallback regardless of `font-size="20"` / + `font-size="64"`. Switched suit-glyph rendering from `` + elements to inline SVG `` elements via a new + `suit_path_d` helper authoring each suit as a single closed + perimeter in a 32×32 logical box. Path-based rendering + bypasses the font system entirely — same bytes on every + machine, no fontdb dependency, no substitution risk. Same + path data renders correctly whether filled (♥ ♠) or outlined + (♦ ♣ — the always-on color-blind glyph differentiation). +- **Default-theme SVGs were overriding new PNG artwork at + runtime** (`a14200a`). The PNG migration in `e8bf9d7` looked + correct under `cargo test` (the constant-fallback path + matched) but a real `cargo run` showed legacy white cards + because `theme::plugin::apply_theme_to_card_image_set` + overlays the bundled-default theme's rasterised SVGs onto + `CardImageSet.faces[..]` at startup, and those SVGs were + still legacy. Fixed by regenerating both rendering paths + from the same `face_svg` / `back_svg` builders. The + migration plan flagged "Theme system — out of scope here"; + that was a planning miss documented in the SESSION_HANDOFF. +- **Top-bar HUD column collided with action-button row at + portrait window widths** (`ae84dc1`). Both nodes were + absolute-positioned siblings at `top: VAL_SPACE_2` without a + shared flex parent, so they could overlap horizontally when + the window narrowed past their combined natural widths. + Fixed via the typography + padding tightening described + under "Changed" — minimal-blast-radius fix; the structural + fix (shared `JustifyContent::SpaceBetween` parent) stays + open as a follow-up if narrower windows surface. +- **Table-surface fill was still legacy green felt despite + v0.20.0's chrome-migration claim** (`8719f77`). Commit + `651f406` retuned in-engine constants but the runtime path + loads from `assets/backgrounds/bg_0.png`, an on-disk PNG that + the migration didn't touch. Same shape as the default-theme + override above — token migration walked past a fallback + rendering path. Fixed by regenerating the 5 background PNGs. + +### Stats + +- **1184 passing tests / 0 failing** across the workspace + (net +8 from v0.20.0's 1176 baseline). New tests this cycle: + the scrub-bar pair (`scrub_pct_covers_state_corners`, + `overlay_scrub_fill_tracks_cursor`); the splash boot-screen + pair (`splash_renders_terminal_boot_screen_content`, + `fadables_start_transparent_and_reach_full_alpha`); the + splash-polish pair (`build_scanline_image_has_expected_2x2_rgba_bytes`, + `scanline_overlay_spawns_and_fades_with_splash`); the + card-face pin (one integration test in + `card_face_svg_pin.rs` that exercises 57 rasteriser outputs + through 57 hash comparisons in a single + `#[test]`-marked function); and the CBM consolidation that + rewrote four `face_colour` tests as two `text_colour` CBM + tests in the same commit (net 0 to count, clean rewrite). +- Zero clippy warnings under `cargo clippy --workspace + --all-targets -- -D warnings`. +- `cargo test --workspace` clean. + +### Documentation + +- `docs/ui-mockups/card-face-migration.md` (`5623368`) — the + multi-session lockstep migration plan that the card-face arc + followed step-by-step. Now reads as historical record of + closed work; lessons documented under "Process notes" in + SESSION_HANDOFF.md. +- `docs/ui-mockups/desktop-adaptation.md` (`39b8496`) — rules- + based companion to the 24-mockup library. Required reading + before any future plugin port. +- `docs/ui-mockups/design-system.md` updates: § Game Cards + line 220 (glyph orientation), CTA / suit-red-cb / Card-back + badge / Primary button / Bottom-bar active-icon palette + retunes for the cyan→red swap. Historical references + preserved as audit trail. +- Multiple `SESSION_HANDOFF.md` refreshes (`a65e5b8`, + `13ae160`, `44f5972`, `73ac67d`, `ef54cde`, `d109c32`) + recording Options B / C / D closures and process notes. + ## [0.20.0] — 2026-05-07 Two through-lines closed: a full **Android port** (build target,