Chapter 7: panels, everything drawn beside the picture
The window shows the game in the middle and, around it, what we want to know about the game: what the bot thinks it is doing, the game state in words, every question Jev was asked, the pad, and a timeline to scrub. This crate draws all of that. It does not draw the game: the picture is never drawn over, so nothing covers the game's own hearts, rupees and item box.
Every panel here is a function from a plain value to egui
calls (and, being built with the hot-patch flags, can be changed while the
game runs: chapter 27). egui is an immediate-mode UI: there is no tree of widgets kept
between frames. Each frame, the app calls panels::state::show(ui, &state)
(or its neighbours), and whatever those calls describe is what is on screen.
If you have written a React component that is a pure function of its props,
you have written one of these; the difference is that it is called sixty
times a second and there is no diffing.
Aside: plain data in, on purpose. The bot panel never sees a
zbanks::Report, and the replay panel never sees areplay::Tree. Those crates link C or write files, and this one must stay portable (chapter 1). So the app converts what it has into this crate's own small structs, and these functions only draw.
The layout is one function of the window's size, Layout::of: the
picture's cell is exactly 4:3 with no slack, the two side columns are
always the same width, and directly under the picture are the scrubber and
then the pad. A test says so.
flowchart TB
subgraph window
direction LR
L["left: Bot, MCP"] --- P["picture, 4:3"] --- R["right: State, Jev"]
end
P --- S["scrubber"] --- PAD["pad"]
Try it.
nix develop -c buck2 test //packages/panels:testchecks the layout invariant, the scrubber's click-to-frame maths and the Jev history's rows (the favourite, a missing probability, a long option wrapping). To see the panels themselves, open the window (chapter 12).
For the people who maintain it
In this folder
| Path | What |
|---|---|
| src/lib.rs | The modules. |
| src/bot.rs | What the bot says about itself: its info line, task list, goal list with scores, traps, and the stall and recovery lines. Plain data in; this crate never links the bot. |
| src/jev.rs | Jev at the goal choice: on or off, the shared spend guards (spent so far, plainly, with no cap), a usage graph bucketed by game frame across the current recording with a playhead, and a scrollable, click-to-expand history of every choice (the request as sent, every option's probability, the pick and upstream's own, tokens, latency, cost, or why nothing was asked). |
| src/state.rs | The alttp::State in words. |
| src/pad.rs | A SNES pad. Buttons held on the last frame are lit; a press that came with a confidence carries it as a percentage. |
| src/layout.rs | The whole window layout as one function of its size, with its test. |
| src/replay.rs | The replay timeline: a scrubber over everything a recording has played, play/pause, skip to end, the speed control, and "run the bot from here". |
| src/palette.rs | Every colour these panels use, legible on the dark theme. |
| BUCK | The rust_library, built with the hot-patch flags (-Csave-temps=true, -Clink-dead-code), and //packages/panels:test. |
The MCP panel is not here: only the native window has a server, so it lives
in apps/native.
← Previous: Chapter 6, replay/ · Up: packages · Next: Chapter 8, mcp/ →