sylpheed-port ran the signed-edge discriminator I proposed but could not execute -- it needs their render beside the capture. Recorded as their measurement, with their tool and commit. Controls against deliberately damaged copies of their own render: a known +1 px shift reads back as +0.938 px, a known blur as r -0.896 on the laplacian, neither leaking into the other's channel. The menu against the capture gives -0.010 px horizontal, -0.009 px vertical, laplacian r +0.103 -- and the weak blur term is the opposite sign to the blur control. So global misregistration and blur are both excluded, and of the three candidates I named the misplaced soft element is the only one left. Reach is the whole reach: a whole-frame fit excludes a global translation, not a local one, since one misplaced element is a small share of 38752 edge pixels. The next test is local and needs the residual map, which is theirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
7.3 KiB
✅ At least two thirds of the title's disagreement is GEOMETRY, not tone
⚠️ The 10.92 title baseline here could not be reproduced on 2026-08-29 —
screen render --build 4 --blackagainst the same capture gives 14.07 both atformats-pin-2026-08-29cand today. The ratio this document argues for may well survive; the absolute is in doubt. Separately, part of the title's residual is now known to be neither tone nor rotation butrest()posing five transient flashes at their peaks —ui-settle-time.mdcloses the light-arc band from 33.22 to 11.79.
Classification: measured, on committed captures. Answers a question the pending rotation decision needs: how much would drawing the rotation actually buy?
Two separate effects are known to make our renders differ from the console:
- the tone curve — the console renders midtones brighter than we do
(
ui-render-tone-curve.md), and its single-exponent model is refuted above render ≈ 40; - the missing rotation — our blit draws axis-aligned rectangles, so the
title's two tilted light sweeps land as upright bars
(
ui-keyframe-rotation.md).
They are confounded in any whole-frame number. This separates them.
Method, and why the split is an upper bound on tone
A per-level lookup table fitted on a screen is the most general tone model there is: it maps every render level to whatever capture level minimises the error, with no functional form assumed. Whatever such a LUT cannot close is, by construction, not a per-pixel-level effect — it is spatial.
So fitting a LUT on the screen itself and measuring what remains gives an upper bound on the tone share and a lower bound on the geometry share.
The positive control
The method must be able to close a residual that really is tone. On the main menu it does:
🔴 THE PREMISE OF THIS CONTROL WAS WRONG, corrected 2026-08-31. It read "where the port measures only 0.06 % of pixels differing, so geometry is essentially right". That 0.06 % is
verify-capture's, and it counts pixels surviving-threshold 25%— differing by more than ~64 levels. It is a gross-displacement detector by design, blind to sub-pixel offsets and antialiasing, which are exactly what a per-level LUT also cannot close. It says no gross displacement, not geometry is right, and I read one as the other.
sylpheed-portmeasured the screen directly (DECISIONS.mdat5738b83): after this LUT, the menu's residual is 6.94 on edge pixels against 2.20 on flat — 3.2×, with a known negative (a render against itself under a pure gamma) leaving exactly 0.00, since a per-level LUT inverts a per-level effect perfectly. So the menu carries spatial error and is not a geometry-free control. ⚠️ I have not reproduced that split — it needs their render beside the capture — and it is recorded as their measurement, not mine.✅ The result below does not rest on this control. "Whatever a fitted per-level LUT cannot close is, by construction, not a per-pixel-level effect" is stated as the method's basis above and stands on its own. What the control actually shows is narrower than claimed: the LUT closes 70 % of the menu's residual — evidence it works on tone, not evidence the menu is tone-only.
| mean abs difference | closed | |
|---|---|---|
| main menu, uncorrected | 9.26 | — |
| main menu + LUT fitted on the main menu | 2.75 | 70.3 % |
✅ The instrument works: a tone-dominated residual collapses by 70 %.
The result
| mean abs difference | closed | |
|---|---|---|
| title, uncorrected | 10.92 | — |
| title + LUT fitted on the title | 7.42 | 32.0 % |
🔴 At most 32 % of the title's disagreement is a tone effect, so at least 68 % is spatial — content in the wrong place. That is where the rotation lives, and it makes the rotation the dominant term by roughly two to one.
⚠️ The same-screen LUT is fitted, so 32 % is generous to tone. The true tone share is smaller and the geometry share larger.
🔴 And a claim this refutes: there is no single transferable tone curve
Fitting on one screen and applying to the other:
| closed | |
|---|---|
| main menu + LUT fitted on the title | +29.7 % |
| title + LUT fitted on the main menu | −24.0 % ✗ |
The menu's curve makes the title worse. A curve fitted on a dark, flat screen is unconstrained at the bright end — the menu's populated range is levels 5–204 with few bright pixels — and extrapolating it onto the title's planet and wordmark actively harms.
⚠️ So "the tone curve" is not one thing that can be measured once and applied.
This extends ui-render-tone-curve.md's refutation of
the single exponent: even a full per-level LUT fails to transfer between
screens. A consumer must not carry a global tone correction.
Reach
- Two screens, one capture each; the title capture is the plate-free frame and our render is at rest, so they are the same screen but not the same instant — a looser pairing than the port's posed comparison, which is why the absolute numbers here (10.92) are larger than its 1.81 % of pixels. ⚠️ The ratio is what this page claims, not the absolute level.
- Our render draws the sweeps' parent record only — the pre-leaf-fix state — so the geometry share measured here includes both the missing rotation and the missing leaf placement. Both are closed by the same decision.
✅ The menu's edge residual is NOT global misregistration, and not blur
Measured by sylpheed-port (tools/port/edge-residual-kind, branch
auto/port-p6-audio at f4351b0), running the discriminator I proposed but could
not execute — it needs their render beside the capture, which I do not have.
Recorded as their measurement.
The test, made concrete: a shift by (dx,dy) makes the signed residual track
the gradient, and the fitted slope is the shift in pixels; a blur makes it
track the laplacian, symmetric and directionless.
| control — a known +1 px shift | reads back +0.938 px (r +0.789) |
| control — a known blur | r −0.896 on the laplacian |
| neither leaked into the other's channel | ✅ |
main_menu vs the capture |
−0.010 px horizontal, −0.009 px vertical; laplacian r +0.103 |
❌ Global misregistration is excluded: any whole-frame translation is under a hundredth of a pixel, against a control that reads a true 1 px at 0.938. ❌ Blur is excluded: the weak laplacian term is the opposite sign to the blur control, so the capture is not a softened render either.
⚠️ The reach is the whole reach: this is a WHOLE-FRAME fit. One misplaced element is a small share of 38 752 edge pixels and would not move these numbers. It excludes a global translation, not a local one.
📌 So of the three candidates I named — misregistration, antialiasing, a misplaced soft element — the third survives, and it is the only one left. The next test is necessarily local: where does the edge residual concentrate spatially, and does that region correspond to one element? ⚠️ That needs the residual map, which is on the port's side; I can state the test and cannot run it.