# 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 and wheel from a `RouletteView`; it owns the geometry, not the rules. The felt is pointer-first: the hover snaps to the fine lattice, so the inner half of a cell is a straight, an edge is a split and a crossing is a corner. Left click adds the selected chip, right or middle click takes one back, and a translucent chip previews the target under the pointer. - `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, highlights the winning pocket and cell, and reports the amount paid and the net for the round. SPIN and CLEAR sit side by side so clearing is never below the fold. - `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.