# The menu's screen id and cursor, in guest memory **✅ Found and verified 2026-08-26.** Menu navigation in this corpus has always been driven by screenshots. That is unusable under `--gpu=null`, which is the only configuration where the game does not hit the software-rasterizer freeze ([`mission-freeze-heap-exhaustion.md`](mission-freeze-heap-exhaustion.md)) — so without a memory signal, the one backend that runs is the one that cannot be steered. ## The words | address | meaning | |---|---| | **`0x828A690C`** | **screen id** — `1` title, `3` main menu, `4` extras | | **`0x828F38AC`** | **menu cursor** (a second copy at `0x828F38BC`) | | `0x828F37B4` | tracks the screen, distinct value per menu | ## How they were found Snapshot `0x82800000` + 3 MB at each menu of a **rendered** run, then keep the 4-byte words that (a) differ between screens and (b) hold small integer values. Of 786 432 words, exactly **four** qualified — and one of them, `0x828A690C`, has the property that matters: it changes on a screen *transition* and stays put when only the highlight moves. screen: title -> main menu -> (4x down) -> extras 828a690c: 1 -> 3 -> 3 -> 4 <- screen id 828f38ac: 2 -> 4 -> 12 -> 14 <- cursor moves with the highlight 828f37b4: 12 -> 45 -> 45 -> 49 ## ✅ Verified against a second run on a different GPU backend The values were then read on a fresh `--gpu=null` run — **no display at all** — while driving the same key sequence blind: | step | rendered (lavapipe) | blind (`--gpu=null`) | |---|---|---| | title | 1 / 2 / 12 | **1 / 2 / 12** | | main menu | 3 / 4 / 45 | **3 / 4 / 45** | | after 4× down | 3 / 12 / 45 | **3 / 12 / 45** | | extras | 4 / 14 / 49 | **4 / 14 / 49** | **4 / 4 exact**, across two runs and two backends. That is the check that matters: the words are not run-dependent, unlike the OB counter address this corpus had to mark run-dependent earlier. `tools/re-capture/menu_state.py` reads them (`menu_state.py watch` polls and prints on change). ❔ Still open: the rest of the sequence into a **mission**. Blind driving reached `extras` (screen 4) and a further Ⓐ did not move it — `4 / 14 / 49` twice — so MISSION SELECT needs a cursor move first. The screen ids beyond 4 are unmapped; the same snapshot-and-diff method extends to them, but it must be done on a rendered run, and the rendered run **freezes on entering that screen**. The way through is to map the ids up to the freeze and step blind past it.