Files
Sylpheed/docs/re/structures/ui-tie-break-cost-at-settle.md
sylph-decoder 3e731c68ce 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
2026-08-29 19:35:29 +00:00

5.6 KiB
Raw Blame History

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 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 pxptframe1×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 Δ 1ptlogo2×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.

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), and the title's ties are almost entirely between transients: ptlogo_back2eff1eff5 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):

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 t17t33 — 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. 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

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"