# ✅ The boot title shows build 4 alone for **2.13 s**, then composites the plate **Status:** ✅ **measured** — two independent boots of the real game in Xenia Canary, 2026-08-29. Not on the disc as a delay: build 2 (the `PRESS Ⓐ BUTTON` plate) is an overlay with no fade quad of its own, and nothing in either bundle's keyframe group carries the gap between them. **Question this closes:** the port asked which of three things the boot title is — build 4 alone, build 4 with the plate composited from the start, or build 4 **then** the plate after a delay — because the third case is the only one where `ScreenView` has to draw **two builds at once**, which it has never done. The sequence was already answered (it is the third, [`menu-idle-and-b-2026-08-29.md`](menu-idle-and-b-2026-08-29.md)); **the delay was withdrawn the same day** and is what this page supplies. ## The number | | run 1 | run 2 | |---|---|---| | title art first drawn (surface leaves black) | 201.617 s | 214.130 s | | **title settled** — glyph counter first reads its no-plate value **154** | 203.260 s | 216.261 s | | **plate first counted** — glyph leaves 154 | 205.398 s | 218.393 s | | **settled → plate** | **2.138 s** | **2.132 s** | | first drawn → plate | 3.781 s | 4.263 s | **Take 2.13 s, measured from the moment build 4's own build-in animation finishes.** The two runs agree to **6 ms**, which is under one sample interval. ⚠️ **Do not take "first drawn → plate".** It differs by 0.48 s between the two runs because the build-in itself ran 1.64 s and 2.13 s — the emulator's frame pacing during an animation is not the game's clock, and this is exactly the sort of number that looks like a measurement and is really the harness. ![plate onset, both runs](captures/ui-timing/plate-onset-two-runs.png) Raw per-frame data, 8 fps, every frame of both runs: [`data/plate-timing-run1.tsv`](data/plate-timing-run1.tsv) · [`data/plate-timing-run2.tsv`](data/plate-timing-run2.tsv). ## Why "then the plate", and not "the plate was pulsing all along too dim to see" The plate's declared alpha never exceeds `0x50` (80/255, [HANDOFF](../port/HANDOFF.md)), so a glyph counter with a hard threshold could in principle miss its dim phase and produce a fake delay. It does not, on two independent observables: * the glyph count is **exactly 154** — the committed no-plate title's own value, 159 on `live-title-build4-no-plate.png` — for every frame of the plateau, with **zero** variation, for 1.99 s (run 1) and 2.13 s (run 2). After onset the same counter swings 714 ↔ 1520 continuously. A cycling plate cannot produce a flat exact-154 plateau nearly one full period long; * the **surface mean** is flat to ±0.03 across the plateau (61.09 → 61.15) and then rises. A pulsing overlay moves the frame mean; the frame mean does not move until onset. ## 🔴 The instruction below was WRONG, and the port refuted it — corrected 2026-08-29 **What stands:** every measurement on this page. **What was wrong:** what I told the port to do with it. The instruction was *"when build 4 has settled, wait 2.13 s, composite build 2"*. The port implemented it literally, then pointed out with arithmetic off the disc that it cannot be right: build 2 has a **group of its own**, and playing that group from a start at "settle" puts the plate at settle + 2.13 + 3.97 s. The 3.97 s is real — `ptbtn00.rat` reaches `a=255` at `t=238`, confirmed here independently of their message: ``` $ sylpheed-cli screen info --build 2 --geometry $SYLPHEED_DISC/dat/GP_TITLE.pak build [2] 1280x720 1 elements 0 ptbtn00.t32 214: 383,560 a=0 236: 383,550 a=0 238: 383,550 a=255 244: 383,550 a=255 -: a=0 ``` ### The reconciliation: one clock, and my landmark is `t≈118`, not `t=261` **Build 2's group runs on the same clock as build 4's, starting together.** Then the plate's own keyframes say when it arrives and nothing needs authoring. The port's premise that *"build 4 settles at `t=261` = 4.35 s"* is the part that fails, and it is worth stating plainly because it will bite elsewhere: 🔴 **`rest.t` is not when a screen settles.** It is the last *hold* keyframe before the exit. `ptlogo1` has `rest.t = 251` and stops moving at **`t=42`** — after which it creeps 5 px over the next 209 units. The title's visible build-in is over at **`t≈118`**, where three elements' ramps end together (`pteff01`, `pteff02.prm`, `ptlogoall_eff`); the only later change is the copyright line and the ™. That closes the gap exactly, with no free parameter: | | units | |---|---| | last build-in ramp ends (`pteff01` / `pteff02.prm` / `ptlogoall_eff`) | `t = 118` | | `ptbtn00` reaches `a = 255` | `t = 238` | | **difference** | **120 units = 2.000 s** at 1 unit = 1/60 s | against a measured **2.138 s** and **2.132 s**. So the interval the two runs agree on to 6 ms is a **declared** 120 units — the number was on the disc, and I handed over a wall-clock reading of it. ### ⚠️ And the wall-clock reading is 6.7 % long, for a reason the corpus already knew 120 units in 2.135 s is **56.2 units/s**, i.e. the game presenting at **28.06 / 28.14 fps** against its nominal 30. The corpus independently measured the idle title at **28.5 fps** ([`ui-keyframe-time-unit.md`](ui-keyframe-time-unit.md)) — 1.3 % from these two runs, established before and separately from them. ✅ Corroborating that it is presentation rate and not the game: within these runs *first pixels → settle* is **1.643 s** and **2.131 s** — a 30 % spread — while *settle → plate* is **2.138 s** and **2.132 s**. The build-in is where frames are dropped; the static hold is not. A model in which the game's own timing varied would have to move both. ## What the port should author — nothing 1. draw build 4 and build **2** on **one clock, started together**, and play both groups from their own keyframes; 2. the plate then appears at its declared `t = 238` with no authored constant; 3. its pulse is the focus record `ptbtn00f`, measured here at **2.12 / 2.19 / 2.34 / 2.31 s** over four intervals, mean **2.24 s** — replicating the corpus's ≈ 2.3 s rather than replacing it. ⚠️ **If you do author a gap anyway, author 120 units (2.00 s at 30 Hz), not my 2.13 s.** The 2.13 s is this emulator's presentation rate baked into a game constant, and a port running at a true 30 Hz would be visibly late. So yes: `ScreenView` needs two builds at once, and the boot's end state is **not** plate-free. That part of the answer is unchanged. ### ❔ What this does not settle * **Which reading of the keyframe times** — the current one or Q1's replicated shift — is right. It barely matters here (the plate's `a=255` is `t=238` unshifted and `t=236` shifted, 0.03 s apart), but the two make different predictions for `ptcopyright`'s fade, and my traces contain **both** a 0.4 s rise and a 1.1 s creep before the plate. Not separated; Q1's 🟡 stands. * **My settle landmark to better than ±5 units.** At 56 units/s, 8 units is 0.14 s — about one sample. `t=118` is identified from the file (three ramps ending together) and is *consistent with* the measurement, not pinned by it. ## What is NOT measured here — the press latencies, again Both runs pressed Ⓐ on the plate and Ⓑ on the menu, and both runs contain a **frozen frame** on the Ⓐ path that makes the Ⓐ→menu duration meaningless: | | run 1 | run 2 | |---|---|---| | frames held at surface mean **26.626**, motion exactly 0 | 14 (1.53 s) | 12 (1.39 s) | 🔴 **This is not the instrument.** Run 1's freeze straddled an x11grab restart, so it looked exactly like the documented stale-stream failure; run 2 was run with restarts **disabled** for the whole measuring window and reproduced the same freeze, at the **same** surface mean to six decimals, in the same place relative to the press. Two independent runs cannot agree to 1e-6 on a stalled buffer. It is the guest: after Ⓐ, the fade-out starts (mean 64.4 → 51.0 → 26.6), the frame is then **re-presented unchanged for ~1.4 s**, the full title reappears at mean 64.28, and only then does the fade run to completion. That is the shape of a **load stall**, and the Ⓑ path — menu → title, nothing to load — has no freeze at all. **So the Ⓐ→menu latency is an emulator load time, not a game beat, and the port must not bake it in.** The parts of the transition that are stall-free: | | run 1 | run 2 | |---|---|---| | press → first visible change (Ⓐ) | — | 0.29–0.37 s | | press → first visible change (Ⓑ) | — | 0.28–0.33 s | | **pure black between the two screens** (Ⓐ path) | 0.14–0.30 s | 0.14–0.27 s | | black → menu settled | ≈ 1.0 s | ≈ 1.0 s | | Ⓑ path: menu fade-out to black | — | 0.50 s | | Ⓑ path: black → title art | — | ≤ 0.27 s, and it is a **cut**, not a fade | ⚠️ The two "first visible change" figures are **upper bounds that include this harness**: the press is a file the emulator polls (`--hid=file`), so an unknown poll interval sits inside them. They are quoted only because they bracket the black hold, and they do **not** refute [`screen-transitions.md`](screen-transitions.md)'s 0.07 s, which was taken a different way. ✅ **The black hold does check the port's authored constant.** The port ships 0.17–0.23 s; both runs put it in **0.14–0.30 s**. Consistent, at a sampling resolution (0.125 s) that cannot do better — so the authored value stands and is now bracketed by a measurement rather than only by the declared 12 units (0.20 s). ## The instrument, and its controls [`tools/re-capture/title_timing_probe.py`](../../tools/re-capture/title_timing_probe.py), built because the four durations withdrawn on 2026-08-29 came from a classifier costing **1503 ms per frame** draining an 8 fps stream at 0.64 fps. * **8.7 ms of compute per frame** — measured, 173× cheaper. The saving is the ±8 px offset search: every committed capture aligns at exactly `dy=0 dx=0` ([`five-screens-acceptance.md`](five-screens-acceptance.md)), so the live path decimates 4× and does one ZNCC per reference instead of 25 at full res. * **Both runs sampled at 7.97 and 7.98 fps against a requested 8.** A backlog preserves ordering and destroys durations; there was no backlog. * `--control` **passed 9/9 content controls and 4/4 plate-detector controls**, including the two committed movie frames that are the class this oracle exists to reject. * an **independent one-shot grab** every 20 s, through a separate process, is logged beside the stream's own frame. On the static screens the two agree to **0.000 / 0.001**; the large disagreements are all inside movies, where a 0.3 s difference in grab time is a different picture. * and the plateau itself carries an internal clock check: the plate's ~2.2 s pulse is visible in the same trace. A stalled stream cannot produce a periodic signal. ## Reach Two runs, English locale, one machine, Xenia Canary. It says nothing about the **attract loop's** title (which the corpus records as accepting no input at all), and nothing about the Japanese build 7.