docs/re: a second screen captured, and the two title states pinned down

Two results, one of which closes the navigation problem the last three
iterations kept hitting.

**The title states.** The hypothesis was that the attract-loop title is a
non-interactive presentation that omits the PRESS (A) plate. Half right:

* the state distinction is REAL — a single (A) on the title that ends the boot
  opens the main menu, 2 of 2 in independent runs, one of which never pressed
  F10; the title the attract loop returns to accepts nothing, not (A), START, B,
  BACK, X or Y, across dozens of delivered presses;
* the proposed tell is REFUTED — capturing the draws in both states in one run
  gives 13 quads at identical rects, ptbtn00 and ptbtn00f included. The two are
  identical to the renderer and different only to the guest.

So there is now a reliable route to the menu: first title after boot, one tap.

**The main menu's paint order**, captured with it. Its sprites are GP_TITLE
build 5's, and ptframe1/ptframe2/ptbtn01f land within 4 px of their declared
resting placements — an independent placement check on an untouched bundle.

It does NOT settle the ordering question, and the entry says so: build 5 lists
its background at indices 1-2, so declaration order and "background first"
predict the same sequence here. Same failure mode as GP_READY_ROOM/GP_OPTIONS.
What it does establish is that the title's disagreement is not a decode
artefact — same pak, same engine, one build that follows its table and one that
does not.
This commit is contained in:
Sylpheed RE agent
2026-08-18 23:10:04 +00:00
parent 4b0263b80f
commit 9e16331155
5 changed files with 125 additions and 13 deletions

View File

@@ -132,19 +132,29 @@ useless, it **breaks the run** — 88 presses left a black screen that never cam
back (no crash, no throw, the emulator healthy). The script no longer taps
during boot; the intro takes ~3.5 minutes and gets to the title by itself.
**So the difference is not the number of presses or the button.** The one
success came on a title that appeared ~83 s into a warm boot; the failures came
on titles that appeared after 292 s and a full attract cycle. The obvious
reading — that the attract-loop title is a non-interactive presentation and the
post-boot title is the interactive one — is a **hypothesis, unconfirmed**, and it
is what to test next.
**So the difference is not the number of presses or the button — it is which
title you are looking at**, and that is now measured rather than guessed:
* the title that **ends the boot sequence** accepts a single Ⓐ and opens the main
menu — **2 of 2**, in independent runs, one of which never pressed F10;
* the title the **attract loop returns to** accepts nothing — Ⓐ, START, B, BACK,
X, Y, dozens of presses, every one delivered, none swallowed.
**The recipe, then:** launch, wait for the first `title` classification, tap Ⓐ
once. Do not tap during the boot, and do not wait for a second title.
The tell is *not* visible in what the game draws — a `log_ui_draws` capture in
each state gives 13 quads at identical rects, `ptbtn00` (the `PRESS Ⓐ BUTTON`
plate) included in both. See
[`ui-title-paint-order-capture.md`](ui-title-paint-order-capture.md).
## Still open
Which title state accepts input, and how to tell them apart from outside. A
`log_ui_draws` capture in each state would say whether the two composite
differently (the interactive one draws `ptbtn00`, the `PRESS Ⓐ BUTTON` plate,
from build 2 — if the attract title omits or replaces it, that is the tell and it
is visible in one capture). Until that is pinned down, reaching the main menu is
a matter of luck, which is not a basis for the second screen's paint-order
capture.
**Why** the attract title stops accepting input, given that it draws exactly the
same thing. Nothing in the composition, the input path or the sign-in state
differs; the difference is in the guest's own state machine, and reading it means
reading that code.
Not open any more, and worth stating because it was the thing blocking the RE:
reaching the main menu is now routine (first title, one Ⓐ), and the second
screen's paint order has been captured with it.

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 KiB

View File

