diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index d9f30db4..9bb26395 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -219,6 +219,27 @@ authored version can be deleted. ⚠️ An earlier version of this bullet said "the title screen loops at ≈ 2.2 s" and attributed it to `ptloop01/02`. Both halves were wrong: it is the **plate**, and it is a different build. +* 🟡 **`screen render` silently drops one full-screen element per screen — and + you must NOT simply draw it.** Auditing what the composer omits on your five + screens: everything is accounted for (`kind & 0x4` ghost instances, `.prm` + primitives, `loop*` animations) except **`pteff04.t32`** on the title and + **`pteff05.t32`** on both menus. Those are `kind 0x0`, one keyframe, rest + `a = 255`, pivot `(640,360)` — full-screen and opaque. + **Cause:** the element declares `pteff05.t32`, but the `T8aD` behind its `opt ` + link is registered under the name **`8AX`**, so the sprite lookup misses and a + silent `continue` drops it. + ✅ **It does not currently show,** because `ptbase.t32` (640×360, drawn at + 200 %) is *the same artwork at half resolution* — its 2× upscale differs from + `8AX` by mean 2.05, and our background is pixel-identical to `8AX` in every + patch sampled. + ⚠️ **So resolving the name and drawing it as well would double-draw an opaque + full-screen layer** — invisible as a doubling, which is worse. If you want the + sharper background, use `8AX` at 1:1 and *drop* `ptbase`; don't add it. + ❔ Which of the two the game actually draws is not established — both carry the + same art, and separating them needs a per-draw capture recording texture base + addresses (the two differ in size). + [`structures/ui-8ax-fullres-background.md`](../re/structures/ui-8ax-fullres-background.md) + * **Menu order is geometric.** Buttons sorted top-to-bottom by resting Y. This is ✅ correct for a vertical menu and is **not** a decoded neighbour graph — the disc's real navigation structure is unknown, and `opt ` is *not* a focus link diff --git a/docs/re/METHOD.md b/docs/re/METHOD.md index d8d58b24..ce775665 100644 --- a/docs/re/METHOD.md +++ b/docs/re/METHOD.md @@ -470,3 +470,15 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the never moved. The signal to stop is not "this is hard", it is "the thing this unblocks is not blocking anything". Write down the recipe you built and leave it for a session with a reason to spend the time. +* **Audit what a renderer silently SKIPS, not only what it draws.** `compose` has + half a dozen `continue` paths, and a sprite-name miss is one of them — an + element vanishes with no error, which is exactly how the port agent's missing + bracket happened. `screen render` already prints its omissions; reading that + list for the five screens that matter took one command and turned up a + full-screen opaque element dropped on three of them. Any composer with skip + conditions should be asked to name what it skipped before it is trusted. +* **An element's declared name is not necessarily its texture's name.** The + `opt ` link on `pteff05.t32` leads to a `T8aD` registered as `8AX`, so a + lookup by declared name misses. Before concluding a texture is absent, look at + the bytes the link actually points at — the name in the declaration table and + the name the sprite table keys on can differ. diff --git a/docs/re/structures/ui-8ax-fullres-background.md b/docs/re/structures/ui-8ax-fullres-background.md new file mode 100644 index 00000000..7db77327 --- /dev/null +++ b/docs/re/structures/ui-8ax-fullres-background.md @@ -0,0 +1,84 @@ +# 🟡 `pteff04` / `pteff05` are dropped — the texture is registered as `8AX` + +**Status:** 🟡 a real name-resolution gap, **currently harmless to look at**, and +the obvious fix would make the render *worse*. Found by auditing what +`screen render` silently omits on the port's five screens. + +## What `screen render` drops, and why + +`sylpheed-cli screen render` reports its omissions. On the five screens the port +needs, every one is accounted for except two: + +| screen | not drawn | reason | +|---|---|---| +| title (4) | `ptlogo1`×2, `ptlogo2`×2 | `kind & 0x4` ghost instances — the draw capture shows one quad per wordmark | +| | `pteff00.prm`, `pteff02.prm` | `.prm` primitives, off without `--primitives` | +| | `ptloop01.rat`, `ptloop02.rat` | `loop*` animations, off without `--animated` | +| | **`pteff04.t32`** | ⚠️ **unexplained — this page** | +| main menu (5), `EXTRAS` (6) | as above, plus **`pteff05.t32`** | ⚠️ same | +| splash (10, 11) | `palogo_eff0.prm` | primitive | + +`pteff04`/`pteff05` are `kind = 0x0`, one keyframe, rest **`a = 255`**, and pivot +`(640,360)` — i.e. a **full-screen, fully opaque** element. Exactly the shape of +the defect the port agent reported (an element the game draws that we omit). + +## The cause: the element's name and its texture's name differ + +Both names occur twice per bundle, the same as `pteff03.t32`, which resolves +fine. The difference is what follows the `opt ` link: + +``` +pteff03.t32 @0x4661a4 opt → T8aD ← resolves +pteff05.t32 @0x0e2035 opt → 8AX T8aD ← the sprite is named 8AX +``` + +Hex at `0x0e2035`: + +``` +opt .... 70 74 65 66 66 30 35 2e 74 33 32 00 38 41 58 54 38 61 44 + p t e f f 0 5 . t 3 2 \0 8 A X T 8 a D +``` + +So the declaration says `pteff05.t32` while the `T8aD` that follows is registered +under **`8AX`**. `compose` does `build.sprites.get(sprite)` and, on a miss, hits a +silent `continue`. `8AX` is a **1280×720** texture and appears in all six +title-family bundles (`a60fcb85`, `a715f485`, `a81c1d85` and the three JP twins); +it is a *sprite* in builds 4/5/6 and never an element. + +## ✅ Why it does not currently show + +The same artwork is already on screen. `ptbase.t32` is **640×360** and its +element draws at **200 %**, and the background our render produces is +pixel-identical to `8AX` in every patch sampled: + +| patch | capture | our render | `8AX` | +|---|---|---|---| +| top-left | 4.5, 9.4, 19.5 | **17.7, 29.7, 46.7** | **17.7, 29.7, 46.7** | +| top-right | 4.4, 9.0, 18.2 | 17.2, 28.2, 43.8 | 17.1, 28.2, 43.8 | +| bottom-left | 3.5, 6.0, 11.1 | 13.6, 20.5, 31.2 | 13.6, 20.5, 31.2 | + +Directly: `ptbase` upscaled 2× against `8AX` is **mean abs diff 2.05** (max 80), +not byte-identical. They are **the same art at two resolutions** — `8AX` is the +full-res copy, `ptbase` the half-res one the element scales back up. + +## ⚠️ So do not "fix" this by drawing it + +Resolving `pteff05 → 8AX` and drawing it *in addition to* `ptbase` would +**double-draw the background** — an opaque full-screen layer over an identical +one. It would not be visible as a doubling, which is worse: it would silently +cost fill and hide any future change to either layer. + +🟡 **The free win, if a port wants it:** use `8AX` at 1:1 and *drop* `ptbase`, +rather than upscaling a 640×360 copy 2×. That is a sharper background from a +texture already in the bundle. Not done here — it is a rendering choice, and +`ptbase`'s element carries the keyframes. + +## ❔ Not established + +* **Whether the game draws one, the other, or both.** The pixel evidence says + our background matches `8AX`'s art, which `ptbase` also carries — it cannot + separate them. A per-draw capture of the main menu recording texture *base + addresses* would, since the two textures are different sizes. +* The capture is ~4× darker than the render in these patches (4.5 vs 17.7), and + not by a constant ratio. That is a separate colour/gamma question, untouched + here.