The copy of sylpheed-cli in this container was built 2026-08-29 12:38, before the keyframe-record-layout fix. The old parser shifted every time by one slot and could not time a group's final pose, printing a trailing '-': stale pteff00.prm 4 kf rest t=70 [12:0,0 70:0,0 80:0,0 -:0,0] fresh pteff00.prm 4 kf rest t=12 [ 0:0,0 12:0,0 70:0,0 80:0,0] Both outputs are well-formed and neither announces its age. That refutes the premise of screen-transitions.md's 2026-08-29 section, which argued from 'there is exactly one untimed keyframe, and every element has it'. There is no untimed keyframe, so the question it answered -- is 0.4 s the missing duration of that keyframe -- has lost its subject. The ratio test in the same section is untouched. And it decodes the number the port asked about: pteff00.prm's final ramp is 70 -> 80 = 10 units, about 0.167 s, not the ~24 this page authored. I tried to refute the port's 10 against the bytes and could not. So the measured ~0.4 s is NOT the ramp alone -- 24 units measured against 10 decoded. That the remaining ~14 units are exactly the black hold is arithmetic that fits (0.233 s, inside this corpus's own 0.17-0.23 s plateau) and is NOT a measurement; the decomposition stays open. CONTAINER-NOTES gains the trap. Renders are byte-identical across the two binaries (max per-channel difference 0 on GP_TUTORIAL build 0), so element identity, pivots, keyframe counts and screen render output are unaffected -- it is the times that move. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
9.2 KiB
What happens between two screens — a fade through black, and where its timing lives
Status: ✅ CONFIRMED. The quad and its ramp are decoded (a keyframe
group on the disc, with a disc-wide check); the wall-clock timings are
measured off the running game at 30 fps. One piece is undecodable from this
field and is called out below.
Answers MISSION Q7.
The mechanism — decoded
Every title-side screen carries a full-screen untextured primitive that is
black, and paints last: pteff00.prm in GP_TITLE, pfeff00.prm in
GP_SAVE_LOAD. That it sorts last was already established
(structures/ui-paint-order-key.md); what is
new here is that its keyframe group is the transition.
The group is always four blocks, and always this shape:
| block | alpha | meaning |
|---|---|---|
| 1 | 0xff at t = T0 |
the screen starts black |
| 2 | 0x00 at t = T1 |
ramp to fully clear — the screen fades in |
| 3 | 0x00 at t = T2 |
clear; this is the resting pose, the quad is invisible |
| 4 | 0xff, no time |
ramp back to black — the screen fades out on exit |
Read with the corpus's rule that a keyframe is the start of a ramp
(structures/ui-resting-pose.md).
$ tools/re-capture/fade_quads.py 4 5 6 # GP_TITLE
build 4 (title) pteff00.prm t=16 α=255 t=261 α=0 t=269 α=0 t=— α=255
build 5 (main menu) pteff00.prm t=12 α=255 t= 70 α=0 t= 80 α=0 t=— α=255
build 6 (EXTRAS) pteff00.prm t=12 α=255 t= 64 α=0 t= 74 α=0 t=— α=255
Under Q1's 1 unit = 1/60 s: the screen holds black
for 0.20 s, then fades in over 0.87 s (EXTRAS), 0.97 s (main menu)
or 4.08 s (the title).
❔ The fade-OUT duration is not in this field
The fourth block has no time — a group's last block stops 4 bytes short and
that word is already the next group's element index
(ui_layout.rs documents the
packing). So the disc gives the ramp's target (black) and not its length. That
duration is measured below, and the port is authoring it.
The disc-wide check, and what it shows about overlays
Over every GP_*.pak, counting bundles that have a .prm element and ≥8
elements (screen-sized rather than a two-element fragment):
40 of 97 carry a 255 → 0 → 255 quad; 56 of the 60 found disc-wide have exactly 4 keyframes.
41 % sounds weak until it is read per pak, where it is nearly all-or-nothing:
| pak | with quad / screen-sized |
|---|---|
GP_MISSION_SELECT, GP_MOVIE_THEATER, GP_OPTIONS, GP_TUTORIAL, GP_SYSTEM |
2/2 each |
GP_BUNK, GP_CHALLENGE |
6/6 |
GP_STAGE_CLEAR |
4/4 |
GP_SAVE_LOAD |
10/12 |
GP_TITLE |
6/12 |
GP_DIALOG |
0/133 |
GP_DEBRIEFING_PILOTLOG |
4/102 |
GP_TITLE's 6 of 12 is the interesting row, and it is not a gap. The six
that carry the quad are exactly the six screen builds — title, main menu and
EXTRAS, English and Japanese. The six that do not are exactly the six
overlays: the PRESS Ⓐ BUTTON plate and the two DELTASABER plates
(ui-title-build-map.md). An overlay composited onto a
screen has no transition of its own, so it has no fade quad — which is
independent corroboration that those builds are overlays rather than screens.
GP_DIALOG's 0/133 says the same thing about dialog boxes.
The timing — measured
Recorded with ffmpeg -f x11grab -framerate 30 over the game surface, mean
frame luminance per frame; raw data in
captures/transitions/transition-luminance.csv,
filmstrip in
transition-filmstrip.png.
main menu → EXTRAS (Ⓐ) |
EXTRAS → main menu (Ⓑ) |
|
|---|---|---|
| press → first visible change | 0.07 s | 0.37 s |
| fade-out to black | 0.367 s | 0.400 s |
| pure black (luminance 0.02) | 0.233 s | 0.167 s |
| luminance rise until settled | 0.567 s | 1.467 s |
The fade-out is the number the file cannot give, and it comes out the same both ways: ~0.4 s, i.e. ~24 units under Q1's rule.
The black hold is consistent with the file's 12 units (0.20 s) but does not confirm it — the plateau spans the tail of the outgoing screen's fade-out and the head of the incoming screen's black, and this measurement cannot separate them.
⚠️ The luminance rise is not the quad's ramp
The two columns differ by 2.6× where the quad's declared ramps differ by only 1.12× (58 units vs 52). The filmstrip says why: the background reappears first and the labels arrive after it, so what the luminance curve is timing is the incoming screen's own element animations, not the fade quad. Quoting 1.47 s as "the main menu's fade" would be wrong. The quad's ramp is decoded; the screen's build-in is a separate, longer thing.
For the port
- a screen change is: fade the outgoing screen to black over ~0.4 s, hold black briefly, then fade the incoming screen in over its own declared ramp while its elements play their own keyframes;
- the fade-in ramp is read from the file (
T1 − T0on the screen's fade quad); - the ~0.4 s fade-out and the black hold are authored from this page — the disc does not carry them.
✅ Which quantity the ~0.4 s is — measured 2026-08-29
Asked by the port: is 0.4 s (a) the ramp from the hold to the exit pose, i.e. exactly the missing duration of that untimed keyframe, (b) several keyframes' worth, or (c) something the game does independently of the group?
It is (a) — and it is bigger than the fade quad. Two facts.
🔴 1. "There is exactly one untimed keyframe, and every element has it" — REFUTED 2026-08-30. It was a STALE BINARY.
That claim came from screen info, and the copy of sylpheed-cli in this container
was built 2026-08-29 12:38, before the keyframe-record-layout fix landed. The old
parser shifted every time by one slot and could not time a group's final pose, so it
printed a trailing -. Rebuilt, the same element reads:
stale pteff00.prm 4 kf rest t=70 [12:0,0 70:0,0 80:0,0 -:0,0]
fresh pteff00.prm 4 kf rest t=12 [ 0:0,0 12:0,0 70:0,0 80:0,0]
Four timed poses. There is no untimed keyframe and no unknown duration, so the question this section was answering — "is 0.4 s the missing duration of that untimed keyframe" — no longer has its subject. The argument below (the ratio test) is untouched and still shows the content fading rather than a quad arriving; what is dead is the framing around it.
✅ And the number is now decoded. pteff00.prm's final ramp is 70 → 80 = 10
units ≈ 0.167 s, not the ~24 units this page authored. That confirms the port
agent's reading; I tried to refute it against the bytes and could not.
🔴 So the measured ~0.4 s is NOT the ramp alone — 0.4 s is ~24 units against a decoded 10. Something else occupies the other ~14 units. 🟡 That the remainder is exactly the black hold is arithmetic that fits (14 units = 0.233 s, inside this corpus's own 0.17–0.23 s plateau), not a measurement — and a fit that closes a question without evidence is what this pair of agents has been catching all week. The decomposition stays open.
| elements | final untimed block | what it does |
|---|---|---|
pteff00.prm (the fade quad) |
a = 255 |
goes black |
pteff10, pteff12, ptbtn01…05, ptmsg |
a = 0 |
fade out |
ptframe1, ptframe2 |
a = 255 |
hold, and get covered |
ptbase, pteff05, ptloop*, pteff02.prm |
single keyframe | hold |
2. The capture shows the content fading, not just a black quad arriving. This
has a null hypothesis that discriminates: under (c) — the game blackens the frame
independently — every region is scaled by the same 1 − α, so the ratio
between a button region and a background region is constant through the
fade-out. Under (a) it must fall, because the buttons ramp to a = 0 while the
background elements hold at 255 and are only dimmed.
Measured on transition-filmstrip.png,
button column ÷ upper-right background art, frame by frame through the fade-out:
frame 0 1 2 3 4 5
ratio 6.495 5.574 3.105 2.125 1.935 (black)
A 3.4× monotonic fall. Constant is refuted. The buttons really are fading independently of the overall dim, exactly as their declared final block says. (The incoming screen runs it in reverse, 2.22 → 3.47 over frames 7–12.)
⚠️ Reach. The filmstrip is downsampled and the "button" region unavoidably contains some background, so the ratio is a direction, not a clean alpha measurement. It refutes the constant-ratio null decisively; it does not by itself pin the 0.4 s to ±0.05 s. And it is measured on one transition pair.
For the port
Write one authored constant — the duration of the final untimed keyframe, ~0.4 s / ~24 units — and play the group to its end on every element. Do not model the exit as a black rectangle fading over a frozen screen: the buttons and labels ramp to transparent at the same time, and that difference is visible.