re(ui): answer four of the port's five asks -- splash, fade-out, focus, gamma
1 SPLASH ADDRESSING (was blocking P3). No content predicate exists: design size fails (every extra composable bundle sampled is 1280x720, like every screen) and element count fails (fragments run 2..15, the splash halves are 3 and 7). But GP_TITLE needs none -- `--all` adds exactly four bundles there and all four are real screens, with the --all index equal to the pak entry index 1:1. And there are TWO splash screens: 11/14 are the developer logos, 10/13 are the SQUARE ENIX publisher wordmark, which the port did not have and which the boot shows first. 2 FADE-OUT (was blocking P3). It is (a), and it is bigger than the fade quad. Every element ends on exactly ONE untimed keyframe, which rules out (b); that block is where the screen plays out -- quad to a=255, buttons/labels/glows to a=0, frames hold. (c) is refuted by a null test that discriminates: a black quad alone holds the button/background brightness ratio constant, and through the fade it falls 6.50 -> 1.94, 3.4x monotonic. 3 FOCUS (saves P5 rework). Over-vs-instead is unobservable -- the focused sprite covers the base at 100.0% of base-visible pixels on three pairs once aligned (true offset (7,7); the centre alignment reads a misleading 78-84%), and compositing both ways differs by RMSE 1.1 inside the button rect. The real defect is the focus record's SECOND element: ptbtn0Nf.rat declares ptbtneff01.t32 (a 42x46 glowing ring, focus only) plus the bright label, where the base declares one sprite. That ring is the marker the port draws nowhere. 5 GAMMA. The capture is not neutral: capture ~ 255*(render/255)^g, g ~ 1.34-1.49, and the chain says it is a ramp the GAME installed, not a capture artefact. So RMSE against captures has a floor. Reach stated: the flat patches are all dark (render ~0-60), so midtones and highlights are unconstrained. 4 ROTATION is a human's call and is recorded in MISSION, not acted on -- the port rotating while the reference renderer does not would make verify-screen report a large diff meaning "the port is right". The RE half is answered: rotation is about the declared pivot, measured against a GPU capture. The focus record's +20 element-count word is marked 🟡 not ✅ -- read on GP_TITLE's ten button records only; the disc-wide check is written and still running.
This commit is contained in:
@@ -41,6 +41,76 @@ authored version can be deleted.
|
||||
|
||||
## Already settled — the port can rely on these today
|
||||
|
||||
### ⬅ Answers to the port's five asks (2026-08-29)
|
||||
|
||||
* **1 — how to recognise the splash.** ❔ **No content rule exists; you are
|
||||
authoring this.** Design size fails (every extra composable bundle sampled is
|
||||
1280×720, same as every screen) and element count fails (the fragments run
|
||||
2…15 elements, the splash halves have 3 and 7 — the ranges overlap).
|
||||
✅ **But `GP_TITLE` needs no rule.** There, `--all` adds exactly **four**
|
||||
bundles and all four are real screens — no fragments at all — and the `--all`
|
||||
index equals the pak **entry** index 1:1 across all 16, so addressing by entry
|
||||
index does not mean something different from elsewhere.
|
||||
🔴 **And there are TWO splash screens; you have one.** Entries **11/14** are the
|
||||
developer logos (GAME ARTS / SETA / studio anima). Entries **10/13** are the
|
||||
**SQUARE ENIX publisher** wordmark — the *first* thing the boot shows — and you
|
||||
do not have them. The pairs are region twins (`™` on 10, `®` on 13). All four
|
||||
draw every element they declare.
|
||||
[`ui-splash-addressing.md`](../re/ui-splash-addressing.md) ·
|
||||
[render grid](../re/captures/title-builds/splash-both-halves-rendered.png)
|
||||
|
||||
* **2 — the ~0.4 s fade-out is (a)**, and it is bigger than the fade quad.
|
||||
Every element of a screen ends on **exactly one** untimed keyframe — so there
|
||||
is one unknown duration per screen, which rules out (b). That final block is
|
||||
where the screen plays out: the quad goes `a=255` (black) while the buttons,
|
||||
`ptmsg` and the glows go `a=0` and the two frames hold. (c) is refuted by a
|
||||
null test on the capture: a black quad alone keeps the button÷background
|
||||
brightness **ratio constant**, and measured through the fade it falls
|
||||
**6.50 → 1.94, a 3.4× monotonic drop**. So: write one authored constant
|
||||
(~0.4 s / ~24 units) and **play the group to its end on every element** — do
|
||||
not fade a black rectangle over a frozen screen.
|
||||
[`screen-transitions.md`](../re/screen-transitions.md)
|
||||
|
||||
* **3 — focus: your choice is fine, and it is not your bug.** ✅ The focused
|
||||
sprite **completely covers** the base — `f` alpha ≥ base alpha at **100.0 %** of
|
||||
base-visible pixels on three pairs across both languages, once aligned properly
|
||||
(the true offset is **(7,7)**, and at the centre alignment it reads a
|
||||
misleading 78–84 %). Compositing both ways differs by **RMSE 1.1 inside the
|
||||
button rectangle**, max 12/255 on ~25 px — unmeasurable at frame level.
|
||||
🔴 **What you are actually missing is the focus record's SECOND element.**
|
||||
`ptbtn0Nf.rat` declares **two** sprites — `ptbtneff01.t32` (a 42×46 **glowing
|
||||
ring**, focus only) then `ptbtn0Nf.t32` (the bright label) — where the base
|
||||
record declares one. That ring is the marker you say you draw nowhere. ⚠️ Note
|
||||
the small dot-in-circle at each underline's left end is *not* it: that is on
|
||||
every button all the time, part of the base art.
|
||||
[`structures/ui-button-focus-record.md`](../re/structures/ui-button-focus-record.md)
|
||||
|
||||
* **4 — rotation: not mine to decide alone.** Raised with the human; see
|
||||
MISSION. What I can say without a decision: the two sub-questions are not
|
||||
equally open. Rotation is about the **declared pivot** — that anchor is
|
||||
*measured*, not assumed: the title's two `ptloop` sweeps scale 600 %/800 %
|
||||
vertically, where the pivot term is worth 450 and 630 px, and the GPU capture
|
||||
puts both quad centres at y **359.1**/**360.0** against the pivot formula's
|
||||
**360.0**; top-left anchoring predicts 810/990 and centre-as-position 270. So
|
||||
if you draw rotation, rotate about the declared pivot.
|
||||
⚠️ It changes nothing on your five screens **at rest** — they have zero
|
||||
top-level rotations, and the title's two nested ones sit entirely off-screen at
|
||||
rest. [`structures/ui-keyframe-rotation.md`](../re/structures/ui-keyframe-rotation.md)
|
||||
|
||||
* **5 — the capture is not gamma-neutral, and RMSE against it has a floor.**
|
||||
Measured on flat patches (16×16, both images `std < 8`):
|
||||
`capture ≈ 255·(render/255)^γ` with **γ ≈ 1.49** (main menu), **1.49**
|
||||
(`EXTRAS`), **1.34** (title). The chain says this is a ramp **the game
|
||||
installed**, not a capture-path artefact: canary's swap-path gamma stage is a
|
||||
pure 256-entry LUT that defaults to identity, and the game is measured calling
|
||||
`VdGetCurrentDisplayGamma` once at video init. ⚠️ **Reach: the flat patches are
|
||||
almost all dark (render ~0–60), so nothing here constrains midtones or
|
||||
highlights** — which is where γ 1.4 does its visible work. So: yes, there is a
|
||||
floor; a γ ≈ 1.4 darkening gets closer and is **authored**, best applied where
|
||||
it was measured rather than extrapolated. Do not chase RMSE below it.
|
||||
[`structures/ui-render-tone-curve.md`](../re/structures/ui-render-tone-curve.md)
|
||||
|
||||
|
||||
* **`GP_TITLE.pak` is eight screens, each shipped twice — English and Japanese.**
|
||||
Build 4 is the English title art and 7 its Japanese twin; **2/3 are the
|
||||
`PRESS Ⓐ BUTTON` plate, a build of their own** composited over the title and
|
||||
|
||||
@@ -208,6 +208,28 @@ settled and only multi-keyframe absolute timing is open; `rest()` differs from
|
||||
its alternative on **one** element across all five screens, and the current
|
||||
answer there is the defensible one.
|
||||
|
||||
## 🔵 Needs a human decision — rotation (raised 2026-08-29)
|
||||
|
||||
The port agent asks whether it should **render** `rotation_deg` (decoded at
|
||||
keyframe `+12`) when `sylpheed-cli screen render` deliberately does not. Its own
|
||||
framing is the reason this is not mine to settle: if the port rotates and the
|
||||
reference renderer does not, then `verify-screen` reports a large title diff that
|
||||
means *"the port is right"* — a silently inverted signal.
|
||||
|
||||
The RE half is answered and is in HANDOFF: rotation is about the **declared
|
||||
pivot** (measured against a GPU capture, not assumed), and it changes nothing on
|
||||
the five screens **at rest**.
|
||||
|
||||
What needs a decision is which way the divergence gets closed:
|
||||
|
||||
* teach `ui_layout::blit` a rotating path, so the two renderers stay comparable
|
||||
and the diff keeps meaning "someone is wrong" — costs work in the reference
|
||||
renderer, which is otherwise not on the port's critical path; or
|
||||
* let the port render rotation and mark the title as a known-divergent screen in
|
||||
`verify-screen`, accepting a check that no longer guards the title.
|
||||
|
||||
Recorded rather than chosen, per "do not improvise around a blocker".
|
||||
|
||||
## Known unknowns — say so, do not fill them in
|
||||
|
||||
Some of these may turn out to be undecodable. That is a valid, useful answer, and
|
||||
|
||||
Reference in New Issue
Block a user