@@ -0,0 +1,40 @@
# every draw in SUBMISSION ORDER, undeduplicated, frames 1..4
# tex dimensions identify the sprite; base is the guest address
0 prim=8 indices=3 vs=0x0A6D1DD7767FDF27 ps=0x2E372EA28CC404B7
vb=0x14F993B8 stride=28 attrs=[57@0 38@12 ] fmt0=57 v: [-0.50,-0.50,z=0.00000] [1279.50,-0.50,z=0.00000] [1279.50,719.50,z=0.00000]
1 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14F99410 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000] [1.00,1.00,z=0.00000] [1.00,-1.00,z=0.00000] [-1.00,-1.00,z=0.00000]
2 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14F99470 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [1.84,1.58,z=0.00000] [2.38,1.02,z=0.00000] [1.54,-1.57,z=0.00000] [1.00,-1.02,z=0.00000] [-2.82,1.02,z=0.00000] [-2.38,1.81,z=0.00000] [-0.79,-1.02,z=0.00000] [-1.23,-1.81,z=0.00000]
3 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0AEF0000 1280x768 fmt=6]
vb=0x14F99530 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000] [1.00,1.00,z=0.00000] [1.00,-1.00,z=0.00000] [-1.00,-1.00,z=0.00000]
4 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0x5773DC18083C4C20
vb=0x14F99590 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000] [1.00,1.00,z=0.00000] [1.00,-1.00,z=0.00000] [-1.00,-1.00,z=0.00000]
5 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14F995F0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.64,1.00,z=0.00000] [0.64,1.00,z=0.00000] [0.64,-1.00,z=0.00000] [-0.64,-1.00,z=0.00000]
6 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0BA60000 1280x768 fmt=6]
vb=0x14F99650 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.54,1.00,z=0.00000] [0.54,1.00,z=0.00000] [0.54,-1.00,z=0.00000] [-0.54,-1.00,z=0.00000]
7 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14F996B0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.31,0.70,z=0.00000] [0.07,0.70,z=0.00000] [0.07,-0.08,z=0.00000] [-0.31,-0.08,z=0.00000] [-0.09,0.26,z=0.00000] [0.31,0.26,z=0.00000] [0.31,-0.60,z=0.00000] [-0.09,-0.60,z=0.00000]
8 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14F99770 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.18,-0.65,z=0.00000] [0.17,-0.65,z=0.00000] [0.17,-0.76,z=0.00000] [-0.18,-0.76,z=0.00000]
9 prim=13 indices=24 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C30000 1280x768 fmt=6]
vb=0x14F997D0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.16,0.42,z=0.00000] [-0.23,0.44,z=0.00000] [-0.21,0.57,z=0.00000] [-0.15,0.55,z=0.00000] [-0.16,0.57,z=0.00000] [0.17,0.57,z=0.00000] [0.17,0.42,z=0.00000] [-0.16,0.42,z=0.00000]
10 prim=8 indices=3 vs=0x72CBCAA6A7984111 ps=0xE59B2B3DA4AA9008 tex[base=0x10000000 1x1 fmt=26]
11 prim=8 indices=3 vs=0x72CBCAA6A7984111 ps=0xE59B2B3DA4AA9008 tex[base=0x10000000 1x1 fmt=26]
--- frame 3 ---
12 prim=8 indices=3 vs=0x0A6D1DD7767FDF27 ps=0x2E372EA28CC404B7
vb=0x14FD9B38 stride=28 attrs=[57@0 38@12 ] fmt0=57 v: [-0.50,-0.50,z=0.00000] [1279.50,-0.50,z=0.00000] [1279.50,719.50,z=0.00000]
13 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14FD9B90 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000] [1.00,1.00,z=0.00000] [1.00,-1.00,z=0.00000] [-1.00,-1.00,z=0.00000]
14 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14FD9BF0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.49,1.58,z=0.00000] [-0.95,1.02,z=0.00000] [-1.80,-1.57,z=0.00000] [-2.34,-1.02,z=0.00000] [-2.87,1.02,z=0.00000] [-2.43,1.81,z=0.00000] [-0.83,-1.02,z=0.00000] [-1.28,-1.81,z=0.00000]
15 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0AEF0000 1280x768 fmt=6]
vb=0x14FD9CB0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000] [1.00,1.00,z=0.00000] [1.00,-1.00,z=0.00000] [-1.00,-1.00,z=0.00000]
16 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0x5773DC18083C4C20
vb=0x14FD9D10 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000] [1.00,1.00,z=0.00000] [1.00,-1.00,z=0.00000] [-1.00,-1.00,z=0.00000]
17 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]
vb=0x14FD9D70 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.64,1.00,z=0.00000] [0.64,1.00,z=0.00000] [0.64,-1.00,z=0.00000] [-0.64,-1.00,z=0.00000]
18 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0BA60000 1280x768 fmt=6]
vb=0x14FD9DD0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.54,1.00,z=0.00000] [0.54,1.00,z=0.00000] [0.54,-1.00,z=0.00000] [-0.54,-1.00,z=0.00000]
19 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0C340000 1280x768 fmt=6]

