This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/menu-navigation-semantics.md
Sylpheed RE agent dfcaac221e re: the new-game path completes, the intro is only weakly identified, and
this container kills long runs

Three results, and the middle one is deliberately not upgraded.

First: NEW GAME -> DIFFICULTY -> NORMAL -> SELECT DATA -> pick a slot ->
a movie plays, with no crash. The previous run's throw at 0x82307128 is
therefore not inherent to the menu path -- the same six presses got
through it -- which fits the incomplete-cache trigger the corpus already
names. n=1 either way, and the note says so. Worth recording because one
observation had already hardened once into "A on NEW GAME hangs", and it
would have hardened again into "the new-game path crashes".

Second: with the path open, the manifest's MS00A -> S00A.wmv finally got
a runtime test, and it did NOT reproduce the quality of the attract-movie
identification. The first four samples give a clean monotonic S00A
playhead of 2, 6, 9, 13 s and the strongest frame matches at 0.916, but
the run as a whole is not one advancing timeline, most frames sit at
contrast 23-37 where this page's own rule says discrimination is poor,
and one high-contrast frame prefers ADV. So it stays amber: consistent
with S00A, corroborating the manifest decode, not confirming it. A clean
answer needs the 30fps x11grab route rather than 5-second screenshots.

Third, and it bounds the rest: the emulator vanished at ~145 s with no
crash line in its own log, last entries routine MEM-WATCH at 1.15 GB RSS.
Second time this session -- the other was ~50 s into a boot. That is an
external kill on a box with ~1 GB free and swap exhausted, not a guest
fault. METHOD and the handoff's residue table both now say dynamic
experiments here have to fit in about two minutes of guest time, which is
why the DELTASABER plates went unseen again: they need a mission load and
the run never got there.
2026-08-28 19:19:14 +00:00

137 lines
7.4 KiB
Markdown

