re(ui): Q1 -- the interpolation law holds, the group timeline does not

Q1's gate asks whether the ramp is linear. It is, and that result stands:
it rests on the splash's _eff glows, which reproduce exactly. This adds
the part that does not.

The test is a calibration, not a fit. Fix the clock on
palogo_gamearts_eff -- declared 15-unit fade-in 0@15 -> 255@30 against
captured alphas 34,68,102,136,170,204,238, a constant step of 34, giving
t = 2f - 171 -- then check that against the glow's own next landmark: its
declared hold ends t=45, predicted frame 108.0, observed last full-alpha
frame 107. Then apply it to palogo_gamearts in the same bundle and the
same frames, with no free parameter left:

  declared a=232 at t=206 -> frame 188.5, observed alpha 255
  declared a= 32 at t=210 -> frame 190.5, observed alpha 255

The logo is still at full alpha nine frames after it should read 32; its
fade-out runs ~17 frames late; its declared 80-frame fade-in is never
drawn. Not culling -- the same element is submitted down to a=7 on the
way out. Calibration-free version: the declared fade-out spends 12 of 16
units dropping 23/255 of the alpha, and the capture has no such plateau.

Candidate, offered and NOT adopted: if +36 held the NEXT keyframe's time,
the fade-out shape fits (RMS 4.05 vs 12.13, two elements) and the
decoder's "last block's time is unreadable" special case disappears --
the last block would simply have no successor. Rejected for now because
it explains neither the missing fade-in nor the lateness, and because the
_eff elements cannot discriminate between the readings at all (with four
blocks the shift only relabels the phases). Decoder unchanged.

Also withdrawn, mine, within the iteration: "the _eff glows hold a
constant alpha 33". They ramp 34 -> 255 in steps of 34. I printed the
series minimum and read it as its range, with a "14 distinct colours"
column sitting next to it saying otherwise.
This commit is contained in:
Sylpheed RE agent
2026-08-28 22:56:17 +00:00
parent f11fde51e5
commit 531840b417
6 changed files with 208 additions and 1 deletions

View File

@@ -161,3 +161,82 @@ the competing reading is ruled out.
`_sqex_eff` absence is explainable (the capture joined the SQUARE ENIX logo
mid-hold); the missing studio-anima logo is not, and is left as an open
observation for Q2 rather than a claim.
---
## 🟡 Open: the `palogo_*` LOGO elements do not play their declared timeline
**Added 2026-08-28.** Everything above stands — it rests on the `_eff` glows, and
they reproduce exactly. What follows is a **different element in the same bundle
and the same capture**, and it does not.
Reproduce with
[`tools/re-capture/splash_ramp_check.py`](../../tools/re-capture/splash_ramp_check.py);
output committed at [`data/splash-ramp-check.txt`](data/splash-ramp-check.txt).
### Why this is a test and not a fit
The clock is calibrated on `palogo_gamearts_eff` — its declared 15-unit fade-in
`0@15 → 255@30` against its captured alphas 34, 68, 102, 136, 170, 204, 238, a
constant step of exactly 34. That gives `t = 2f − 171`, and the calibration
checks itself: the glow's declared hold ends at `t=45`, predicted **frame 108.0**,
and the observed last full-alpha frame is **107**.
That calibration is then applied to `palogo_gamearts` — same bundle, same frames,
**no free parameter left**:
| declared | predicted frame | observed alpha |
|---|---|---|
| `a=0` at `t=15` | 93.0 | not drawn |
| `a=0` at `t=30` | 100.5 | not drawn |
| `a=255` at `t=190` | 180.5 | 255 |
| `a=232` at `t=206` | 188.5 | **255** |
| `a=32` at `t=210` | 190.5 | **255** |
The logo is still at full alpha nine frames after it should have been at `a=32`.
Its fade-out actually runs frames **199–211**, some 17 frames late, and its
declared 80-frame fade-in (`t=30→190`) is **not drawn at all** — the element's
first appearance, frame 116, is already at 255.
⚠️ "Not drawn" is not a culling artefact: the same element is submitted all the
way down to `a=7` on the way out, so low-alpha quads plainly do reach the GPU.
### The shape mismatch, which needs no calibration at all
The declared fade-out spends **12 of its 16 units** dropping only **23/255** of
the alpha — a near-flat leg — then **200/255** in the remaining 4. The captured
per-frame drops are `1, 11, 6, 22, 34, 33, 17, 33, 33, 17, 25, 8, 8`. There is no
near-flat leg.
### 🟡 A candidate, offered as one and NOT adopted
If the word at `+36` were the time of the **next** keyframe rather than of its own
block, the logo's fade-out would read `255@190 → 232@194 → 32@206 → 0@210`:
slow, fast, slow — which is the captured shape. Fitting both readings to the
captured fade-out gives RMS alpha error **4.05** shifted against **12.13** as
decoded, on two elements independently (`gamearts` and `sqex`).
It also removes a special case. The decoder currently notes that a group's data
"stops 4 bytes short of its final block's time slot", so the last block's time is
unreadable. Under the shifted reading the last block simply *has no successor*,
so it has no time word — the same bytes, no special case.
**Not adopted, for three reasons:**
1. It does not explain the missing fade-in, which is the larger anomaly.
2. It does not fix the 17-frame lateness of the fade-out.
3. The `_eff` elements **do not discriminate** between the two readings — I
checked: with four blocks the shift merely relabels which phase is which, and
both reproduce the observed fade-in / hold / fade-out. So the entire case for
the shift rests on one element's fade-out shape.
**The decoder is unchanged.** 🟡 What a port should take from this: the
interpolation *law* is settled (linear, 2 units per frame), and the *group
timeline* for multi-keyframe elements is not.
### 🔴 One thing I got wrong in the course of this
I first reported the `_eff` glows as holding "a constant α ≈ 33" and read that as
contradicting the declared 255 plateau. They do no such thing — they ramp 34 →
255 in exact steps of 34. I had printed only the series' **minimum** and read it
as its range. Withdrawn; the trap is in [METHOD.md](METHOD.md).