From bc6354dce011c43dabba563c8f41cd757a50557f Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Fri, 28 Aug 2026 19:11:11 +0000 Subject: [PATCH] re: the title presents at 28.5 fps idle -- the keyframe unit is settled at 1/60 s, and the 60 Hz reading is excluded ui-keyframe-time-unit.md named its own re-test and nobody had run it: time 300 submitted frames on the IDLE title, where nothing is streaming from the ISO. Reaching the title is cheap now that one A skips the intro, so this cost one boot. Two clean trials: 300 frames in 10.40 s and 10.60 s, i.e. 28.8 and 28.3 fps. That is the same rate as the 27.6 fps measured during the loading splash, which is exactly the page's own criterion for "the game is 30 Hz and the unit is 1/60 s". The 60 Hz alternative is now excluded rather than disfavoured: it needs the emulator at 47% of real time while sitting idle on a screen the capture says costs 1526 draws over 300 frames, about five per frame. Nothing there halves an emulator. So the durations stand as written -- title 4.2 s, main menu 1.1 s, EXTRAS 0.87 s -- and Q1 leaves the handoff's open-residue table. It stays MEASURED, not decoded: no field on the disc says sixtieths of a second. One trap, and it nearly cost the conclusion. My first attempt reported 39.5 fps, which sits between the two hypotheses and would have left the question open. It was a harness bug: I polled the log for a "done" line rather than for the COUNT of them increasing, so it matched a capture that had already completed and timed 0.1 s of nothing. METHOD gets the general form -- a log-polling probe must compare a count, not test for presence. --- docs/port/HANDOFF.md | 31 ++++++++++----------- docs/re/METHOD.md | 6 ++++ docs/re/ui-keyframe-time-unit.md | 48 ++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index 703d08ee..59c6b319 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -27,7 +27,7 @@ authored version can be deleted. | | 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 s** — [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) | +| Q1 | keyframe time unit + ramp shape | ✅ answered | ramp is **linear**; **2 units per rendered frame**; **`1 unit = 1/60 s` — settled**, the idle title presents at 28.5 fps so the game is 30 Hz — [`ui-keyframe-time-unit.md`](../re/ui-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`](../re/ui-title-build-map.md) | | Q3 | paint order for the six screens | ✅ answered | **decoded**: a `u16` layer key at `+0x0A` of each `T8aD` sprite header, stable-sorted with declaration index; unkeyed elements get an implied key. Confirmed on 5 measured orders + `EXTRAS` vs a capture. One residual: the **tie-break** is unknown and bites on one element of the title — [`structures/ui-paint-order-key.md`](../re/structures/ui-paint-order-key.md) | | Q4 | button → GamePart | ✅ answered | **measured** which screen all **5** buttons open — `NEW GAME` → `DIFFICULTY` → `SELECT DATA`, not a hang. The **GamePart id is still a name match**, not a measurement — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) | @@ -76,19 +76,18 @@ authored version can be deleted. 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; [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) - names the re-test. 🟡 **A second, independent measurement now supports it**: the - transition quad is declared black from `t=0` to `t=12` — 12 units, i.e. 0.20 s - under this conversion — and a 30 fps capture measured the pure-black plateau at - **0.17–0.23 s** ([`screen-transitions.md`](../re/screen-transitions.md)). That - is corroboration and not proof: the plateau spans the outgoing screen's - fade-out tail as well as the incoming screen's black, and this measurement - cannot separate them. - ⚠️ If the game turns out to present at 60 Hz, **every duration on this page - derived from keyframe units halves** — including Q7's declared fade-in lengths - (0.87 s / 0.97 s / 4.08 s). The wall-clock numbers measured off a capture (the - ~0.4 s fade-out, the black hold, the attract timings) do not move. + ✅ **The seconds conversion is settled: `1 unit = 1/60 s`, a 30 Hz title.** The + re-test this page used to name has been run — 300 submitted frames timed on the + **idle** title (nothing loading) came out at **28.8 and 28.3 fps**, the same + rate as the 27.6 fps measured during the loading splash. The competing 60 Hz + reading is excluded: it needs the emulator at 47 % of real time while idling on + a screen that costs ~5 draws per frame. + A second, independent line agrees — the transition quad is declared black for + 12 units (0.20 s under this conversion) and a capture measured the pure-black + plateau at 0.17–0.23 s + ([`screen-transitions.md`](../re/screen-transitions.md)). + ⚠️ Still **measured, not decoded**: no field on the disc says "sixtieths of a + second". * **The paint order is derivable from the file.** Each `T8aD` sprite header carries a **`u16` layer key at `+0x0A`** (the upper half of the 32-bit word at `+0x08` is zero in all 21 184 sprites on the disc). Paint order is that key, @@ -247,7 +246,8 @@ authored version can be deleted. ## What is still open Every question above is answered, so this is the honest residue rather than a -work queue. **None of it blocks the five screens.** +work queue. **None of it blocks the five screens.** (Q1's seconds conversion was +here until 2026-08-28 and is now settled.) | | what | why it is stuck | |---|---|---| @@ -255,7 +255,6 @@ work queue. **None of it blocks the five screens.** | ❔ | **the wave index into `Static.slb`** (Q8) | same instrumentation. This container runs `--mute=true` against an SDL dummy device, so it cannot watch the audio path at all | | 🟡 | **the paint-order tie-break** (Q3) | eight candidates refuted; costs one element's blend on one screen | | 🟡 | **GamePart ids behind the buttons** (Q4) | the *screens* are measured; the ids are a name match onto the executable's class names | -| 🟡 | **`1 unit = 1/60 s`** (Q1) | two independent measurements agree, neither is proof; if it is 60 Hz every keyframe-derived duration halves | | ❔ | **the boot transitions in code** (Q6) | bounded as code-not-data, not proven. `sub_821C6458` — the substantial function in `GamePart_Title`'s neighbourhood — has **not been read** | | ❔ | **`MS00A` → `S00A.wmv` never watched** (Q9) | decoded from the manifest; the one run that reached it crashed at `SELECT DATA` first | | ❔ | **builds 0/1 and 10/11**, the `DELTASABER` plates (Q2) | never seen on screen anywhere in the boot path, the title-side screens or the attract loop | diff --git a/docs/re/METHOD.md b/docs/re/METHOD.md index 9041e075..43880c4d 100644 --- a/docs/re/METHOD.md +++ b/docs/re/METHOD.md @@ -184,3 +184,9 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the XACT string at all. The names came from the authoring tool and survived into the shipped data. Check for the magic before committing to a parser for the format the extension advertises. +* **A log-polling probe must compare a COUNT, not test for presence.** Timing an + operation by waiting for its "done" line in a log gives an instant false + positive if any earlier run left one there. This produced a confident + "39.5 fps" that was really 0.1 s of matching a stale line — and it disagreed + with the true 28.5 fps by enough to have flipped a conclusion. Snapshot + `log.count(marker)` before starting and wait for it to *increase*. diff --git a/docs/re/ui-keyframe-time-unit.md b/docs/re/ui-keyframe-time-unit.md index 57f99437..ee7e72d1 100644 --- a/docs/re/ui-keyframe-time-unit.md +++ b/docs/re/ui-keyframe-time-unit.md @@ -109,14 +109,46 @@ fit are: t = 16 … 269) is then **4.2 s**, and the main menu build (build 5, t = 12 … 80) **1.1 s**. -**The reach of this negative:** the present rate was measured *during the boot -splash*, where the guest is also streaming from the ISO, so it is a lower bound on -the emulator's speed and cannot by itself exclude the 60 Hz reading. What would -settle it is the same 300-frame timing taken on the **idle title screen**, where -nothing is loading — if that also comes out near 28 fps the game is 30 Hz and the -unit is 1/60 s; if it doubles to ~55 fps the game is 60 Hz and every duration on -this page halves. Until then the port should treat **2 units per rendered frame** -as the measured fact and `1/60 s` as the working conversion. +**The reach of this negative** *(as written before the test below — kept for the +reasoning)*: the present rate was measured *during the boot splash*, where the +guest is also streaming from the ISO, so it is a lower bound on the emulator's +speed and cannot by itself exclude the 60 Hz reading. What would settle it is the +same 300-frame timing taken on the **idle title screen**, where nothing is +loading — if that also comes out near 28 fps the game is 30 Hz and the unit is +1/60 s; if it doubles to ~55 fps the game is 60 Hz and every duration on this page +halves. + +## ✅ That test was run — 2026-08-28. The game is 30 Hz; `1 unit = 1/60 s` + +Reached the title with a single Ⓐ to skip the intro +([`movie-binding.md`](movie-binding.md)), let it settle 12 s so nothing was +loading, then armed the bounded 300-frame capture and timed it to its own +`[UI-CAP] done` line: + +| | 300 frames in | rate | +|---|---|---| +| idle title, trial 1 | 10.40 s | **28.8 fps** | +| idle title, trial 2 | *arm produced no capture* | — | +| idle title, trial 3 | 10.60 s | **28.3 fps** | +| *(prior)* boot splash | 10.87 s | 27.6 fps | + +**~28.5 fps on an idle title — the same rate as the loading splash.** By this +page's own criterion that settles it: the title presents at **30 Hz**, the +timeline ticks at **60 units/second**, and **`1 unit = 1/60 s`**. + +**The 60 Hz reading is now excluded, not merely disfavoured.** It would require +the emulator to be running at 47 % of real time *while sitting idle on a static +title* — and the capture says that screen costs **1 526 draws over 300 frames, +about 5 draws per frame**. Nothing there is expensive enough to halve the +emulator's speed, and the splash and the idle title returning the same rate is +exactly what a constant ~95 %-of-real-time emulator looks like. + +So the durations on this page stand as written: title build 4 ≈ **4.2 s**, main +menu build 5 ≈ **1.1 s**, and `EXTRAS` build 6's declared fade-in ≈ **0.87 s**. + +⚠️ Still **measured, not decoded** — no field on the disc says "sixtieths of a +second". What changed is that the measurement now has an idle-state control and +the competing reading is ruled out. ## What this does not say