# The title menu — how it moves, and where each button goes
**Status:**`CONFIRMED` (**measured**, by driving the running game) for the
movement rules and for four of the five main-menu destinations. 🟡 the GamePart
*id* behind each destination is a **name match onto the decoded id table**, not a
measurement. ❔ `NEW GAME` deliberately untested.
Answers [MISSION Q5](../port/MISSION.md) and most of Q4. Nothing here is on the
disc in any form found so far — the port is **authoring** these rules from this
page, not transcribing a field.
## Q5 — movement
Two boots via `tools/re-capture/boot_menu.sh`, cursor read off the focus ring
with [`tools/re-capture/menu_focus.py`](../../tools/re-capture/menu_focus.py).
| | behaviour | evidence |
|---|---|---|
| **initial focus, main menu** | **`TUTORIAL`** — the *middle* item, not the top | 2/2 boots, the first frame after the menu appears |
| **initial focus, `EXTRAS`** | `MISSION SELECT` — the top item | [`extras-wrap.png`](captures/menu-nav/extras-wrap.png) |
| **up / down** | one item per press, no auto-repeat at the durations tried | |
| **wrap at the top** | ⬆ from the first item goes to the **last** | [`wrap-montage.png`](captures/menu-nav/wrap-montage.png), panels 1→2 |
| **wrap at the bottom** | ⬇ from the last item goes to the **first** | same, panels 3→4, and 4 presses from `EXTRAS` landing on `OPTIONS` — i.e. wrapping — is what makes the count come out |
| **left / right** | **nothing**, on the main menu | cursor unmoved across one ⬅ and one ➡ |
| **Ⓑ on a submenu** | returns to the parent **with focus restored to the item you entered from**`LOAD GAME``LOAD GAME`, `TUTORIAL``TUTORIAL`, `OPTIONS``OPTIONS`, `EXTRAS``EXTRAS` | 4/4 |
| **Ⓑ on the main menu** | goes to the **title**, which re-draws `PRESS Ⓐ BUTTON` after a beat | |
| **Ⓑ on the title** | **nothing** | |
Wrap holds on both screens tested — the 5-item main menu and the 3-item `EXTRAS`
submenu — so it is a menu rule, not a per-screen table.
**🟡 Initial focus is reproducible but not established as invariant.** Both of my
boots opened on `TUTORIAL`, and both used `boot_menu.sh`. The run recorded in
[`menu-state-in-memory.md`](menu-state-in-memory.md) reached `EXTRAS` with *four*
downs from the main menu, which only works from `NEW GAME`. Either the harness
path matters or something persists. **Do not hardcode `TUTORIAL` without
re-testing it**; what is solid is that the menu does *not* open on the top item
in this harness.
## Q4 — where each button goes
Measured by driving: focus the item, press Ⓐ, read the screen's own title.
| button | screen it opens | evidence | GamePart id |
|---|---|---|---|
| `NEW GAME` | ❔ **not tested** | — | — |
| `LOAD GAME` | the save-slot list, `LOAD GAME` / `Current Storage` | [`q4-destinations.png`](captures/menu-nav/q4-destinations.png) left | 🟡 `3 GP_LOAD` |
| `TUTORIAL` | the lesson list, `TUTORIAL`, Level 1 / Level 2 | same, middle | 🟡 `25 GP_TUTORIAL` |
| `OPTIONS` | `OPTIONS` — GAME / CONTROL / SOUND / SCREEN SETTINGS / BACK | same, right | 🟡 `8 GP_OPTIONS` |
| `EXTRAS` | **`GP_TITLE.pak` build 6** — MISSION SELECT / MOVIE THEATER / BACK | [`ui-title-build-map.md`](ui-title-build-map.md) | 🟡 `5 GP_EXTRAS` |
| `EXTRAS ▸ MISSION SELECT` | the stage list + Wide Area Space Map | | 🟡 `7 GP_MISSION_SELECT` |
| `EXTRAS ▸ MOVIE THEATER` | ❔ not tested | | 🟡 `6 GP_MOVIE_THEATER` |
**Say which, as the gate asks.** The *screen* each button opens is **measured**
I pressed the button and read the title off the framebuffer. The **GamePart id is
not measured**: it is the entry of the decoded 29-id table at `.rdata 0x820A1630`
([`challenge-mission-gate.md`](challenge-mission-gate.md) §3) whose *name* matches
the screen I saw. The table is decoded; the *binding* of a button to an entry in
it is a name match I made by eye. The port should treat these ids as authored.
Worth noting that the ids and the paks are not one-to-one: `GP_EXTRAS` is id 5
with **no pak of its own** — its artwork is a build inside `GP_TITLE.pak`.
**`NEW GAME` was deliberately not pressed.** Ⓐ on it leads to a standing
black-screen hang that ends the run
([`ui-paint-order-third-permutation.md`](ui-paint-order-third-permutation.md)),
and this iteration needed the session. It is the one destination still unmeasured.
### The cheap way to finish this, and to make it a measurement
`0x828A690C` holds a **live screen id**`1` title, `3` main menu, `4` extras —
and `0x828F38AC` the cursor ([`menu-state-in-memory.md`](menu-state-in-memory.md)).
Reading those while pressing Ⓐ turns "the screen said OPTIONS" into a measured
transition, and works under `--gpu=null` with no screenshots at all. ⚠️ Note that
those values are **not** GamePart ids — `GP_TITLE` is GamePart 0 and `GP_EXTRAS`
is 5, but the word reads 1 and 4 — so it is a third enumeration and mapping it to
the id table is itself unfinished work.
## ✅ `NEW GAME` — measured 2026-08-28, and it is not a hang
The one destination this page could not test has been driven. **Ⓐ on `NEW GAME`
does not hang.** It opens two more menus first:
```
NEW GAME -> DIFFICULTY -> SELECT DATA -> guest crash
```
* **`DIFFICULTY`** — `EASY` / `NORMAL` / `HARD` / `BACK`, footer
`Ⓐ : OK Ⓑ : Back`, opening focused on **`NORMAL`**
([capture](captures/newgame-path/newgame-difficulty.png)). It sat unchanged for
90 s with the emulator healthy — a menu waiting for input, which is exactly
what "a standing hang" looks like to a screenshot loop that never presses
anything.
* Ⓐ on `NORMAL` → **`SELECT DATA`**, a save-slot picker headed
`Current Storage: Dummy HDD`, prompting to pick a file for the auto-save.
* Then the guest throws, and Xenia pauses with `PC: 0x82307128`
([capture](captures/newgame-path/newgame-selectdata-crash.png)).
**That crash is already in the corpus and is not new**: `0x82307128` is inside
`sub_823070B0`, the cache-manager STL erase documented in
[`title-crash-stl-tree.md`](title-crash-stl-tree.md), whose trigger is an
incomplete on-disc shader/code cache — not the menu path. The corpus also already
holds `captures/select-data-crash.png`.
So Q4's last row closes as **measured**:
| button | screen it opens |
|---|---|
| `NEW GAME` | **`DIFFICULTY`** (then `SELECT DATA`) |
🟡 The GamePart ids for these two are unmeasured, like the rest — `24 GP_DIALOG`
and `3 GP_LOAD` / `2 GP_SELECT_STORAGE` are name-match candidates and nothing
more.
### Initial focus — a fourth data point, and it still varies
This boot opened the main menu on **`NEW GAME`**. Running tally across four
boots of the same harness: `TUTORIAL`, `TUTORIAL`, `NEW GAME`, `NEW GAME`.
Unchanged conclusion: **do not hardcode it.**
### The `NEW GAME` path completes — the `SELECT DATA` crash is state, not path
A second run of the same path, 2026-08-28, **did not crash**:
```
NEW GAME → DIFFICULTY → (Ⓐ on NORMAL) → SELECT DATA → (Ⓐ on a slot) → a movie plays
```
The previous run's throw at `PC 0x82307128` is therefore **not inherent to this
menu path** — the same six presses got through it. That is consistent with the
trigger `title-crash-stl-tree.md` already names (an incomplete on-disc cache) and
with nothing about `NEW GAME`. 🟡 n = 1 either way; do not read it as "fixed".
Worth recording because the first observation could easily have hardened into
"the new-game path crashes", which is what "A on NEW GAME hangs" had already
become once.