re: the paint-order tie-break costs one pixel, on one screen we do not ship
Closes the open half of Q3. `ui-paint-order-derived-check.md` bounded WHERE a wrong tie-break could show -- overlapping same-key pairs -- and said outright that nobody had measured how many change a pixel. At the instant the player sees, the answer is: at most 1 px at max channel difference 1, on the JAPANESE title only (`ptlogo2` x `ptlogo_tm`, 5 px of shared ink). Exactly 0 px on all five port screens. The earlier 24-pair bound was counted at `rest()`, and 10 of the title's 11 overlapping tied pairs are between `ptlogo_back2eff1`..`eff5` -- the five transient flashes from the settle-time finding, transparent on the settled screen. A tie between two invisible elements cannot cost a pixel. Not a knife-edge. Sweeping every keyframe time and every midpoint between keyframe times, the live-pair count is flat across the ENTIRE settle window: 1 on the EN title, 2 on the JP title, 0 on all four loading bundles -- whose tie is live only at t17..t33, during the build-in, which matters because their settle windows are narrow enough to deserve little trust otherwise. Controls: every entry reporting zero also swaps an overlapping DIFFERENT-key pair, which must and does move pixels (25 310 / 268 698 / ~765 000 px). Zeros are explained by shared-ink counts rather than asserted -- the `ptframe` pairs overlap by bounding box and share 0 px of ink. Entries 0/1/12/15 have NO live control and their zeros rest on keyframe data rather than a render; recorded as the weaker claim it is. Refutation attempt on the corpus's "24 overlapping pairs": it SURVIVES as a rest-pose count -- an independent recount reproduces entry 7's 16 exactly. What is overturned is its interpretation as the risk surface. `tie_break_pixel_cost` gains a settle-time case and an alpha/scale filter on its rect test; `tie_cost_over_time` is new. Also strips 611 bytes of captured cargo warnings from the head of the committed tie census. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
# ✅ Does the derived paint order reproduce the measured ones? Mostly — and the gap is bounded
|
||||
|
||||
> ✅ **The open half of this page is closed (2026-08-29): the tie-break's pixel
|
||||
> cost is measured.** At the instant the player sees, it is **at most one pixel at
|
||||
> Δ1, on the Japanese title only, and exactly zero on all five port screens** —
|
||||
> [`ui-tie-break-cost-at-settle.md`](ui-tie-break-cost-at-settle.md). The 24-pair
|
||||
> bound below is a **`rest()` count** and survives as such (entry 7's 16
|
||||
> reproduces exactly), but 10 of the title's 11 pairs are between elements that
|
||||
> are *transparent* on the settled screen. Why the game orders ties as it does is
|
||||
> still unknown, and now costs one pixel.
|
||||
|
||||
**Status:** ✅ **checked, with numbers.** `compose` uses a paint order *measured
|
||||
from the running game* for the builds that have one and falls back to
|
||||
`derived_paint_order` — a sort on each sprite's layer key — everywhere else. The
|
||||
|
||||
118
docs/re/structures/ui-tie-break-cost-at-settle.md
Normal file
118
docs/re/structures/ui-tie-break-cost-at-settle.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# What the paint-order tie-break actually costs: one pixel, on one screen
|
||||
|
||||
**Classification: decoded.** Both terms come from the disc — the pairs from the
|
||||
keyframe table, the pixels from rendering the same bundle twice with two
|
||||
elements swapped. No capture is involved, and none is needed: this measures how
|
||||
much a *wrong* answer could cost, not which answer is right.
|
||||
|
||||
## The question this closes
|
||||
|
||||
[`ui-paint-order-derived-check.md`](ui-paint-order-derived-check.md) bounds
|
||||
*where* a wrong tie-break could show — same-layer-key pairs whose rects overlap —
|
||||
and says outright that **nobody has measured how many of them change a pixel**.
|
||||
That was the last open half of Q3.
|
||||
|
||||
## The answer
|
||||
|
||||
**At the instant the player actually sees, the tie-break costs at most one pixel,
|
||||
at a maximum channel difference of 1, and only on the Japanese title. On all five
|
||||
port screens it is exactly zero.**
|
||||
|
||||
| entry | screen | live tied pairs at settle | measured cost |
|
||||
|---|---|---|---|
|
||||
| 4 | title (EN) | 1 | **0 px** — the pair is `ptloop01`×`ptloop02`, not both drawn |
|
||||
| 5 | main menu | 2 | **0 px** — `ptframe1`×`ptframe2` share **no ink**; the other is undrawn |
|
||||
| 6 | submenu | 2 | **0 px** — same shape |
|
||||
| 8 | submenu | 2 | **0 px** — same shape |
|
||||
| 9 | submenu | 2 | **0 px** — same shape |
|
||||
| 7 | title (JP) | 2 | **1 px, max Δ 1** — `ptlogo2`×`ptlogo_tm`, 5 px of shared ink |
|
||||
| 0, 1, 12, 15 | loading | **0** | no pair is live at all |
|
||||
|
||||
Full run: [`tie-break-pixel-cost-gp_title.txt`](../data/tie-break-pixel-cost-gp_title.txt).
|
||||
|
||||
## Why the number moved: `rest()` was counting elements that are not there
|
||||
|
||||
The census that produced the earlier bound posed every element at `rest()`, its
|
||||
own last hold keyframe. That draws **transients at their peak**
|
||||
([`ui-settle-time.md`](ui-settle-time.md)), and the title's ties are almost
|
||||
entirely *between transients*: `ptlogo_back2eff1`…`eff5` are five staggered
|
||||
two-frame flashes, all extinguished by t110, and they account for 10 of the
|
||||
title's 11 overlapping tied pairs.
|
||||
|
||||
A tie between two elements that are transparent cannot cost a pixel however much
|
||||
their rects overlap. Posing at the settle time instead:
|
||||
|
||||
| | entry 4 | entry 7 | entries 0/1/12/15 |
|
||||
|---|---|---|---|
|
||||
| overlapping tied pairs at `rest()` | 11 | 13 | 1 each |
|
||||
| **still live at the settle time** | **1** | **2** | **0** |
|
||||
|
||||
## It is not a knife-edge
|
||||
|
||||
The obvious objection is that "at the settle time" picks one instant, and a
|
||||
different instant might give a different count. Sweeping every keyframe time and
|
||||
every midpoint between keyframe times
|
||||
([`tie-break-live-over-time-gp_title.txt`](../data/tie-break-live-over-time-gp_title.txt)):
|
||||
|
||||
| entry | peak live pairs over the whole timeline | **max anywhere in the settle window** |
|
||||
|---|---|---|
|
||||
| 4 | 6 | **1** |
|
||||
| 7 | 6 | **2** |
|
||||
| 5 / 6 / 8 / 9 | 2 | 2 |
|
||||
| 0 / 1 / 12 / 15 | 1 | **0** |
|
||||
|
||||
The count is **flat across the entire window**, not just at its midpoint. The four
|
||||
loading bundles are the sharpest case: their tie is live only at t17–t33 — during
|
||||
the build-in — and dead everywhere else, which matters because their settle
|
||||
windows are narrow (4 and 8 units) and would otherwise deserve little trust.
|
||||
|
||||
## Controls
|
||||
|
||||
* ✅ **A live control on every entry that reports a zero.** Each run also swaps an
|
||||
overlapping pair with **different** keys — an order the game demonstrably does
|
||||
care about — and requires it to move pixels. It moves 25 310 px on the title,
|
||||
268 698 px on the JP title, and ~765 000 px on the four menu screens.
|
||||
* ⚠️ **Entries 0, 1, 12, 15 have no live control** ("no overlapping different-key
|
||||
pair is drawn"). Their zeros rest on the *keyframe data* — no tied pair has both
|
||||
elements opaque at any instant in the window — not on a render, so a dead
|
||||
control does not undermine them. But nothing here demonstrates the renderer
|
||||
would notice a swap on those bundles.
|
||||
* ✅ **Shared-ink accounting.** A zero is only meaningful with an explanation. The
|
||||
`ptframe` pairs overlap by bounding box and share **0 px** of actual ink; the
|
||||
JP title's 1 px comes from 5 px of shared ink between `ptlogo2` and
|
||||
`ptlogo_tm`.
|
||||
|
||||
## 🟡 Refutation attempt: the corpus's "24 overlapping pairs" — it survives
|
||||
|
||||
Recounted independently. Without the alpha/scale filter this document adds, the
|
||||
per-entry counts are `e0:1 e1:1 e4:13 e5:2 e6:2 e7:16 e8:2 e9:2 e12:1 e15:1`,
|
||||
total 41 — and **entry 7's 16 reproduces the corpus's figure exactly**. The 24 is
|
||||
that population scoped to the entries without a measured order. Adding the filter
|
||||
takes the total to 36.
|
||||
|
||||
So the count stands as a **rest-pose upper bound**. What this document overturns
|
||||
is its *interpretation*: 24 was being read as the surface on which a wrong
|
||||
tie-break could show, and at the instant the player sees, that surface is one
|
||||
pixel.
|
||||
|
||||
## Reach and what is still open
|
||||
|
||||
❔ **Why the game orders ties as it does is still unknown**, and this does not
|
||||
touch it — eight candidate rules remain refuted in
|
||||
[`ui-paint-order-derived-check.md`](ui-paint-order-derived-check.md). What changes
|
||||
is that the question is no longer worth much: getting it wrong costs one pixel on
|
||||
a screen the port does not ship.
|
||||
|
||||
⚠️ **`GP_TITLE` only.** Other paks were not swept. The method is bundle-agnostic
|
||||
but the numbers are not.
|
||||
|
||||
⚠️ **Rect overlap is still an approximation** (pivot doubled, placed at the pose).
|
||||
It is used only to *choose candidate pairs*; every reported cost is a real render
|
||||
diff, so the approximation can add candidates but cannot invent a cost.
|
||||
|
||||
## Reproducing
|
||||
|
||||
```bash
|
||||
cargo run -p sylpheed-formats --example tie_break_pixel_cost -- "$SYLPHEED_DISC/dat/GP_TITLE.pak"
|
||||
cargo run -p sylpheed-formats --example tie_cost_over_time -- "$SYLPHEED_DISC/dat/GP_TITLE.pak"
|
||||
```
|
||||
Reference in New Issue
Block a user