View File

@@ -0,0 +1,13 @@
frame 1 draw 0 ( 0, 0) 1280x720 → 8AX 1280x720
frame 1 draw 1 ( 0, 0) 1280x720 → 8AX 1280x720
frame 1 draw 2 (1280,-209) 883x1134 ROT → ?
frame 1 draw 2 (-1165,-292) 1299x1303 ROT → ?
frame 1 draw 3 ( 0, 0) 1280x720 → 8AX 1280x720
frame 1 draw 4 ( 0, 0) 1280x720 → 8AX 1280x720
frame 1 draw 5 ( 230, 0) 819x720 → ?
frame 1 draw 6 ( 294, 0) 691x720 → ?
frame 1 draw 7 ( 442, 108) 243x281 → ptframe1.t32 247x281 (±4)
frame 1 draw 7 ( 582, 266) 256x310 → ptframe2.t32 257x311 (±1)
frame 1 draw 8 ( 525, 594) 224x40 → ptmsg.t32 223x38 (±2)
frame 1 draw 9 ( 493, 155) 51x54 ROT → ?
frame 1 draw 9 ( 538, 155) 211x54 → ptbtn01f.t32 216x56 (±5)

View File

@@ -264,3 +264,52 @@ What is established so far is small, and stated so it is not mistaken for more:
`sub_821B4498`, turns out to be a **time-string parser** (`MM:SS.mmm` — it
splits on `:` and `.` and multiplies by 60, then 100). The guest does not
necessarily index that table with a multiply at all.
---
## A second screen, and a second title state (2026-08-18, later still)
### The main menu's paint order
Reached and captured. Its sprites are `GP_TITLE.pak` **build 5**'s (the 16-element
menu build), and every identified quad lands within 4 px of its declared resting
placement — another independent check on the placement decode, on a bundle
nothing had touched:
| draw | quad | sprite | declared rest |
|---|---|---|---|
| 7 | (442,108) 243×281 | `ptframe1.t32` [6] | (445,108) |
| 7 | (582,266) 256×310 | `ptframe2.t32` [7] | (578,267) |
| 8 | (525,594) 224×40 | `ptmsg.t32` | — |
| 9 | (538,155) 211×54 | `ptbtn01f.t32` (focused NEW GAME) [10→focus] | (542,157) |
preceded by five full-screen layers and the rotated `ptloop` pair.
**And it does not discriminate**, which is the honest headline. The observed order
is *consistent* with build 5's declaration order — but build 5 lists its
background at indices 12, so "declaration order" and "background first" predict
the same thing here. It is exactly the failure mode `BACKLOG.md` recorded for
`GP_READY_ROOM` and `GP_OPTIONS`. What it does establish is that the title's
disagreement is not a decode artefact: same pak, same engine, two builds, and one
of them paints in an order its table does not describe.
### The two title states: identical to draw, different to press
The previous entry's hypothesis — that the attract-loop title is a
non-interactive *presentation* that omits the `PRESS Ⓐ BUTTON` plate — is
**half confirmed and half refuted**, and the halves matter:
***The state distinction is real.** A single Ⓐ on the title that ends the boot
sequence opens the main menu — **twice out of two**, in independent runs, one of
which never pressed F10 at all. On a title that the attract loop has come back
to, Ⓐ does nothing — as do START, B, BACK, X and Y — across dozens of presses,
every one delivered and none swallowed.
***The tell is not in the drawing.** Capturing `log_ui_draws` in both states
in one run gives **13 quads each, at identical rects**, `ptbtn00` and
`ptbtn00f` included. The two titles are pixel-identical apart from the phase of
the rotating effect. Whatever gates the button is invisible to the renderer.
So there is now a **reliable route to the main menu** — wait for the first title
after boot, tap Ⓐ once — which is what the second screen's capture needed, and it
is written into `tools/re-capture/`. Why the attract title stops accepting input
is still unexplained.