# GUI plan Decisions and rationale live in `docs/adr/0001-gui-frontend-architecture.md` and `0002-version-lockstep.md`. This file is the order of work. ## Non-goals Audio, 3D, macOS, auto-update, a browser client, and pixel-golden tests in CI. ## Phase 0 — version handshake (v4.0.0) Breaking wire change, released for client and server together. - `HELLO ` is the first line after TLS. The server answers `HELLO latest= url=` and rejects every other message with `ERROR HELLO required` until it has seen one. - MAJOR.MINOR must match; PATCH may differ. A mismatch is refused before any credentials are sent. - The client measures its connect latency with the `HELLO` round trip and prints a notice when the server advertises a newer version. - `DOWNLOAD_URL` is read from the environment by the server, with the public site as the fallback. **Gate:** mismatch refused in both directions, `HELLO` required before auth, existing game flows unchanged, new tests for version parsing and gating. ## Phase 1 — core boundary and roulette (done) Complete in v4.0.7. Every game plus `Lobby` and `History` are structured views; the core builds the view and frontends send `Command`. The client transport (TCP, rustls, TOFU, `HELLO`, auto-login) lives in `client::transport` behind a trust callback. The command line moved out of the core in two pieces: `client::input` owns the editor, history and key mapping, and `client::shell` parses a finished line into a core `Command` or an adapter action (connect, login, register, set-credential, host maintenance). `ClientCore` no longer holds a `Key`, a prompt buffer, or any of the old TUI-shaped effects (`Interactive`, `SetPrompt`, `ListHosts`, `ForgetHost`, `AnimateRoulette`); the roulette wheel animation is derived from the `Result` view by the adapter. "Log out" (`logout`) and "forget saved login" (`forget-login`) are distinct: the latter drops the credential for the pinned key and keeps trust. The `Connect` and `Trust` screens are adapter-owned for now: the terminal asks in the transcript, and the GUI will draw them as its own screens over the same `client::transport` callback. They are not core state because the core never sees a certificate. - Introduce `Command` and `View`; move terminal-only concerns (prompt editing, wheel animation, interactive prompts) into the TUI adapter. - App screens: `Connect`, `Trust`, `TrustMismatch`, `Login`, `Lobby`, `History`, `Game`. - Port roulette first: `PlaceBet(BetTarget)`, `SetChip`, `ClearBets`, `Spin`, and a `FeltView` carrying chips, cursor, and the last result. - Add `forget-login` so "log out" and "forget saved login" are distinct in both frontends. - Auto-login stays: a stored credential for the pinned fingerprint logs in automatically after the trust check. **Gate:** met. The TUI behaves as before (same boards, keys and prompts), its tests drive the real adapter path (`shell::parse`, `Editor`, `game_input`), and `ClientCore` contains no terminal types. ## Phase 2 — the other three games Slots, blackjack, crash ports with their own `GameView` variants and commands. Server push (`CRASH_BUSTED`) feeds the same `View`. The TUI keeps animating the crash board from its local clock. **Gate:** all four games playable in the TUI through `Command`/`View`. ## Phase 3 — `gui/` skeleton and the style spike **Code complete in v4.1.0; awaiting the screenshot sign-off.** - `gui/` is a workspace member (`zagan-bet-gui`). It depends on the core with `default-features = false`, so neither egui nor native-tls enters the TUI or server build graph. The build uses the workspace's `gui-release` profile (opt-level `z`, LTO, stripped). - `gui/src/theme.rs` holds the tokens: the terminal-derived dark palette, felt green kept for the table, a 4/8/12/16/24 spacing scale, radii, and the type scale. Two embedded fonts: Open Sans (OFL) for text, Hack (MIT) for numbers, chips and labels. Licences sit next to the files in `gui/assets/fonts/`. - `gui/src/roulette.rs` draws the felt, chips, the fine lattice cursor and the wheel from a `RouletteView`; it owns the geometry, not the rules. - `gui/src/app.rs` composes the persistent header (connection, account, balance) with the table and the betting sidebar. The demo state animates a 2.4 s wheel spin and highlights the winning pocket and cell. - `gui/tests/layout.rs` covers the pure maths (money grouping, wheel angle, table aspect, bet names). UI wiring tests arrive with `egui_kittest` in Phase 4. Measured on Linux at 1080p with llvmpipe software GL: | Check | Result | | --- | --- | | Linux binary | 6.0 MB | | Windows x86_64 binary | 4.7 MB | | Cold start to window | 52 ms | | Idle RSS | 137 MB | | Idle CPU | 0% | The approved reference lives at `docs/screenshots/gui-roulette-1080p.png`, with the result state at `docs/screenshots/gui-roulette-result-1080p.png`. **Gate:** the screenshot needs your approval. Frame rate on integrated graphics still needs a run on real hardware. ## Phase 4 — GUI wiring ## Phase 4 — GUI wiring - Network thread with channels, request deadlines in the shared adapter. - Trust modal, version-mismatch screen, login/register, lobby, history panel. - All four games, per-frame painting and tier 1–2 effects. - Update notice from the handshake in the lobby. **Gate:** manual checklist per game at 60 fps, `egui_kittest` wiring tests, modem-throttled run. ## Phase 5 — packaging - `publish.sh` emits `zagan-bet-gui---[.exe]`. - Bash and PowerShell installers that verify the SHA-256, install to the user directory, and create `.desktop`/Start-menu entries. - Download page lists raw binaries and installers; add the source-code link. **Gate:** `deploy.sh` verifies both artifact kinds; a clean machine installs from the page and launches. ## Testing split - `View`/`Command` tests in the core: flows, gating, state. Always. - The TUI adapter remains the regression net through Phases 1–2. - `egui_kittest` for wiring that `View` cannot see; no pixel goldens in CI. - Manual for feel, animations, and layout at different window sizes.