re(ui): rotation is not nested-only, and the pivot-anchored scale is measured

Two corrections and one new confirmation, all from finishing the sweep I
left running last iteration.

Refuted, by my own sweep, within the hour: "rotation appears to live only
in nested .rat leaf records". That held for GP_TITLE, GP_BUNK and
GP_CHALLENGE -- the three archives the sweep had reached when I wrote it
-- and fails on GP_DIALOG and GP_DEBRIEFING_PILOTLOG, which rotate
top-level elements. Scoping the claim made it cheap to withdraw, but the
sentence should have waited for the sweep.

Those top-level cases are the best evidence on the disc, and they show up
in `screen info --geometry` without a hex dump. GP_DIALOG build 0:
pceff03/pceff04 ramp r = 90 -> 30 -> 10 -> 3 -> 0 while alpha ramps
0 -> 255 and they slide into place -- a swing-in settling upright. Build
6: pzeff02 ramps 43 -> 61 -> 75 -> 90 while scaling 112% -> 200% and
fading to 0 -- a spin-out. Rows committed as reference data.

New: the pivot-anchored scale term in blit, kf.x - pivot*(scale-100)/100,
was implemented and reasoned about but never measured, because every
element previously examined sits at 100% scale where the term is exactly
zero. The ptloop pair scale 600% and 800%, where it is worth 450 and 630
px. Formula predicts centre y = 360.0 for both; capture measures 359.1
and 360.0. Top-left anchoring predicts 810 and 990. Horizontally it makes
t-from-position agree with t-from-alpha to 0.33 / 0.65 units against ~8
without it.

That agreement does NOT prove linear interpolation -- both fields were
inverted through the same linear map, so a shared easing curve cancels.
It shows position and alpha ride one shared parameter. Recorded as such.

The disc-wide sweep is still running; the count is incomplete, the
existence is settled.
This commit is contained in:
Sylpheed RE agent
2026-08-28 22:46:44 +00:00
parent 67fa1a1b0b
commit f11fde51e5
5 changed files with 124 additions and 15 deletions

View File

@@ -86,6 +86,18 @@ authored version can be deleted.
affect this render**: `blit` sizes a sprite from its **texture**, and applies the
pivot only as `kf.x − pivot·(scale−100)/100` — and **all seven swoosh elements
are scale `(100,100)` at every keyframe**, so the term is zero.
✅ **That formula is now MEASURED, not just implemented (2026-08-28).** The
title's two `ptloop` sweeps scale **600 %** and **800 %** vertically, where the
pivot term is worth 450 and 630 px, and the GPU capture puts both quad centres
at y **359.1** and **360.0** — against the formula's **360.0** for both.
Top-left anchoring predicts 810 and 990; treating the position as the centre
predicts 270. Horizontally the same term makes the group's `t` solved from
**position** agree with `t` solved from **vertex alpha** to **0.33 / 0.65
units**, versus ~8 units without it. So: **anchor scaling on the pivot, not on
the top-left corner.**
🟡 It does *not* prove interpolation is linear — both fields were inverted
through the same linear map, so a shared easing curve would cancel. It does
show position and alpha ride **one shared parameter**.
⚠️ It *would* bite `ptlogo1`/`ptlogo2`, which scale 100 → 150 during the
build-in. Not at rest, and not on the swoosh.
🔴 **Ruled out for the COLOUR**: every swoosh keyframe's fade is `0x??ffffff`
@@ -137,12 +149,18 @@ authored version can be deleted.
constant — a spin in place. Disc-wide `+12` is non-zero in **14.50 %** of
83 862 keyframe blocks.
⚠️ **Two things the port must know about it.**
(1) 🟡 **Rotation appears to live only in NESTED `.rat` leaf records.** Every
instance found so far is nested, and the top-level table is empty of it across
`GP_TITLE`, `GP_BUNK` and `GP_CHALLENGE` — a pattern over three archives, not a
finished disc-wide sweep. Either way it is the actionable half: a composer that
reads only the declaration table will see zero rotation everywhere and be wrong
on exactly the elements that move.
(1) **Rotation lives in BOTH the top-level table and nested `.rat` leaf
records.** ⚠️ I told you one iteration ago that it looked nested-only; that was
three archives' worth of pattern and **it is refuted** — `GP_DIALOG` and
`GP_DEBRIEFING_PILOTLOG` rotate top-level elements. The actionable half stands:
the *title's* rotations are nested, so a composer reading only the declaration
table gets zero rotation on exactly the elements that move there.
The clearest examples are top-level and show up in
`screen info --build 0 --geometry dat/GP_DIALOG.pak`: `pceff03.t32` and
`pceff04.t32` ramp `r=` **90 → 30 → 10 → 3 → 0** while their alpha ramps
0 → 255 and they slide into place — a swing-in that settles upright; and build
6's `pzeff02.t32` ramps **43 → 61 → 75 → 90** while scaling 112 % → 200 % and
fading to 0 — a spin-out burst.
(2) **`sylpheed-cli screen render` still does not rotate.** The field is
decoded, not rendered; `ui_layout::blit` is axis-aligned only. So the reference
renderer and the port will *both* draw these upright until a rotating blit