Files
Sylpheed/docs/port/options-screens.md
Sylpheed port agent 41f13318f4 port(exporter): 0x3003 is a button too -- the OPTIONS menu navigates
The Decoder decoded bit 0 of kind as the PARENT FLAG, disc-wide: kind & 1 agrees
with 'has a parent' on 15493 elements, zero disagreements. So 0x3003 is 0x3002
parented, and carries no role information -- the OPTIONS rows were never a
different class, they just have a parent.

Detector now matches 0x3002 | 0x3003 as TWO LISTED VALUES, not a mask.
kind & 0xFFFE == 0x3002 would also match 0x73002/0x73003 -- 160 elements whose
0x70000 bits are undecoded -- silently, on screens neither agent has looked at.
Excluded by construction until somebody decides deliberately.

Impact measured BEFORE re-exporting: exactly two screens gain buttons, options
and options_jp, five rows each. No existing screen changes.

Verified: main_menu -> down x3 -> (A) -> OPTIONS, then down x2 moves
po_menu_btn2 -> po_menu_btn3, focus ring rendering on the highlighted row.

📌 Waiting was right. The rule I rejected -- 'carries a focus record therefore is
a menu item' -- would have reached this answer by a second inference from
structure and reclassified elements on unseen screens. The field cost one
question and needed no inference.
2026-09-03 19:21:32 +00:00

5.9 KiB

The OPTIONS menu tree exists, renders, and is named

2026-09-03. GP_OPTIONS joined export_archives and produced 14 screen builds. All 14 render; all 14 are now named.

What they are

entry name English entry name
19 options the root — GAME / CONTROL / SOUND / SCREEN SETTINGS, BACK 21 options_jp
16 game_settings Auto-Save, View Point, Radio Log, Subtitles 18 game_settings_jp
4 control_settings Control Type, Throttle, sensitivities, Vibration 8 control_settings_jp
3 sound_settings Music / Movie / Voice / SFX Volume 5 sound_settings_jp
6 screen_settings Gamma Correction, R/G/B, NEXT PAGE 9 screen_settings_jp
7 screen_settings_page2 White / Black Level Adjust, PREVIOUS PAGE 10 screen_settings_page2_jp
20 control_customize per-action key remapping 22 control_customize_jp

A clean EN/JP pair for every screen, which is itself a check: 14 builds, 7 pairs, no leftovers.

How they were identified, and why that is stronger than usual here

By the text the screen renders about itself. Each was exported, drawn by the port at rest, and read: the titles and row labels are legible.

📌 That matters because this project has been bitten three times by identification via position, size or ordinal — the sweep strips confused by size, the plate identified by screen position, ptcopyright mistaken for the plate. A screen that renders the words SOUND SETTINGS above four volume rows is not that kind of inference.

⚠️ What it still does not establish: which screen the game navigates to from which. The tree above is read off content, so control_customize being "reached from CONTROL SETTINGS" is a reading of its own legend (Ⓨ : Customize on control_settings), not a measured transition. Wiring anything beyond main_menu → options needs the real navigation.

Not yet done

  • Nothing is reachable yet. main_menu ptbtn04 still has goto: null.
  • po_pad_slider1 has no sprite in the export and reports NOT DRAWN.
  • All 14 are NEVER COMPARED by verify-screen — reported, not asserted; both its allowance and the reference renderer were calibrated on GP_TITLE.
  • The screens are static: no navigation, no focus movement, no value editing.

OPTIONS is reachable — and navigation inside it is blocked on a kind

main_menu ptbtn04 now has goto: "options". Walked with the menu harness: main_menu → ⬇⬇⬇ → Ⓐ → the OPTIONS root renders. Ⓑ backs out.

RESOLVED — the rows move. 0x3003 is 0x3002 with the parent bit set

The Decoder decoded it disc-wide: bit 0 of kind is the PARENT FLAG, and it carries no role information. Over every .pak in dat/, kind & 1 agrees with "has a parent" on 15 493 elements with zero disagreements (docs/re/ui-kind-bit0-is-has-parent.md). The OPTIONS rows are parented; the main-menu buttons are not. Same record class.

So the detector now matches 0x3002 | 0x3003two values listed, not a mask. kind & 0xFFFE == 0x3002 would also catch 0x73002/0x73003, 160 elements whose high bits nobody has decoded, silently and on screens neither agent has seen.

Impact measured before re-exporting, not after: exactly two screens gain buttons — options and options_jp, five rows each. No existing screen changes.

Verified by walking it: main_menu → ⬇⬇⬇ → Ⓐ → OPTIONS, then ⬇⬇ moves po_menu_btn2po_menu_btn3 with the focus ring rendering on the highlighted row.

📌 The port was right to wait. The rejected rule — "carries a focus record ⇒ menu item" — would have reached the same answer here by a second inference from structure, and would have reclassified elements on screens nobody had looked at. The field cost one question and needed no inference at all.

The original section, kept for the shape of the block

The exporter's button detector is kind == 0x3002 && !focused. The OPTIONS rows are kind_raw = 0x3003, so role comes out unknown, the export's buttons[] is empty, and up/down move nothing.

screen element kind focus record in buttons[]
main_menu ptbtn01 0x3002 yes yes
extras ptbtn11 0x3002 yes yes
options po_menu_btn1 0x3003 yes no

What 0x3003 means is not the port's to decide, so the rule was not widened here. The circumstantial case is strong — five rows, each carrying a focus record, on a screen whose own text lists five options — and circumstantial is precisely the standard that has cost this project three separate retractions. Asked of the Decoder.

⚠️ A tempting alternative rule is "an element with a focus record is a menu item", which fits both screens. It is still an inference about semantics from structure, and it would silently reclassify elements on every screen in the export. Not taken.

The workflow cost this exposed, worth knowing before repeating it

A screen name is authored data, but it only reaches the port through a full re-export — which re-transcodes both movies. Renaming one screen costs the whole tree. Not worth fixing today; worth knowing before anyone plans a naming pass.

🔴 And a genuinely dangerous mistake, recorded because it nearly cost the session

Killing a background check with pkill -f "check-all" matched the container's own entrypoint, whose command line contains the loop prompt — and that prompt mentions check-all. pgrep duly reported the process as still running after it had stopped, and a pkill -9 on that pattern could have killed the session itself.

Match a process by its actual comm, or list with ps and check, before sending a signal. A pattern that appears in your own instructions is not a pattern that identifies a process.