Files
Sylpheed/docs/port/HANDOFF.md
Sylpheed RE agent 88b3ce9af5 re: which GP_TITLE build is which screen, measured against the game
Q2. The archive is eight screens shipped twice, English and Japanese --
not the "build 4 title, 5 main menu, 6/8/9 submenus" the handoff claimed.
Build 8 is the JAPANESE main menu; 6 and 9 are the EN and JP EXTRAS, and
EXTRAS is the only submenu GP_TITLE holds. The PRESS (A) BUTTON plate is
its own build (2/3), composited over the title art and faded in a beat
later, not a state of build 4.

Confirmed by booting to the main menu and walking it: title, PRESS (A),
main menu and EXTRAS each match their render element for element. Builds
0/1 and 10/11 -- a DELTASABER / SYLPHEED A.I. plate -- were looked for in
the whole boot filmstrip, every title-side screen and the attract loop,
and appear in none of them; the reach of that negative is written down
rather than filled in with a guess.

Two rig traps went into METHOD: the menus drop d-pad presses shorter than
~0.3 s, and a grab 2.5 s after a transition can catch a screen mid-fade
-- which nearly wrote "the returned title has no plate" into the corpus.
2026-08-28 16:55:33 +00:00

7.4 KiB
Raw Blame History

Handoff — what the menu port needs, and where it stands

The single page the port agent reads. Everything here is produced by the container agent's reverse engineering; nothing here is a design decision about the port itself.

Keep it current. It is a summary with links into docs/re/, not a second copy of the findings — but an answer that is not reachable from this page has not been delivered.

How to read an answer

Every row below is one of exactly three things, and the distinction is the point:

meaning what the port should do
decoded a field on the disc, with a disc-wide check read it from the data
measured not on the disc in any form we found, but the running game does this hardcode it, and cite this page
undecodable we looked in these places, it is not there, here is the reach of the negative author it by hand, knowingly

There is no fourth kind. If a row says measured or undecodable, the port is authoring that value, not transcribing it — and it should be kept somewhere a human can see it is a human decision, so that when it is later decoded the authored version can be deleted.

Status

Question State Answer / link
Q1 keyframe time unit + ramp shape answered ramp is linear; the clock advances 2 units per rendered frame; working conversion 1 unit = 1/60 sui-keyframe-time-unit.md
Q2 which build is which screen state answered GP_TITLE is 8 screens shipped twice, EN/JP: 4/7 title art, 2/3 the PRESS Ⓐ plate, 5/8 main menu, 6/9 EXTRAS, 0/1 and 10/11 two unidentified DELTASABER plates — ui-title-build-map.md
Q3 paint order for the six screens open runtime-solved only; declaration table is refuted
Q4 button → GamePart open labels are baked into sprites
Q5 navigation semantics open
Q6 boot sequence + what drives it 🟡 partial order observed, and the attract cycle is timed: ~810 s idle on the title → fade to black → ~85 s of video → title again, plate and all. The driver is still not decoded
Q7 transitions open
Q8 menu audio bindings open cue table complete, event binding is not
Q9 video binding + playback rules 🟡 partial ADV.wmv is the boot intro; new-game intro unidentified
Q10 music-bank sub-wave roles (intro+loop?) open we concatenate blindly today
S1 Ready Room go/no-go open probe not run

Already settled — the port can rely on these today

  • GP_TITLE.pak is eight screens, each shipped twice — English and Japanese. Build 4 is the English title art and 7 its Japanese twin; 2/3 are the PRESS Ⓐ BUTTON plate, a build of their own composited over the title and faded in a beat later; 5/8 are the five-button main menu; 6/9 are the EXTRAS submenu — the only submenu inside this archive. Builds 0/1 and 10/11 are a DELTASABER / SYLPHEED A.I. plate that was never seen running, in the boot path, any title-side screen, or the attract loop. measured against live captures for the four English screens the boot path shows; ui-title-build-map.md. Withdrawn: the earlier "builds 6/8/9 are submenus" — 8 is the Japanese main menu. The other four main-menu buttons leave the archive (GP_SAVE_LOAD, GP_TUTORIAL, GP_OPTIONS, GP_MISSION_SELECT are the likely destinations by name — an inference, not a measurement).
  • Buttons are identifiable as data. Element kind 0x3002 = button, 0x0 = decoration, 0x10 = primitive. decoded.
  • Menu order is geometric. Buttons sorted top-to-bottom by resting Y. This is correct for a vertical menu and is not a decoded neighbour graph — the disc's real navigation structure is unknown, and opt is not a focus link (measured and refuted, see ui-focus-and-effect-elements.md).
  • Highlighted states pair by nameptbtn01.ratptbtn01f.rat. 🟡 a naming convention that holds for all 54 real pairs, not a decoded field.
  • The resting pose is the hold, not the first, last or longest-dwell keyframe; a keyframe is the start of a ramp. ui-resting-pose.md.
  • That ramp is linear, and it runs at 2 keyframe time units per rendered frame. Measured frame-by-frame off the running game's own draw stream: a declared 15-unit fade lands on round(255·k/15) for all seven of its samples, with k stepping 2, 4, 6, 8, 10, 12, 14 on seven consecutive submitted frames. measured, not decoded — the disc says t=30, it does not say what a t is. The seconds conversion (1 unit = 1/60 s, so a 30 fps screen) rests on a measured 27.6 present-frames/second and is the one part still worth re-testing; ui-keyframe-time-unit.md names the test. If it turns out the game presents at 60 Hz, every duration halves — nothing else on this page changes.
  • The GamePart id table — 29 entries at .rdata 0x820A1630, confirmed by the executable's own registration strings. This is the screen vocabulary; which button reaches which entry is Q4 and is not part of it.
  • The logo splash is a screen, not a video. logo1logo4 are manifest-bound with no .wmv on the disc.
  • Sprites carry their own labels. No font rendering or localisation is needed for this milestone. — and the localisation is already baked in: the Japanese screens are separate builds in the same pak, not a text swap.

Facts the port will trip over

  • ADV.wmv is WMV3 video + WMA Pro audio, 1280×720 at 30 fps, 137 s. Godot 4 plays only Ogg Theora natively. How to handle that is the port's decision, not ours — but it is not optional.
  • The disc holds 3.3 GB of video. Only the boot intro and the one new-game intro are in scope.
  • Static.slb over-declares its size by 616 768 bytes — it is the highest-offset entry in sound.pak and its size field is an allocation size. A reader must allow a short read there and only there.
  • Voice downmixes to mono, music does not. The left-channel downmix is correct for spoken lines and discards half a music mix.
  • A music bank has several sub-waves and we glue them together. BGM_001 is 10 KB + 4.47 MB + 4.67 MB, concatenated into one 347 s track. Nobody has established whether those are intro + loop, two variations, or two halves — see Q10. Do not build menu looping on the concatenated track until it is answered.
  • JNGL_001.slb does not decode. One bank in 9 519; its payload is not a whole number of XMA1 packets from any known data offset.

Reference data

Committed alongside the findings, so the port can be built without a disc in the loop during development:

  • sylpheed-cli screen info --build <n> GP_TITLE.pak — the element table, per build, with pivots, kinds, focus links, keyframes and resting poses.
  • sylpheed-cli screen render — the reference composite. When the port draws a screen, this is what it should be diffed against; where they disagree, one of them is wrong and the disagreement is worth reporting back.
  • docs/re/captures/ — framebuffer captures of the real screens, for anything that has to be checked against the game rather than against our renderer.