`main_menu` -- the milestone's gate -- agrees with the reference renderer to within 3/255 on every channel of every pixel, RMSE 0.38 %, no pixel above 4 %. Nine of the twelve screens are at or under that; two are byte-identical. Three exceed it, and each gets a cause rather than a wider tolerance: * `title` (max 6): every disagreement is INSIDE A TIE -- the derived order and the CLI's measured-off-the-game order differ only among elements with identical layer keys. That is exactly the residual HANDOFF Q3 documents and the export already declares in `unresolved: paint_order_ties`. Cost: 904 px at 4-6/255 in one glow band. The port keeps the stable sort; fitting it to one screen's capture would be tuning. * `title_jp` (max 154): `ptlogo_eff2` at 125 % is the only drawn element in the whole export at a scale that is not a whole multiple of 100 %, and `title_jp` is the only screen over 6/255. Same fact twice. `ui_layout::blit` samples the source at the destination pixel's top-left corner; a GPU samples at its centre, and at 125 % those disagree on one column in five. I think the CLI is the one that is wrong -- corner-sampled nearest is a half-pixel bias toward the top-left that no rasteriser produces. But that is a reading, not a measurement: it needs a framebuffer capture of the Japanese title screen, so it is filed in BLOCKED.md as a question. The port is NOT changing to match, because matching would mean reproducing a half-pixel offset on purpose to make a number smaller. * `extras` (max 4): two pixels. Also reconciled: the pivot question predicted a P1 diff could not distinguish the declared pivot from half the texture, because both renderers use the declared one. That held. Recorded so the agreement is not later mistaken for evidence -- and P2 will not settle it either. BLOCKED.md's `/reborn` HEAD updated to bc6354d, with a note that the mount is read-only by design and `git -C /reborn pull` fails rather than being skipped.
100 lines
6.1 KiB
Markdown
100 lines
6.1 KiB
Markdown
# Waiting on the RE agent
|
||
|
||
What this port cannot do until an answer lands in
|
||
[`/reborn/docs/port/HANDOFF.md`](https://git.mc02.dev/fabi/Syplheed-Reborn).
|
||
Recorded so it is not re-discovered every iteration.
|
||
|
||
**None of these may be guessed.** A value invented here is indistinguishable from
|
||
a decoded one a month from now. Where a milestone can proceed with a placeholder,
|
||
the placeholder goes in `authored/` with a `why` naming the question it stands in
|
||
for, so it is deleted rather than forgotten when the answer arrives.
|
||
|
||
Last reconciled against HANDOFF.md on **2026-08-28**, at `/reborn` HEAD `bc6354d`.
|
||
(`/reborn` is mounted read-only, so `git -C /reborn pull` fails by design; the
|
||
mount is refreshed outside this container and HEAD is read, not fetched.)
|
||
|
||
## Still open — these block work
|
||
|
||
| Milestone | Needs | HANDOFF | State |
|
||
|---|---|---|---|
|
||
| P6 audio | which cue fires on move / confirm / back | Q8 | ❔ open. The cue table is complete; the **event binding is not**. P6 cannot bind a sound to a keypress without inventing it. |
|
||
| P6 audio | which BGM the menu plays | Q10 | ❔ **not on the disc.** All 32 banks are named `BGM_001`…`BGM_109` with no semantic name anywhere. The port is choosing a track, and that choice is authored. |
|
||
| P6 looping | where a menu loop restarts | Q10 | ❔ `BGM_001` fades out at 167.663 s into 6.15 s of silence, and no loop-point field has been identified. A menu loop is authored. |
|
||
| P4/P7 video | whether Ⓐ skips a movie | Q9 | 🟡 unsettled — the corpus says Ⓐ skips every time, the boot harness never taps during a movie because it breaks the title. P4 can play the movie; it cannot yet say what a button press does during one. |
|
||
| P5 `NEW GAME` | what Ⓐ on `NEW GAME` opens | Q4 | ❔ untested: Ⓐ on it **hangs the emulator**. The other four destinations are measured. |
|
||
| P3 sequencing | what code decides to advance the boot sequence | Q6 | 🟡 the order is observed and the attract cycle timed (~8–10 s idle → fade → `ADV.wmv` in full → title). The *driver* is not decoded. P3 can reproduce the observed behaviour and must say it is reproducing an observation. |
|
||
|
||
## Answered since this file was last written — no longer blocking
|
||
|
||
Q1 (keyframe time unit — linear ramp, 2 units per rendered frame, 1 unit = 1/60 s
|
||
*measured*), Q2 (which build is which screen), Q3 (paint order — a `u16` layer key
|
||
at `+0x0A`, **decoded**), Q5 (navigation: ⬆⬇ wrap, ⬅➡ nothing, Ⓑ up with focus
|
||
restored), Q7 (transitions: a fade through black, fade-in decoded, ~0.4 s fade-out
|
||
measured), Q9 (`ADVERTISE_MOVIE` → `ADV.wmv` is boot intro *and* attract; `MS00A` →
|
||
`S00A.wmv` is the new-game intro), Q10 (a bank is two stems played **together** —
|
||
do not concatenate), S1 (Ready Room: no-go).
|
||
|
||
Three of those are **measured**, not decoded, and so are authored here rather
|
||
than exported:
|
||
|
||
| Authored because it is not on the disc | HANDOFF | Where it lives |
|
||
|---|---|---|
|
||
| `1 keyframe unit = 1/60 s` | Q1 | not yet written — P2 |
|
||
| initial menu focus (not stable across boots; pick one and say so) | Q5 | not yet written — P5 |
|
||
| the ~0.4 s fade-out and the 0.17–0.23 s black hold | Q7 | not yet written — P3 |
|
||
|
||
## Questions this port has raised
|
||
|
||
Not blocking anything today; raised because the port found them and a guess here
|
||
would be believed later.
|
||
|
||
### Does the game sample a scaled sprite at the pixel corner or the pixel centre?
|
||
|
||
Found at P1, by the only screen it could have been found on. `title_jp`'s
|
||
`ptlogo_eff2` is the **single drawn element in the whole export** at a scale that
|
||
is not a whole multiple of 100 % (125 %), and `title_jp` is the only one of the
|
||
twelve screens whose Godot-vs-CLI diff exceeds 6/255.
|
||
|
||
The two renderers pick different source texels at a non-integer ratio.
|
||
`sylpheed_formats::ui_layout::blit` samples at the destination pixel's **top-left
|
||
corner** (`sxi = col * sw / dw`); a GPU samples at its **centre**
|
||
(`floor((col+0.5)*sw/dw)`). At 125 % they disagree on one column in five — ~30
|
||
pixels above 100/255, strung along thin diagonal edges. At every whole multiple
|
||
of 100 % they agree exactly, which is why the other eleven screens are clean.
|
||
|
||
The port has **not** changed to match: matching would mean reproducing a half-
|
||
pixel bias on purpose to make a number smaller. The question for the RE agent,
|
||
when it is cheap: **a framebuffer capture of the Japanese title screen** would
|
||
settle it outright, and it is the kind of thing a capture answers in one look.
|
||
|
||
Cost of being wrong either way: a one-texel edge on one glow, on a screen the
|
||
English boot path never shows. This is filed, not urgent.
|
||
|
||
### The pivot is not half the texture on `GP_TITLE`
|
||
|
||
`sylpheed-formats`'s `ui_layout::Element::pivot_x` is documented as "for a `.t32`
|
||
element this is exactly half the decoded texture's dimensions (verified 7/7 on
|
||
the tutorial bundle)". Counting it over the whole of `GP_TITLE` as exported:
|
||
|
||
* **55 of 93** sprite-bearing `.t32` elements match within ±1 px.
|
||
* **38 do not**, and several are not close: `ptlogo_back2` is 1118×262 with pivot
|
||
(500, 117) where half is (559, 131); `ptmsg` is 223×38 with pivot (123, 19)
|
||
where half is (111.5, 19) — the Y matches and the X does not.
|
||
|
||
This changes nothing today: the exporter emits the **declared** pivot and never
|
||
derives one, and the pivot only affects drawing when scale ≠ 100 %. But it does
|
||
matter, because scale is genuinely animated here — **177 keyframes** across
|
||
`GP_TITLE` are not 100 %, including on the title screen the port must draw at P1.
|
||
|
||
The question for the RE agent, when it is cheap to answer: **does the running
|
||
game anchor a scale to the declared pivot, or to half the texture?** The two
|
||
differ by up to 59 px on `ptlogo_back2`, which is visible. Until then the port
|
||
follows the decoders and uses the declared pivot, which is also what
|
||
`sylpheed-cli screen render` does — so a P1 diff cannot distinguish them, and
|
||
agreement between the two is not evidence.
|
||
|
||
**P1 has now been run and that prediction held.** The port and the CLI agree on
|
||
every scaled element across all twelve screens; the question is untouched by it.
|
||
It will stay untouched by P2 as well, since P2 animates the same two renderers'
|
||
shared assumption. Only a capture answers this.
|