From 41a009a693bfa99ea07c26e42a9d467b54b1da57 Mon Sep 17 00:00:00 2001 From: funman300 Date: Thu, 7 May 2026 18:58:51 -0700 Subject: [PATCH] =?UTF-8?q?docs:=20cut=20v0.20.0=20=E2=80=94=20Terminal=20?= =?UTF-8?q?design=20system=20+=20Android=20persistence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promotes the [Unreleased] section to [0.20.0] dated 2026-05-07 and opens a fresh empty [Unreleased]. The cycle's two through- lines: - **Terminal visual-identity port.** ui_theme token system (0d477ac) is load-bearing; downstream chrome migrations cover the modal scaffold, gameplay-feedback layer (ceec4fc), toasts with a new ToastVariant enum (a137607), table chrome (651f406), card chrome (d752870), splash cursor (cdcadda), and final hint-source / dest pairing (9891ae4). Card-face / suit / card- back palette intentionally NOT migrated — those track PNG artwork that hasn't been regenerated yet. The 24 Stitch-rendered mockups and design-system.md spec landed in fa7f98a. - **Android persistence shim.** solitaire_data::data_dir routes through a per-platform shim (4b51e50) closing the CLAUDE.md §10 dirs::data_dir() = None pitfall on Android. Settings, stats, achievements, replays, game-state, time-attack sessions, and user themes now persist on a real APK. Also closes three v0.19.0 punch-list candidates that landed earlier in the cycle (pull_failure flake at 67c150b, smart-window- size opt-out at e1b8766, Shareable badge at 9b065e5). Tests: 1176 passing / 0 failing (six new this cycle: ui_theme invariant guards, toast-variant-border-mapping, palette-tracking guards on MARKER_VALID / HINT_PILE_HIGHLIGHT_COLOUR / RIGHT_CLICK_HIGHLIGHT_COLOUR / toast-border distinctness). SESSION_HANDOFF.md refreshed: HEAD pointer, test count, the v0.20.0 changelog summary, the open punch list (Phase Android runtime gaps, visual-identity follow-ups including the artwork regeneration item), the updated design-direction box (was Midnight Purple + Balatro yellow; now base16-eighties Terminal), and a refreshed Resume Prompt offering A–F next-step options. Co-Authored-By: Claude Opus 4.7 --- CHANGELOG.md | 164 +++++++++++++++++-- SESSION_HANDOFF.md | 383 +++++++++++++++++++++++++++------------------ 2 files changed, 383 insertions(+), 164 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4d16f7..8419635 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,89 @@ project follows [Semantic Versioning](https://semver.org/). ## [Unreleased] -Two threads in flight: closing the v0.19.0 punch list (settings opt-out -for the smart-default sizer, share-link discoverability, the last -async-pull test flake) and a new performance / portability arc (F3 -diagnostics overlay landing first, then a working Android build -target via `cargo apk`). The Android build is the load-bearing -change — `solitaire_app` now compiles into both a desktop `bin` and -an Android `cdylib` from the same source tree, so subsequent work -can iterate on a phone or AVD without forking the codebase. +No threads in flight. v0.20.0 cut on 2026-05-07; CHANGELOG accumulates +the next cycle here. + +## [0.20.0] — 2026-05-07 + +Two through-lines closed: a full **Android port** (build target, +first 54 MB APK, JNI-free per-app persistence shim) and the +**Terminal visual-identity port** that replaces the prior +Premium-Solitaire palette across every UI surface. The Android +arc opened in `fb8b2ac` (compile + APK), continued in `4b51e50` +(`solitaire_data::data_dir` shim closing the CLAUDE.md §10 +`dirs::data_dir() = None` pitfall), and is functional end-to-end +on a real device — though the runtime artwork is still the legacy +white-card palette, and JNI ClipboardManager / keyring bridges +remain stubbed (matching v0.19.0's documented fallback behaviour). +The Terminal port lands as a top-down stack: the `ui_theme` token +API in `0d477ac` is load-bearing, and the rest of the cycle is +downstream applications (modal scaffold, gameplay-feedback, +toasts, table / card chrome, splash cursor, hint-highlight +pairing). The card faces and suit-pip palette are deliberately +NOT migrated — those track PNG artwork that hasn't been +regenerated yet, and swapping the fallback constants ahead of the +artwork would mix two visual systems on any code path where +image loading fails. + +The 24 Stitch-rendered mockups in `docs/ui-mockups/` are now +in-tree (`fa7f98a`); future plugin work should diff against the +matching mockup before touching pixels. + +Two threads from v0.19.0's punch list also closed in this cycle: +the pull-failure test flake (`67c150b`), the Settings opt-out for +the smart-default window sizer (`e1b8766`), and the share-link +discoverability surfacing (`9b065e5`). The remaining v0.19.0 +candidate — the app-icon round — stays open. ### Added +- **`ui_theme` Terminal design-token system** (`0d477ac`). Single + source of truth for the engine's visual identity: + base16-eighties palette (cyan primary CTA, lime/lavender/gold/ + teal/pink semantic accents), 5-rung type scale, 7-rung 4-multiple + spacing scale, 3-step radius, 14-rung z-index hierarchy, full + motion budget, and four invariant-pinning unit tests. Every + downstream port commit in this cycle reads from this module — + swapping the palette is now a one-file edit, not a hunt across + ~50 plugin files. Card-shadow alphas pinned to 0 (Terminal + achieves depth via 1px borders + tonal layering, no + `box-shadow`); the rendering path is left intact so a future + palette can re-enable shadows without touching consumers. +- **`ToastVariant` enum + Terminal toast styling** (`a137607`). + Toasts now follow `docs/ui-mockups/design-system.md`: opaque + `BG_ELEVATED` fill, 1px accent border keyed off + `Info` / `Warning` / `Error` / `Celebration` variants, 18px + monospaced caption (`TYPE_BODY_LG`), bottom-anchored. All ten + call sites pass their semantic variant: achievement / level-up + / XP / daily / weekly / challenge → Celebration (lavender); + goal-announcement / time-attack / settings volume / auto-complete + → Info (teal). Two regression tests pin variant→border mapping + to the design tokens and require all four borders to be visually + distinct. Queued and immediate toasts use slightly different + bottom anchors (6 % vs. 14 %) so a celebration toast spawned + alongside a queued info banner layers above it. +- **Terminal cursor block on the splash overlay** (`cdcadda`). + The launch splash now renders the design system's signature + `▌` cyan (`ACCENT_PRIMARY`) glyph (96 px, hand-tuned literal) + above the wordmark, matching `docs/ui-mockups/splash-mobile.html`. + Cursor fades on the same per-frame alpha schedule as the title + and subtitle so the brand beat still dissolves as a single + layer. Did *not* pull in the mockup's full boot-loader treatment + (scanline overlay, ✓ check log, progress bar, ROOT@SOLITAIRE + prompt) — those are aesthetic features warranting their own + commit. +- **Terminal design-system spec + 24-mockup library** (`fa7f98a`). + `docs/ui-mockups/design-system.md` (palette, type scale, spacing + scale, motion budget, component library, accessibility notes — + color-blind toggle, high-contrast mode, glyph differentiation, + canonical `"Terminal"` card-back theme) and 24 Stitch-rendered + mockups (HTML + PNG): 12 redesigned existing screens, 1 desktop + home variant, 2 onboarding steps, and 9 missing-plugin screens + (splash, challenge, time-attack, weekly-goals, leaderboard, + sync, level-up, replay, radial-menu). The spec the rest of this + cycle ports against; future plugin work diffs here before + touching pixels. - **Android build target — first working APK** (`fb8b2ac`). `cargo apk build -p solitaire_app --target x86_64-linux-android` now produces a 54 MB debug-signed APK at @@ -84,8 +156,75 @@ can iterate on a phone or AVD without forking the codebase. dismisses the Win Summary modal. Three post-v0.18 entries that had drifted out of the cheat sheet are now listed. +### Changed + +- **Gameplay-feedback colours route through Terminal state + tokens** (`ceec4fc`). Selection-highlight tints in + `selection_plugin` and the valid-drop marker tint in + `cursor_plugin` were hand-tuned RGB literals. Migrated to + semantic state tokens: keyboard-drag picking source → + `ACCENT_PRIMARY` (cyan focus); keyboard-drag lifted source → + `STATE_WARNING` (gold attention); destination → `STATE_SUCCESS` + (lime valid-move); `cursor_plugin::MARKER_VALID` → + `STATE_SUCCESS` at 0.55 α with a tracking test pinning its RGB + to the token. Three stale doc comments in `ui_modal` corrected + ("loud yellow CTA" / "magenta secondary accent" → cyan / + lavender to match the actual token values). +- **`table_plugin` chrome migration to Terminal tokens** (`651f406`). + `marker_colour` promoted to module-level `pub const + PILE_MARKER_DEFAULT_COLOUR` so `cursor_plugin::MARKER_DEFAULT` + imports the const directly — replaces the prior + duplicated literal kept in sync only by doc comment with a + compile-enforced invariant. The empty-tableau "K" placeholder + text now uses `TEXT_PRIMARY` at 0.35 α; `HINT_PILE_HIGHLIGHT_COLOUR` + retuned from bright `srgb(1.0, 0.85, 0.1)` to the `STATE_WARNING` + token (`#ddb26f`) with a tracking test, and the existing "is + gold" character test loosened to fit the muted Terminal gold + while still rejecting non-warm colours. +- **`card_plugin` chrome migration to Terminal tokens** (`d752870`). + Drag-elevation shadow now sources its colour from + `CARD_SHADOW_COLOR` + `CARD_SHADOW_ALPHA_DRAG` so the Terminal + "no box-shadow" policy disables the stack shadow in lockstep + with the per-card shadows. `RIGHT_CLICK_HIGHLIGHT_COLOUR` + retuned from raw green to `STATE_SUCCESS` at 0.6 α with a + tracking test. The duplicated `PILE_MARKER_DEFAULT_COLOUR` + const dropped — this plugin now imports the promoted const + from `table_plugin`. Stock recycle "↺" text moved from raw + white-at-0.7-α to `TEXT_PRIMARY.with_alpha(0.7)`. Card-face / + suit / card-back palette constants were intentionally NOT + migrated (the runtime path renders PNG artwork that's still on + the previous "white card" palette). +- **Hint-source card tint matches the destination pile** + (`9891ae4`). `input_plugin`'s hint-source card tint moved from + raw bright-yellow `srgba(1.0, 1.0, 0.4, 1.0)` to `STATE_WARNING`, + so the source card and the destination pile (which already uses + `STATE_WARNING` via `HINT_PILE_HIGHLIGHT_COLOUR`) wear the same + attention colour as a coherent pair. + ### Fixed +- **`solitaire_data::data_dir` shim closes the Android persistence + gap** (`4b51e50`). `dirs::data_dir()` returns `None` on Android, + which silently disabled every persistence path (settings, stats, + achievements, replays, game-state, time-attack sessions, user + themes). New `solitaire_data::platform::data_dir()` shim falls + through to `dirs::data_dir()` on desktop and returns the per-app + sandbox at `/data/data/com.solitairequest.app/files` on Android + — no JNI needed, since the package id is pinned in + `[package.metadata.android]`. Six call sites across + `solitaire_data` plus `solitaire_engine/assets/user_dir.rs` + migrated. CLAUDE.md §10 already flagged this as a known + pitfall; the shim pays it down at the one chokepoint instead + of per feature. +- **`card_shadow_params` test aligned with Terminal "no shadow" + intent** (`1d1543e`). The Terminal token system pinned both + `CARD_SHADOW_ALPHA_IDLE` and `CARD_SHADOW_ALPHA_DRAG` to 0.0, + which made the prior `drag_alpha > idle_alpha` assertion fail + (`0 > 0` is false). Loosened to `drag_alpha >= idle_alpha` + with a comment naming the new invariant: under Terminal both + are 0; under any future palette that re-enables shadows, drag + still must not be weaker than idle. The useful regression-guard + (catching an accidental swap of the two constants) is preserved. - **`pull_failure_sets_error_status` test flake** (`67c150b`). The fixed 5-update budget was the last test still subject to the AsyncComputeTaskPool starvation mode that v0.19.0's @@ -96,9 +235,12 @@ can iterate on a phone or AVD without forking the codebase. ### Stats -- 1170 passing tests / 0 failing (matches v0.19.0; the - pull-failure flake fix changed the test's pumping shape but - not its count). +- **1176 passing tests / 0 failing** across the workspace + (six new tests this cycle: four `ui_theme` invariant guards + for the type / spacing / z-index scales + `scaled_duration`, + one toast-variant-border-mapping pair, and four palette- + tracking guards on `MARKER_VALID` / `HINT_PILE_HIGHLIGHT_COLOUR` + / `RIGHT_CLICK_HIGHLIGHT_COLOUR` / toast-border distinctness). - Zero clippy warnings under `--workspace --all-targets -- -D warnings`. ## [0.19.0] — 2026-05-06 diff --git a/SESSION_HANDOFF.md b/SESSION_HANDOFF.md index 3442db4..0c4caeb 100644 --- a/SESSION_HANDOFF.md +++ b/SESSION_HANDOFF.md @@ -1,196 +1,273 @@ # Solitaire Quest — Session Handoff -**Last updated:** 2026-05-07 — `[Unreleased]` accumulating v0.20 -candidates. Seven commits sit on top of v0.19.0: three close items -from v0.19.0's punch list (pull-failure flake, smart-window-size -opt-out, Shareable badge), one extends Help cheat-sheet coverage, -and three open a new performance / portability arc — F3 FPS -overlay, Android build target (first working APK), and the matching -developer-setup runbook. The Android build is the load-bearing -change: `solitaire_app` now compiles into both a desktop `bin` and -an Android `cdylib` from the same source. +**Last updated:** 2026-05-07 — v0.20.0 cut. Two through-lines closed +in this cycle: a full **Terminal visual-identity port** (token system +in `ui_theme` plus downstream chrome migrations across modal scaffold, +gameplay-feedback, toasts, and the table / card / splash surfaces) +and the **Android persistence shim** that closes the +`dirs::data_dir() = None` pitfall flagged in CLAUDE.md §10. The +Android *build* target landed earlier in the cycle (`fb8b2ac`); this +session paid down the persistence half so a real APK can survive a +cold start. The 24 Stitch-rendered mockups are now in-tree under +`docs/ui-mockups/`; future plugin work diffs against the matching +mockup before touching pixels. ## Status at pause -- **HEAD on origin:** `59424a3` (post-Android-runbook commit). -- **Working tree:** modified — `CHANGELOG.md` and - `SESSION_HANDOFF.md` carry the v0.20-candidates promotion + this - refresh, ready to commit. `artwork/` remains untracked. +- **HEAD on origin:** the v0.20.0 docs commit (the one that lands + this file + CHANGELOG cut). Tag not yet pushed; cut whenever + feels right. +- **Working tree:** clean apart from the still-untracked `artwork/` + directory (intentional — the card PNGs there are mid-flight for + the Terminal aesthetic and committing now would freeze a + transitional state). - **Build:** `cargo clippy --workspace --all-targets -- -D warnings` - clean (verified this session). -- **Tests:** **1170 passing / 0 failing** across the workspace - (verified this session). The previously-flaky - `pull_failure_sets_error_status` is fixed; no known flakes remain. -- **Tags on origin:** `v0.9.0` through `v0.19.0`. + clean. +- **Tests:** **1176 passing / 0 failing** across the workspace. + Six new tests this cycle: four `ui_theme` invariant guards + (type / spacing / z-index scales + `scaled_duration`), one + toast-variant-border-mapping pair, and four palette-tracking + guards on `MARKER_VALID` / `HINT_PILE_HIGHLIGHT_COLOUR` / + `RIGHT_CLICK_HIGHLIGHT_COLOUR` / toast-border distinctness. No + known flakes. +- **Tags on origin:** `v0.9.0` through `v0.19.0`. v0.20.0 not yet + tagged. -## Where we are +## What shipped in v0.20.0 -v0.19.0's "Possible next-round candidates" list shipped 3 of 4: +### Terminal visual-identity port -- ~~**`pull_failure_sets_error_status` flake fix:**~~ shipped at - `67c150b`. -- ~~**Settings UI for smart-default-size opt-out:**~~ shipped at - `e1b8766`. -- ~~**Persistent share link URL on selector caption:**~~ shipped at - `9b065e5` (as a "Shareable" badge on the Latest-win caption — - the Prev/Next selector chips don't have a live spawn site yet, - so the badge attaches to the existing single-replay caption). -- **App icon round** — still open. 11 PNGs generated by - `artwork/Icon Export.html` are *not* in the `artwork/` directory - any more (current `artwork/` holds the reverted Rusty Pixel - card PNGs); icon-export needs to be re-run before this item can - be picked up. +Top-down stack — every commit downstream of the token system +reads from it, so swapping the palette is now a one-file edit: -Two new threads opened that weren't on any prior punch list: +- **`ui_theme` token system** (`0d477ac`). base16-eighties + palette, 5-rung type scale, 7-rung 4-multiple spacing scale, + 3-step radius, 14-rung z-index hierarchy, full motion budget, + 4 invariant-pinning unit tests. Card-shadow alphas pinned to 0 + (Terminal achieves depth via 1px borders + tonal layering). +- **Modal scaffold already on tokens** — `ui_modal` was ported + in the same commit's wake; three stale "loud yellow" / + "magenta secondary" doc comments fixed. +- **Gameplay feedback → semantic state tokens** (`ceec4fc`). + Selection / valid-drop tints route through `ACCENT_PRIMARY` / + `STATE_WARNING` / `STATE_SUCCESS`. +- **Toasts** (`a137607`). New `ToastVariant` enum + (Info / Warning / Error / Celebration); opaque `BG_ELEVATED` + + 1px accent border + bottom-anchor. All ten call sites pass + their semantic variant. +- **`table_plugin` chrome** (`651f406`). + `PILE_MARKER_DEFAULT_COLOUR` promoted; `cursor_plugin` imports + it, replacing a "kept in sync" doc comment with a compile- + enforced invariant. `HINT_PILE_HIGHLIGHT_COLOUR` → + `STATE_WARNING`. +- **`card_plugin` chrome** (`d752870`). Drag-elevation shadow + routes through `CARD_SHADOW_*` tokens. `RIGHT_CLICK_HIGHLIGHT_COLOUR` + → `STATE_SUCCESS`. Stock recycle "↺" text → `TEXT_PRIMARY @ 0.7α`. + Card-face / suit / card-back palette intentionally NOT migrated + (artwork dependency — see open-list item below). +- **Splash cursor** (`cdcadda`). The signature `▌` cyan glyph + (96 px) added above the wordmark, matching the spec. +- **Hint-source / dest pairing** (`9891ae4`). `input_plugin`'s + source-card tint now matches the destination pile's + `STATE_WARNING`. +- **Design system + 24-mockup library** (`fa7f98a`). + `docs/ui-mockups/design-system.md` + 24 Stitch mockups (HTML + + PNG) covering every screen plus 9 missing-plugin surfaces. +- **`card_shadow_params` test aligned** (`1d1543e`). Drag-vs- + idle shadow assertion loosened to `>=` to accept the Terminal + "no shadow" intent without losing the regression-guard. -- **F3 FPS / frame-time overlay** (`690e1d2`). `DiagnosticsHudPlugin` - wraps `FrameTimeDiagnosticsPlugin`; F3 toggles a top-right - readout. Hidden by default; primarily a developer affordance. -- **Android build target** (`fb8b2ac` + `59424a3`). - `solitaire_app` is now a bin + cdylib hybrid. `cargo apk build` - produces a 54 MB APK with full assets. Five gating points - resolved (split, manifest, bevy feature, arboard target-gate, - keyring target-gate). What's *not* yet verified: APK launch on - AVD/phone, `dirs::data_dir()` Android behaviour for the - persistence/sync layer. +### Android persistence -### Design direction (unchanged) +- **`solitaire_data::data_dir` shim** (`4b51e50`). New + `solitaire_data::platform::data_dir()` falls through to + `dirs::data_dir()` on desktop and returns the per-app sandbox + at `/data/data/com.solitairequest.app/files` on Android — no + JNI needed (package id pinned in `[package.metadata.android]`). + Six `solitaire_data` callsites + `solitaire_engine/assets/user_dir.rs` + migrated. Settings, stats, achievements, replays, game-state, + time-attack sessions, and user themes now persist on Android. -- **Tone:** Balatro — chunky readable type, theatrical hierarchy, - satisfying micro-interactions. -- **Palette:** Midnight Purple base + Balatro yellow primary + warm - magenta secondary. +### Inherited from earlier in the cycle (pre-session) + +- Android build target + APK (`fb8b2ac`), runbook (`59424a3`), + F3 FPS overlay (`690e1d2`), Smart Window Size opt-out + (`e1b8766`), Shareable badge (`9b065e5`), Help cheat-sheet + M/P/Enter rows (`35516d3`), `pull_failure_sets_error_status` + flake fix (`67c150b`). + +## Open punch list + +### Phase Android (build + persistence shipped; runtime gaps remain) + +- **APK launch verification on AVD / device.** `adb install` then + `adb logcat` against the `bevy_test` AVD or an x86_64 device. + The build works and persistence is wired, but no end-to-end + device run has been logged. Shakes out runtime bugs the build + + unit tests can't catch. +- **JNI ClipboardManager bridge.** Replaces the Android stub for + the Stats "Copy share link" toast. `arboard` doesn't ship an + Android backend; small custom JNI call. +- **Android Keystore for credentials.** `keyring` is target-gated + to a stub returning `KeychainUnavailable`; replace with Android + Keystore via JNI when sync auth ships on mobile. +- **Google Play Games (gpgs) integration.** Listed as a + Phase-Android target since Phase 1; now unblocked by the build + target. +- **Cosmetic `cargo apk build --lib` workaround.** Post-sign + panic doesn't affect the APK on disk but produces noisy stderr. + Either upstream a cargo-apk fix or document `--lib` as + canonical in the runbook. + +### Visual-identity follow-ups (opened by v0.20.0's port) + +- **Card-face / suit / card-back artwork regeneration.** The + Terminal spec calls for dark `#1a1a1a` cards with light suit + pips (pink for hearts/diamonds, foreground gray for spades/ + clubs); the runtime path still renders the legacy white-card + PNG artwork. The fallback constants in `card_plugin` + (`CARD_FACE_COLOUR`, `RED_SUIT_COLOUR`, `BLACK_SUIT_COLOUR`, + `CARD_FACE_COLOUR_RED_CBM`, `card_back_colour` palette) are + intentionally unmigrated and should swap in lockstep with the + artwork. Largest visible payoff remaining in the visual- + identity arc. +- **Splash boot-loader richness.** The mockup + (`docs/ui-mockups/splash-mobile.html`) calls for a scanline + overlay, ✓ lime check log lines, pulsing cursor, ROOT@SOLITAIRE + prompt, and a loading bar — none of which v0.20.0's + cursor-glyph-only port pulled in. Aesthetic feature, its own + commit. +- **Replay-overlay redesign.** The mockup + (`docs/ui-mockups/replay-overlay-mobile.html`) envisions a + much richer surface (terminal `▌replay.tsx` header, move log + scroll, MOVE 47/87 chip, WIN MOVE callout, status bar) versus + the current top banner. Aesthetic feature. +- **Toast Warning / Error variants.** The new `ToastVariant` + enum has slots for `Warning` (gold) and `Error` (pink) but no + in-engine event uses them yet (the four current toast events + all map to Info or Celebration). Wire when a warning- or + error-flavoured toast event materialises. + +### Carried forward from v0.19.0 + +- **App icon round.** `Window::icon` not yet wired; no + `.icns` / `.ico` / Linux hicolor PNG hierarchy. The 11-size + icon export the v0.19 handoff referenced is *not* currently + in `artwork/` (current `artwork/` holds the reverted Rusty + Pixel card PNGs and is intentionally untracked); icon-export + needs to be re-run before this item can be picked up. + Half-day task once the PNGs are back in place. No cert + dependency. + +### Other small candidates + +- **Prev/Next selector chips spawn site.** v0.19.0's `9b065e5` + noted Prev/Next markers exist in `stats_plugin` but no spawn + site renders them today — the Shareable badge therefore lands + on the single-replay caption. If/when Prev/Next is plumbed, + the badge will need to follow. +- **Toast queue / immediate unification.** The two toast paths + (`spawn_queued_toast` for `InfoToastEvent` queue; `spawn_toast` + for fire-and-forget) now share visual treatment but remain + separate functions because they serve different temporal + needs (sequential vs. parallel). If overlap becomes a UX + issue, merge into one queue with priority lanes. + +### Process notes + +- **Token-port pattern.** v0.20.0's chrome-migration commits + set a reusable shape for "centralized design system applied + across N plugins": + 1. Constants module (`ui_theme.rs`) is the source of truth. + 2. Const sites that can't call `Alpha::with_alpha` (not yet + `const` on stable) use a literal RGB matching the token, + with a unit test pinning the RGB to the token (e.g. + `MARKER_VALID`, `HINT_PILE_HIGHLIGHT_COLOUR`, + `RIGHT_CLICK_HIGHLIGHT_COLOUR`). + 3. Cross-plugin duplication (e.g. `MARKER_DEFAULT` ↔ + `PILE_MARKER_DEFAULT_COLOUR`) collapses to a single + promoted const re-exported from one plugin and imported + by the other — replaces "kept in sync" doc comments with a + compile-time invariant. + 4. Domain colours (suit pips, card faces, lerp helpers) stay + as literals with a comment naming the rationale; only UI + chrome routes through tokens. +- **Audit before migrating wide.** Before touching any plugin, + grep for the literal pattern (`Color::srgb\(|Color::srgba\(| + Color::WHITE|Color::BLACK`) and classify each hit as domain + vs. chrome. Most plugins after the modal scaffold port turned + out to be 100 % token-correct already; the audit prevents + wasted churn. ### Canonical remote `github.com/funman300/Rusty_Solitaire` is the canonical repo. Always push there. -## v0.20 candidates ([Unreleased] in CHANGELOG) +### Design direction (now Terminal — base16-eighties) -| Area | Commit | What landed | -|---|---|---| -| Async-pull flake fix | `67c150b` | `pull_failure_sets_error_status` swaps a fixed 5-update budget for a 5-second wall-clock deadline + `yield_now` between pumps. Closes the last v0.19-era flake. | -| Smart window size opt-out | `e1b8766` | New `Settings::disable_smart_default_size: bool` (#[serde(default)]). `solitaire_app::main` reads the flag at startup and skips `apply_smart_default_window_size` registration when set. Settings → Gameplay row toggles it; tooltip notes saved geometry always wins. | -| Shareable badge | `9b065e5` | Stats overlay's Latest-win caption gains `\u{2022} Shareable` when the displayed replay carries a `share_url`. Badge appears on the single-replay caption (no Prev/Next live spawn site yet). | -| Help: M / P / Win-Summary-Enter | `35516d3` | Three rows added to F1 Help → Overlays. Closes coverage drift on post-v0.18 keys. | -| F3 FPS overlay | `690e1d2` | `DiagnosticsHudPlugin` + `FrameTimeDiagnosticsPlugin`. Hidden by default; F3 toggle is not gated by pause/modal state. Smoothed FPS / frame_time. Anchored top-right at `Z_SPLASH + 100`. | -| Android first APK | `fb8b2ac` | `solitaire_app` split into bin + lib (cdylib). `[package.metadata.android]` pins SDK 34 / 26. Bevy gains `android-native-activity`. `arboard` and `keyring`/`keyring-core` target-gated to non-Android. 54 MB APK builds; launch on device not yet verified. | -| Android runbook | `59424a3` | Debian 13 toolchain install, `cargo apk build` invocation, post-sign panic workaround, wired-vs-stubbed table. Fresh-clone runnable. | +- **Tone:** retro-terminal / synthwave — flat depth (no box-shadows), + monospaced-forward typography (JetBrains Mono / FiraMono), tight + 16 px edge margins, 8 px card radius. +- **Palette:** near-black surface ramp (`#151515` / `#202020` / `#2a2a2a` + / `#353535`), cyan primary CTA (`#6fc2ef`), lime success + (`#acc267`), gold warning (`#ddb26f`), pink error / suit-red + (`#fb9fb1`), lavender celebration (`#e1a3ee`), teal info + (`#12cfc0`). +- **Two-color suits.** Red = `#fb9fb1`, black = `#d0d0d0`. Outlined + glyphs for diamonds & clubs are *always on*; the Settings + "color-blind mode" toggle only swaps red → cyan. -## Open punch list - -### Carried forward from v0.19.0 - -- **App icon round.** `Window::icon` not yet wired; no `.icns` / - `.ico` / Linux hicolor PNG hierarchy. The 11-size icon export - the v0.19 handoff referenced is *not* currently in - `artwork/` — re-running `artwork/Icon Export.html` is the - prerequisite. Half-day task once the PNGs are back in place. - No cert dependency. - -### New — Phase Android (opened by `fb8b2ac` + `59424a3`) - -- **APK launch verification on AVD / device.** `adb install` then - `adb logcat` against the bevy_test AVD. Shakes out any - Bevy/winit Android-specific runtime bugs not caught by the - build alone. -- **`dirs::data_dir()` Android port.** Persistence (settings, - stats, achievements, replays, progress) all route through this - function. Android sandboxing usually demands `getFilesDir()` via - JNI. Until verified, the APK may launch but fail to persist - anything across cold starts. -- **JNI ClipboardManager bridge.** Replaces the Android stub for - the Stats "Copy share link" toast. `arboard` doesn't ship an - Android backend, so this is a small custom JNI call. -- **Android Keystore for credentials.** `keyring` is target-gated - to a stub that returns `KeychainUnavailable`; replace with - Android Keystore via JNI when sync auth ships on mobile. -- **Google Play Games (gpgs) integration.** Listed in `solitaire_gpgs` - as a Phase-Android target since Phase 1; now unblocked by the - build target. -- **Cosmetic `cargo apk build --lib` workaround.** The - post-sign panic doesn't affect the APK on disk but produces - noisy stderr. Either upstream a cargo-apk fix or document the - `--lib` invocation as canonical in the runbook. - -### Other small candidates - -- **Cut v0.20.0** — the seven commits are a coherent bundle (3 - punch-list closes, 1 docs polish, 1 perf tool, 2 Android arc - starters). Tag whenever feels right; the Android arc has more - surface to land before it's "done", but the build-works state - is a defensible release point. -- **Prev/Next selector chips spawn site.** `9b065e5` notes - Prev/Next markers exist in `stats_plugin` but no spawn site - renders them today — the Shareable badge therefore lands on - the single-replay caption. If/when Prev/Next is plumbed to the - Stats overlay, the badge will need to follow. - -### Process notes (from this round) - -- **Async-test starvation pattern (resolved twice now).** - Auto-save flake (v0.19) and pull-failure flake - (v0.20-candidates) shared the same root cause: a fixed - N-update budget for an `AsyncComputeTaskPool` task to surface - its result, which starves under cargo-test parallelism. The - wall-clock-bounded loop pattern (`std::thread::yield_now()` - between pumps, deadline = `Instant::now() + Duration::from_secs(5)`) - is the canonical fix. Future async-test work should reach for - this shape on the first commit, not after a flake materialises. -- **Bin → lib + thin shim refactor.** The `solitaire_app` split - for cargo-apk is a textbook cdylib-as-NativeActivity pattern. - Worth knowing as a reusable shape for any future Bevy-on-mobile - project: keep `main.rs` to ≤10 lines that delegate to - `pub fn run`, put all setup in `lib.rs`, and let the build - system pick which artifact (`bin` or `cdylib`) it needs. -- **Target-gating defensive defaults.** Three of v0.20-candidates' - Android-arc commits had to disable a default-on dependency - (`arboard`, `keyring`, `keyring-core`) for the new target. - When a future contributor adds a desktop-implicit dependency, - reaching for `[target.'cfg(not(target_os = "android"))'.dependencies]` - preemptively is cheaper than rediscovering the gating during - the next platform port. +(Was: Midnight Purple base + Balatro yellow primary + warm magenta. +Replaced this cycle.) ## Resume prompt ``` You are a senior Rust + Bevy developer working on Solitaire Quest. Working directory: . -Branch: master. v0.19.0 is tagged on origin; seven commits sit on -top opening the v0.20 cycle (3 punch-list closes + a perf tool + -the Android build target). +Branch: master. v0.20.0 just cut on 2026-05-07; CHANGELOG's new +[Unreleased] section is empty pending the next cycle's threads. -State: HEAD at 59424a3 + the v0.20-candidates docs commit on top -(this session). Working tree may carry the doc updates if not yet -committed. +State: HEAD on the v0.20.0 docs commit. Tag not pushed yet — last +pushed tag is v0.19.0. Working tree clean apart from the +intentionally-untracked `artwork/`. READ FIRST (in order, before doing anything): 1. SESSION_HANDOFF.md — this file - 2. CHANGELOG.md — [Unreleased] holds the v0.20 draft + 2. CHANGELOG.md — [0.20.0] section is the most recent cut 3. CLAUDE.md — unified-3.0 rule set 4. CLAUDE_SPEC.md — formal architecture spec 5. ARCHITECTURE.md — crate responsibilities + data flow - 6. docs/android/* — Android setup + build runbook (59424a3) - 7. ~/.claude/projects//memory/MEMORY.md + 6. docs/ui-mockups/ — design system + 24-mockup library + (Terminal aesthetic — landed in fa7f98a) + 7. docs/android/* — Android setup + build runbook + 8. ~/.claude/projects//memory/MEMORY.md — saved feedback / project context (machine-local; may be missing on a fresh machine) DECISION TO ASK THE PLAYER FIRST: - A. APK launch verification — `adb install` + `adb logcat` on - bevy_test AVD or a physical x86_64 device. Shakes out - runtime bugs the build can't catch. - B. Phase-Android persistence — port dirs::data_dir() through a - JNI getFilesDir() bridge so the APK can survive a cold - start. Largest unblocked Android piece. - C. App icon — re-run artwork/Icon Export.html, then wire + A. Push v0.20.0 tag — `git tag v0.20.0 && git push --tags`. If + the player wants the cut formalised before any new work. + B. APK launch verification — `adb install` + `adb logcat` on + bevy_test AVD or an x86_64 device. Now that persistence is + wired (4b51e50), shake out remaining runtime bugs. + C. Card-face artwork regeneration — generate Terminal-aesthetic + card PNGs (dark face, light suit pips), then migrate + CARD_FACE_COLOUR / RED_SUIT_COLOUR / BLACK_SUIT_COLOUR / + CARD_FACE_COLOUR_RED_CBM in lockstep. Largest visible + payoff remaining in the visual-identity arc. + D. Splash boot-loader richness — port the scanline overlay, + ✓ check log, pulsing cursor, ROOT@SOLITAIRE prompt, and + loading bar from docs/ui-mockups/splash-mobile.html. Pure + polish; no behavioural change. + E. App icon round — re-run artwork/Icon Export.html (the + export PNGs are not currently in `artwork/`), then wire Window::icon + generate .icns / .ico. Half-day task. No cert dependency. - D. Cut v0.20.0 — promote [Unreleased] to [0.20.0], tag, - push. Mechanical close-out; the Android arc has more - surface to land but the build-works state is a defensible - release point. + F. JNI ClipboardManager / Keystore bridge — replaces the + Android stubs for Stats clipboard share + sync auth. WORKFLOW NOTES: - Use the system git config (already correct). @@ -201,5 +278,5 @@ WORKFLOW NOTES: - Push to GitHub (origin) — gh auth setup-git wired on primary dev box; verify on laptop before first push. -OPEN AT THE START: ask which of A–D. Don't pick unilaterally. +OPEN AT THE START: ask which of A–F. Don't pick unilaterally. ```