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/ui-title-build-map.md
Sylpheed RE agent a048910497 re: the loop record is located, its cycle is still not readable
Continuing the one gap from last iteration -- turning the title's
measured 2.2 s loop into a decoded cycle. It did not turn.

The record itself is found and partly confirmed. ptloop01.rat is an
opt-linked leaf RATC at 0xbb5966 in build 4, placing pteff03.t32, with
0x1e -- thirty -- in the high half of the word at +0x004, which is the
~30 keyframes ui-rat-layout.md predicts for a loop record. Its pivot
fields read 200 and 90, matching exactly what screen info prints for
ptloop01, so this is the right blob and the header offsets hold.

The times are not there. A build's keyframes are 40-byte blocks with the
time at +36; scanning every 4-byte-aligned start across a 0xC0 window for
29 strictly increasing values at that stride finds nothing, in either
loop record. So a leaf record's keyframe layout is NOT the build
placement layout, which is now a line in REFUTED because it is the
obvious first assumption and it is wrong.

The 2.2 s stays measured and the port hardcodes it. What the next attempt
inherits is the record's address, a confirmed pivot, and one layout ruled
out -- which is the useful part of a negative.
2026-08-28 20:49:11 +00:00

266 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Which `GP_TITLE` build is which screen — measured against the running game
**Status:** ✅ `CONFIRMED` for the four screens the boot path actually shows
(title art, `PRESS Ⓐ BUTTON`, main menu, `EXTRAS`); 🟡 `PROBABLE` for their
Japanese twins; ❔ open for the two `DELTASABER` plates.
Answers [MISSION Q2](../port/MISSION.md). The previous statement — *"build 4
title, 5 main menu, 6/8/9 submenus"* — is **partly wrong** and is withdrawn:
build 8 is the **Japanese main menu**, not a submenu, and `GP_TITLE` holds
exactly **one** submenu (`EXTRAS`), in two languages.
## The archive is eight screens, each shipped twice
`GP_TITLE.pak` has 16 entries; `sylpheed-cli screen list` calls 12 of them
composable builds. The 16 fall into **eight pairs**, and each pair's two members
have near-identical sizes and name hashes that differ by a constant — one
character of the name apart:
| entry | hash | bytes | build idx | pair |
|---|---|---|---|---|
| 0 | `01a2db9c` | 483 958 | 0 | A |
| 1 | `0ff0b8a8` | 483 958 | 1 | A |
| 2 | `285d8849` | 267 014 | 2 | B |
| 3 | `369773cb` | 267 014 | 3 | B |
| 4 | `a60fcb85` | 12 278 666 | 4 | C |
| 7 | `b483e6e6` | 13 363 328 | 7 | C |
| 5 | `a715f485` | 6 977 437 | 5 | D |
| 8 | `b58a0fe6` | 6 931 653 | 8 | D |
| 6 | `a81c1d85` | 6 549 126 | 6 | E |
| 9 | `b69038e6` | 6 548 438 | 9 | E |
| 10 | `cdba806e` | 426 473 | — | F |
| 13 | `db2ea1f8` | 423 333 | — | F |
| 11 | `cec0a96e` | 999 643 | — | G |
| 14 | `dc34caf8` | 999 643 | — | G |
| 12 | `cf2a8ccd` | 1 774 639 | 10 | H |
| 15 | `dd56d99b` | 1 774 639 | 11 | H |
For the three pairs whose members differ visibly — C, D, E — **the difference is
English versus Japanese**: build 7 is the title art with the katakana subtitle
プロジェクト シルフィード, build 8 the main menu reading 新規 / ロード /
チュートリアル / オプション / エクストラ, build 9 the `EXTRAS` submenu as
エクストラ. That is the whole of the language split we can see. In pairs A, B and
H the two members render **byte-identical PNGs** — the archive still carries two
copies, but the artwork does not change with the language.
Pairs F and G are the four entries `screen list` does *not* classify as builds by
default. **They are the developer splash**, and they render — see below.
## The map
Contact sheet of every render:
[`captures/title-builds/title-build-contact-sheet.png`](captures/title-builds/title-build-contact-sheet.png).
| build | what it is | confirmed how |
|---|---|---|
| 0, 1 | a `DELTASABER / SYLPHEED A.I.` plate low-left on black, no background | ❔ **not observed running.** Never seen in the boot path, the main menu, `EXTRAS` or `MISSION SELECT` |
| **2**, 3 | the `PRESS Ⓐ BUTTON` plate — **an overlay build of its own**, not a state of build 4 | ✅ seen composited over build 4 on the live title, at the same rect our render puts it |
| **4** | title art, English (`PROJECT SYLPHEED`, ™, `(C)2006,2007 SQUARE ENIX`) | ✅ [`live-title-press-a.png`](captures/title-builds/live-title-press-a.png) |
| 7 | the same, Japanese | 🟡 renders as the JP twin of build 4; the container runs an English locale, so it was not seen |
| **5** | main menu, English: NEW GAME / LOAD GAME / TUTORIAL / OPTIONS / EXTRAS, footer `Ⓐ : OK` | ✅ [`live-main-menu.png`](captures/title-builds/live-main-menu.png) — element for element |
| 8 | the same, Japanese | 🟡 as above |
| **6** | the `EXTRAS` submenu, English: MISSION SELECT / MOVIE THEATER / BACK, footer `Ⓐ : OK Ⓑ : Back` | ✅ [`live-extras.png`](captures/title-builds/live-extras.png) |
| 9 | the same, Japanese | 🟡 as above |
| 10, 11 | the same `DELTASABER` plate as build 0, over a dark circuit-line background | ❔ **not observed running** |
## ✅ The splash — the four "non-build" entries, rendered
`screen list --all` widens the enumeration to every composable bundle and shows
all **16** entries. The four that the default listing drops are the two halves of
the developer splash, each shipped twice:
| entry | elements / sprites | what it is |
|---|---|---|
| **10, 13** | 3 / 2 | the white **`SQUARE ENIX`** publisher logo |
| **11, 14** | 7 / 6 | **`GAME ARTS` / `SETA` / `studio anima`** — the developer logos |
[`splash-entries-rendered.png`](captures/title-builds/splash-entries-rendered.png).
Rendered with `screen render --all --primitives --black`. Entry 11's seven
elements are the three logos, their three `_eff` glows and the
`palogo_eff0.prm` black backdrop — exactly the composition
[`structures/ui-paint-order-key.md`](structures/ui-paint-order-key.md) measured
for the splash.
### ✅ Confirmed against the running game — 2026-08-28
The 🟡 above ("no framebuffer capture to diff against") is closed. Recording the
boot from the moment the window appears, at 2 fps, catches the splash before the
movie:
[`live-splash-publisher.png`](captures/title-builds/live-splash-publisher.png),
[`live-splash-developer.png`](captures/title-builds/live-splash-developer.png).
Edge-correlated against the renders, **with the other half as a negative
control**:
| capture | vs entry 10 | vs entry 11 |
|---|---|---|
| publisher frame (t ≈ 2.0 s) | **0.9146** @ (0,0) | 0.027 ✗ |
| developer frame (t ≈ 6.0 s) | −0.033 ✗ | **0.9792** @ (0,0) |
Both halves match their own render at zero shift and are firmly rejected by the
other. The `13`/`14` twins score 0.876 / 0.966 — near-identical artwork, so this
test cannot tell a pair apart, only a screen from a different screen.
### ✅ The splash's timing is DECODED, and the capture confirms it
Re-recorded at **10 fps** (the 2 fps pass below was ±0.5 s and could not see
ramps at all). The splash **fades, both ways** — it does not cut — and the
bundle's own keyframes say so:
```
$ sylpheed-cli screen info --all --build 10 GP_TITLE.pak
1 palogo_sqex.t32 7 kf [15 30 235 239 251 255 -]
2 palogo_sqex_eff.t32 4 kf [15 30 45 -] (the glow, child of 1)
$ ... --build 11
1 palogo_gamearts.t32 7 kf [15 30 190 194 206 210 -] (seta, anima identical)
2 palogo_gamearts_eff 4 kf [15 30 45 -]
```
Under Q1's `1 unit = 1/60 s`:
| | declared | measured at 10 fps |
|---|---|---|
| `SQUARE ENIX` ramp in | `15 → 30` = 0.25 s | rise 0.4 → 0.8 s |
| `SQUARE ENIX` hold | `30 → 235` = **3.42 s** | ≈ 3.5 s (0.8 → 4.3 s) |
| `SQUARE ENIX` fade out | `235 → 255` = **0.33 s** | **≈ 0.3 s** (4.4 → 4.7 s) |
| developer hold | `30 → 190` = **2.67 s** | ≈ 2.4 s (5.6 → 8.0 s) |
| developer fade out | `190 → 210` = **0.33 s** | **≈ 0.3 s** (8.1 → 8.4 s) |
The offset between declared and measured start is ≈ 0.35 s, which is simply that
the recording's `t = 0` is when the *window* appears, not when the guest starts
drawing. Everything downstream of that lines up.
**The overshoot is the glow.** The measured rise peaks (6.21) at 0.8 s and settles
back (5.39) by 1.1 s, which looks like a bloom. It is the `_eff` child element:
its keyframes are `15 → 30 → 45`, so it ramps in *after* the logo and then back
down, while the logo itself holds. Decoded, not a rendering artifact.
So the port can **read** the splash's timing off the disc rather than author it —
the first screen's animation is not a measurement it has to trust.
### The wall-clock sequence, for orientation
| | |
|---|---|
| `SQUARE ENIX` on screen | **≈ 0.5 → 4.0 s** after the window appears |
| black | ≈ 4.5 s |
| `GAME ARTS` / `SETA` / `studio anima` | **≈ 5.0 → 7.5 s** |
| black | ≈ 9.0 s |
| `ADV.wmv` begins | **≈ 9.5 s** |
⚠️ The frames at ≈ 9.5–12.5 s show `SQUARE ENIX` again in **cyan**. That is not a
third splash — it is the intro movie's own opening, which the milestone-2 notes
describe as "white SQUARE ENIX + cyan glow + red diamonds". A capture-only reading
would have recorded a third logo screen that does not exist.
**So the first of the five screens now has a reference composite, a framebuffer
capture, and its on-screen durations.**
**Reach of the two negatives.** Builds 0/1 and 10/11 were looked for in: the whole
boot sequence (a 5 s-cadence filmstrip from launch to the title, ~190 s), the
title, the main menu, the `EXTRAS` submenu, the `LOAD GAME` slot list, the
transition into `MISSION SELECT` (a 40-frame burst), and the attract cycle. They
appear in none of them. The obvious remaining candidate is a *long* load — a
mission launch — which is out of this objective's scope; they are most likely a
loading/AI-chatter plate. That is a hypothesis, not a result.
## Three things the captures settle beyond the map
**The live title is two builds composited.** Build 4 draws the art; build 2 draws
`PRESS Ⓐ BUTTON` on top, and it **fades in a beat later** — a screenshot taken
2.5 s after arriving at the title has the art and no plate, one taken ~1 s later
has both. The port must treat the plate as its own timed element.
**The attract-loop title carries the plate too.** After ~8–10 s idle the title
fades to black, a full-motion video plays for ~85 s, and the title comes back —
*with* `PRESS Ⓐ BUTTON`
([`live-attract-title-press-a-band.png`](captures/title-builds/live-attract-title-press-a-band.png)).
This is consistent with, and adds nothing to, the draw-quad comparison in
[`canary-scripted-input-traps.md`](canary-scripted-input-traps.md): the plate is
not the tell that distinguishes the boot title from the attract title.
**`EXTRAS` is the only main-menu destination inside `GP_TITLE`.** Ⓐ on `EXTRAS`
opens build 6 — measured. The other four destinations leave the archive: Ⓐ on
`LOAD GAME` opened a `LOAD GAME` slot list, and Ⓐ on `MISSION SELECT` inside
`EXTRAS` opened a `MISSION SELECT` screen, neither of which is a `GP_TITLE`
build. `dat/` carries `GP_SAVE_LOAD.pak`, `GP_TUTORIAL.pak`, `GP_OPTIONS.pak`,
`GP_MISSION_SELECT.pak` and `GP_MOVIE_THEATER.pak`; **that those are the archives
behind the other four buttons is an inference from the names, not a measurement.**
## How to reproduce
```bash
sylpheed-cli screen list "$SYLPHEED_DISC/dat/GP_TITLE.pak"
sylpheed-cli screen render --build 6 "$SYLPHEED_DISC/dat/GP_TITLE.pak" /tmp/b6.png
tools/re-capture/boot_menu.sh q2 # boots to the main menu, cursor on NEW GAME
tools/re-capture/pad.py dpad down 0.35 # x4 -> EXTRAS
tools/re-capture/pad.py tap A 0.30
```
Mind the d-pad hold — see [`METHOD.md`](METHOD.md).
## ✅ The title is not a still image — it loops, ≈ 2.2 s
Recording the title at 10 fps for 22 s shows the screen **never settles**. After
the build-in it oscillates by about ±0.5 in mean luminance, continuously:
```
peaks at 5.6 7.8 10.0 12.7 15.2 17.1 19.2 21.3 s
intervals 2.2 2.2 2.7 2.5 1.9 2.1 2.1
mean 2.24 s
```
**measured**, n = 7 intervals, spread 1.9–2.7 s — peak-picking a low-amplitude
signal is coarse, so read it as **≈ 2.2 s ± 0.4**, not a precise period.
The mechanism is already decoded: build 4 declares **`ptloop01.rat` /
`ptloop02.rat`**, and `loop*.rat` is a **looping sprite animation** rather than a
composition ([`INDEX.md`](INDEX.md), UI screen layout row). So the title carries a
looping element by construction; what is new is that it runs at ≈ 2.2 s and never
stops.
### ❔ The loop record was opened, and its cycle is still not readable
The `.rat` was located and partly confirmed, but its **keyframe times are not**.
`ptloop01.rat` is an **`opt `-linked leaf record**, not a nested build: in build 4
the chunk `opt ` (size `0x0c`) carries the name `ptloop01.rat`, immediately
followed by a `RATC` blob at **`0xbb5966`**. `ptloop02.rat` is the same shape at
`0xbb5a82`.
| offset | value | |
|---|---|---|
| `+0x004` | `0x001e0000` — **30** in the high half | the ~30 keyframes [`structures/ui-rat-layout.md`](structures/ui-rat-layout.md) predicts |
| `+0x014` | `1` | name count |
| `+0x018` / `+0x01c` | `1280` / `720` | design space |
| `+0x020` | `pteff03.t32` (`pteff03a.t32` for loop02) | the sprite it places |
| `+0x050` / `+0x054` | `200` / `90` | pivot — **matches `screen info`'s `pivot (200,90)` for `ptloop01`**, which confirms this is the right record |
**But the times are not where a build's are.** A build's keyframes are 40-byte
blocks with the time at `+36`. Scanning every 4-byte-aligned start across
`+0x60 … +0x120` for 29 strictly-increasing values at a 40-byte stride finds
**nothing**, in either record. So a leaf record's keyframe layout is *not* the
build placement layout, and the loop's declared cycle cannot be read by that
route.
**The ≈ 2.2 s therefore stays measured, not decoded.** What a future attempt
gains from this one is the record's address, the confirmed pivot, and one layout
ruled out.
**For the port:** drawing build 4's resting pose and stopping will look wrong —
the title has a continuous ≈ 2.2 s loop over it.
### ❔ The declared 4.08 s build-in was not tested
That was the intent of this recording and it did not work. The title was reached
by **skipping the movie with Ⓐ**, which cuts to black and brings the title up on a
path that may not be the normal one; and the visible rise (≈ 2.7 s, from t ≈ 0.8
to 3.5) is a *luminance* curve, which
[`screen-transitions.md`](screen-transitions.md) already establishes is **not**
the fade quad's ramp. So ≈ 2.7 s neither confirms nor contradicts build 4's
declared `16 → 261` (4.08 s); the two are not measuring the same thing.
Testing it properly needs the title reached **without** a skip, and a way to
separate the quad from the elements — neither of which this recording had.