diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index 4107a998..63b2c26e 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, 🟡 one gap | 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. 🟡 **The interpolation law is settled; the group TIMELINE for multi-keyframe elements is not** — `palogo_gamearts` is still at full alpha 9 frames after its declared `a=32`, and its declared 80-frame fade-in never draws — [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) | +| Q1 | keyframe time unit + ramp shape | ✅ answered, 🟡 one gap | 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. 🟡 **The interpolation law is settled; the group TIMELINE for multi-keyframe elements is not** — `palogo_gamearts` is still at full alpha 9 frames after its declared `a=32`, and its declared 80-frame fade-in never draws — [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md). ✅ **REPLICATED 2026-08-29 — for ANIMATION, read `+36` as the time the NEXT pose is reached.** Three elements across two screens: `palogo_gamearts` and `palogo_seta` hold full alpha for **83 frames** and `palogo_sqex` for **≥77**, where the current reading predicts **6–8** and the shifted one **80–102**. The elements that cannot discriminate (the `_eff` glows, on which the linear law was measured) fit both. ⚠️ Our decoder still defaults to the other reading (`SYLPHEED_KF_TIME_SHIFT=1` to flip) because it changes `rest()` on one element — but that is an unsound fallback guessing either way, so **static rendering is unaffected and animation timing should use the shift** | | 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, ❔ tie-break | **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). ⚠️ **The key does not fully order a screen**: elements sharing a key are tied, and the tie-break is ❔ **undecodable from the bundle** — declaration table, `T8aD` header (exhaustive: every offset 0x00–0x7f at u8/u16/u32, both directions, **0** fields match the measured order against **64** for the control) and the RATC child order all give the same order the game does *not* use. Your exposure is **2 overlapping tied pairs on `EXTRAS`** — [`structures/ui-paint-order-derived-check.md`](../re/structures/ui-paint-order-derived-check.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) | diff --git a/docs/re/METHOD.md b/docs/re/METHOD.md index 754ecf74..9bbaf557 100644 --- a/docs/re/METHOD.md +++ b/docs/re/METHOD.md @@ -742,3 +742,11 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the inflated by my own duplicate runs. A slow thing observed under contention looks like a stuck thing, and the correction matters: an hour-scale gate can be run deliberately, a hung one cannot be run at all. +* **Separate the question with evidence from the question tangled with it.** The + keyframe-time reading was held back for several iterations by one objection: + adopting it changes `rest()` on a single element. But `rest()` reaches the times + only through a fallback that is unsound whenever it runs, and the shift does not + fix that fallback either — so the objection was never about the times. Timing + had three discriminating measurements; pose-selection had a heuristic guessing. + When a conclusion is blocked, check whether the blocker is actually evidence + about the same thing. diff --git a/docs/re/REFUTED.md b/docs/re/REFUTED.md index 70b1f873..0e74e30f 100644 --- a/docs/re/REFUTED.md +++ b/docs/re/REFUTED.md @@ -522,3 +522,9 @@ neighbourhood, not just the line. ~45–60 minutes. The 3 h 26 m observed was that work at a load average of 9–14, inflated by my own two duplicate runs. [`test-suite-runtime.md`](test-suite-runtime.md) +* "the case for the keyframe-time shift rests on a single element" → **no longer + true.** Three elements across two screens discriminate and all favour it: + `palogo_gamearts` and `palogo_seta` hold full alpha 83 frames, `palogo_sqex` + ≥77, against 6–8 predicted by the current reading and 80–102 by the shifted + one. The `_eff` glows fit both and argue against neither. + [`ui-keyframe-time-unit.md`](ui-keyframe-time-unit.md) diff --git a/docs/re/ui-keyframe-time-unit.md b/docs/re/ui-keyframe-time-unit.md index 267b25a2..f364effc 100644 --- a/docs/re/ui-keyframe-time-unit.md +++ b/docs/re/ui-keyframe-time-unit.md @@ -333,3 +333,60 @@ of build 7 to verify the result against. group's *timing* as unverified — and specifically should not expect a 2-frame hold where the game holds 83 — while `rest()` and `screen render` remain as they are. + +--- + +## ✅ Replicated: three elements, two screens, and the shifted reading wins every time + +**2026-08-29.** The case for reading `+36` as *"the time the NEXT pose is +reached"* rested on one element's fade-out shape, then on one element's hold +duration. Both splash halves supply more, and they all say the same thing. + +Phase durations in frames (2 units/frame, from the `_eff` glow ramp): + +| element | screen | observed hold at `a=255` | as decoded | shifted | +|---|---|---|---|---| +| `palogo_gamearts` | developer splash | **83 f** | 8 f | **80 f** | +| `palogo_seta` | developer splash | **83 f** | 6 f | **80 f** | +| `palogo_sqex` | publisher splash | **≥ 77 f** * | 6 f | **102 f** | + +\* the capture opens mid-hold at frame 1, so 77 is a floor, not the length. + +The two readings predict **opposite structures** for these elements. On +`palogo_gamearts`, as decoded: `hold 8f, in 80f, hold 2f, out 6f, out 2f` — +an eighty-frame *fade-in* and a two-frame hold. Shifted: `in 8f, hold 80f, +out 2f, out 6f, out 2f` — an eight-frame fade-in and an eighty-frame *hold*. +The capture shows a **83-frame hold** and no fade-in at all. + +### And the elements that cannot discriminate are not contradicted + +`palogo_gamearts_eff` observed `in 7f, hold 7f, out 8f`. As decoded it reads +`in 8f, hold 8f`; shifted it reads `hold 8f, out 8f`. Both fit — with only four +blocks the shift relabels which phase is which without changing any duration. So +the glows, which are what Q1's linear law was measured on, **do not argue against +the shift**; they simply say nothing about it. + +### 🟡 Why the decoder's default is still unchanged + +The one thing that opposes the shift is `Element::rest()` on `ptlogo_eff3.t32`, +where the shifted reading makes the longest-dwell fallback return the bloom's +200 % peak instead of an invisible frame. But that fallback is **unsound whenever +it runs** ([resting pose](structures/ui-resting-pose.md)) — it returns an +endpoint of a movement, and neither endpoint is held. Checked: the shift does not +fix it either, so this is not a case of two readings disagreeing about the times. +It is a heuristic guessing, in both. + +**So the two questions are separable, and only one of them has evidence.** The +times govern animation; `rest()` picks a static pose through a rule that consults +them only after its own precondition has failed. + +### ⚠️ What a port should do + +For **animation timing**, read `+36` as the *next* pose's time: three elements +across two screens, each off by an order of magnitude under the other reading. +For **static composites**, nothing changes — `screen render` is unaffected, and +the five screens' correlations stand ([acceptance](five-screens-acceptance.md)). + +🟡 Classified **measured, not decoded**: this is three elements in one game +screen family, not a disc-wide field check, and our own decoder still defaults to +the other reading behind `SYLPHEED_KF_TIME_SHIFT=1`.