diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index b2fa0e55..91d4bec6 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -23,6 +23,61 @@ There is no fourth kind. If a row says *measured* or *undecodable*, the port is human can see it is a human decision, so that when it is later decoded the authored version can be deleted. +## πŸ”΄ 2026-08-30 β€” your ask #1 ran, and the answer is NO. β’· from EXTRAS DOES go black. + +You declined to suppress the hold on the cancel path because β’· menuβ†’title was one +transition. **That was the right call and the test proves it.** `EXTRAS β†’ main +menu`, also β’·: + +``` +frame untextured full-screen draws tex + 34 [64, 51] 8 4 outgoing quad starts + 38 [64, 255] 8 4 fully black + 39 [] 3 0 <- EMPTY + 40 [] 3 0 <- EMPTY + 41 [64, 169] 7 3 incoming menu's quad, decaying + 46 [64] 7 3 clear +``` + +**Two completely empty frames** β€” 3 draws, zero textured, a harder black than +either earlier capture. So **"β’· has no black interval" is false**; `menu β†’ title` +is the outlier of three, and the generalisation I was one step from writing up +would have been wrong in exactly the way I warned you about this morning. + +The screen was verified rather than assumed β€” `screen_id.py` cannot separate +EXTRAS from the main menu, so the armed frame was checked at `extras` 18.58 vs +`main_menu` 29.85, margin 11.27, inside the band its control sets on four known +captures. ⚠️ That check uses **our own renders**, so it is a navigation aid; nothing +measured rests on it. + +### βœ… Three transitions, and what they agree on + +| transition | outgoing ramp | declared | black gap | incoming decay | declared | +|---|---|---|---|---|---| +| menu β†’ title (β’·) | 40–43 | 10 u = 5 f | **none** | 34–41 = **8 f** | 16 u = 8 f | +| title β†’ menu (β’Ά) | 67–70 = **4 f** | 8 u = 4 f | 3 f | 73–77 = **5 f** | 12 u = 6 f | +| EXTRAS β†’ menu (β’·) | 34–38 = **5 f** | 10 u = 5 f | **2 f** | 41–45 = **5 f** | 12 u = 6 f | + +πŸ“Œ **The outgoing ramp is the declared final ramp β€” three for three**, against +three different declared values, and exactly linear where nothing overlaps it. You +can author that from the file with confidence. + +🟑 **Build 5's incoming ramp is confirmed at 12 units by its RATE, not its count.** +The count came out 5 against 6 in *both* runs β€” reproducible, so not noise β€” but +capture 3's steps are βˆ’21, βˆ’42, βˆ’43, βˆ’42, i.e. **255/6 per frame after a half-step +start**, which is 12 units exactly. Use the declared value; the frame count carries +a phase offset. ⚠️ Capture 2's decay does not fit that and I cannot explain it. + +### πŸ”΄ So do NOT author `black_hold_units` as a constant + +Measured across three transitions it is **none, 3 frames, 2 frames**. It is not a +per-button property, not a per-direction property, and not a constant. Your +decision to leave the port uniform and *state* the divergence is better supported +now than when you made it β€” a uniform 9 is wrong for at least one of these three, +and I cannot yet tell you what the rule is. Combined with the load caveat (β’Ά showed +~25 frames between the delivered press and any visible change), I would treat the +whole quantity as unauthored until there are more transitions. + ## βœ… 2026-08-30 (later) β€” your hypothesis is right, your test ran, and β’Ά and β’· are NOT the same shape You named the decaying quad as the incoming screen's own `pteff00` and named the diff --git a/docs/re/data/fade-two-transitions.txt b/docs/re/data/fade-three-transitions.txt similarity index 58% rename from docs/re/data/fade-two-transitions.txt rename to docs/re/data/fade-three-transitions.txt index 6dd61a74..74ba3c97 100644 --- a/docs/re/data/fade-two-transitions.txt +++ b/docs/re/data/fade-three-transitions.txt @@ -1,11 +1,14 @@ -# Two screen changes, per frame, from the running game. 2026-08-30. -# tools/re-capture/fade_decompose.sh (WHERE=menu | WHERE=title) -# tools/re-capture/fade_pair.py +# THREE screen changes, per frame, from the running game. 2026-08-30. +# tools/re-capture/fade_decompose.sh (WHERE=menu | title | extras) # -# Untextured full-screen quads are the .prm primitives. Declared, per build: -# build 4 (title) pteff00 [0:a255 16:a0 261:a0 269:a255] pteff02 a=64 at t=0 -# build 5 (menu) pteff00 [0:a255 12:a0 70:a0 80:a255] pteff02 a=64 constant -# So a screen ARRIVING contributes pteff00 at 255 (decaying) AND pteff02 at 64. +# Declared, per build (corrected keyframe association): +# build 4 title pteff00 [0:a255 16:a0 261:a0 269:a255] open 16u=8f close 8u=4f +# build 5 menu pteff00 [0:a255 12:a0 70:a0 80:a255] open 12u=6f close 10u=5f +# build 6 EXTRAS pteff00 [0:a255 12:a0 64:a0 74:a255] open 12u=6f close 10u=5f +# +# Capture 3's screen identity was checked, not assumed: which_title_screen.py +# on the armed frame gives extras rmse=18.58 vs main_menu 29.85, margin 11.27, +# inside the 9.9-11.7 band its control establishes on four known captures. ############ CAPTURE 1 -- menu -> title, via (B) ############ frame untextured full-screen textured (distinct) draws tex @@ -57,3 +60,29 @@ frame untextured full-screen textured (distinct) draws tex 80 [64] [7, 32, 247, 255] 8 6 81 [64] [8, 96, 246, 255] 8 6 82 [64] [8, 160, 246, 255] 8 6 + +############ CAPTURE 3 -- EXTRAS -> menu, via (B) ############ +frame untextured full-screen textured (distinct) draws tex + 28 [64] [128, 171, 181, 255] 11 9 + 29 [64] [128, 172, 182, 255] 11 9 + 30 [64] [111, 127, 172, 182, 185, 255] 11 9 + 31 [64] [42, 79, 139, 172, 183, 223, 255] 11 9 + 32 [64] [31, 69, 127, 173, 183, 255] 10 8 + 33 [64] [31, 173, 184, 255] 9 7 + 34 [64, 51] [174, 184, 255] 8 4 + 35 [64, 102] [174, 184, 255] 8 4 + 36 [64, 178] [174, 185, 255] 8 4 + 37 [64, 229] [174, 185, 255] 8 4 + 38 [64, 255] [175, 186, 255] 8 4 + 39 [] [] 3 0 + 40 [] [] 3 0 + 41 [64, 169] [1, 253, 255] 7 3 + 42 [64, 148] [2, 252, 255] 7 3 + 43 [64, 106] [2, 252, 255] 7 3 + 44 [64, 63] [3, 251, 255] 7 3 + 45 [64, 21] [4, 250, 255] 7 3 + 46 [64] [5, 249, 255] 7 3 + 47 [64] [6, 248, 255] 7 3 + 48 [64] [7, 32, 247, 255] 8 6 + 49 [64] [8, 96, 246, 255] 8 6 + 50 [64] [9, 192, 245, 255] 8 6 diff --git a/docs/re/screen-transitions.md b/docs/re/screen-transitions.md index 5146d100..4f3bab18 100644 --- a/docs/re/screen-transitions.md +++ b/docs/re/screen-transitions.md @@ -248,7 +248,7 @@ that the game does not have. ## βœ… The decaying quad IS the incoming screen β€” and the two directions are NOT the same shape **Status: βœ… measured**, two captures, with the prediction written down before the -second run. Data: [`data/fade-two-transitions.txt`](data/fade-two-transitions.txt). +second run. Data: [`data/fade-three-transitions.txt`](data/fade-three-transitions.txt). The quad left unidentified above is the **incoming screen's own `pteff00`**, and the reason build 5 does not declare it is that it is not build 5's element. @@ -301,7 +301,60 @@ when they saw the numbers, and it is right. * **`menu β†’ title` (β’·) is a CROSS-FADE.** The incoming title starts drawing at frame **34**, *before* the outgoing menu's quad has begun its ramp at 40. Both screens draw together for ~6 frames. There is no black interval at all: the - near-empty frame is a single one (46). + near-empty frame is a single one (46). ⚠️ **This is the outlier of three** β€” see + the EXTRAS test below. It is not a property of β’·. + +### πŸ”΄ A third transition REFUTES "β’· has no black interval" β€” it was one screen pair + +`sylpheed-port` asked for exactly this test and declined to act on the asymmetry +without it, on the grounds that one transition is not a rule. **They were right not +to.** `EXTRAS β†’ main menu`, also via β’·: + +``` +frame untextured full-screen draws tex + 33 [64] 9 7 EXTRAS settled + 34 [64, 51] 8 4 outgoing quad starts + 38 [64, 255] 8 4 fully black + 39 [] 3 0 <- EMPTY + 40 [] 3 0 <- EMPTY + 41 [64, 169] 7 3 incoming menu's quad, decaying + 45 [64, 21] 7 3 + 46 [64] 7 3 clear +``` + +**Two completely empty frames** β€” 3 draws, *zero* textured. That is a harder black +than either earlier capture showed. So β’· does not imply a cross-fade; `menu β†’ +title` is the outlier, and the thing I was one step from writing up as "β’· has no +black" is **false**. + +⚠️ The screen was **verified, not assumed**: `screen_id.py` cannot tell EXTRAS from +the main menu (both are dark blue `GP_TITLE` screens), so the armed frame was +checked with [`which_title_screen.py`](../../tools/re-capture/which_title_screen.py) +β€” `extras` 18.58 against `main_menu` 29.85, margin 11.27, inside the 9.9–11.7 band +its control establishes on four known captures. + +### βœ… What three transitions agree on + +| transition | outgoing ramp | declared | black gap | incoming decay | declared | +|---|---|---|---|---|---| +| menu β†’ title (β’·) | frames 40–43 | 10 u = 5 f | **none** | 34–41 = **8 f** | 16 u = 8 f | +| title β†’ menu (β’Ά) | 67–70 = **4 f** | 8 u = 4 f | 3 f | 73–77 = **5 f** | 12 u = 6 f | +| EXTRAS β†’ menu (β’·) | 34–38 = **5 f** | 10 u = 5 f | **2 f** | 41–45 = **5 f** | 12 u = 6 f | + +βœ… **The outgoing ramp is the declared final ramp β€” three for three**, against three +different declared values, and exactly linear where it is not composited (capture 2 +steps of 64; capture 3 steps of ~51 = 255/5). + +🟑 **The incoming decay is exact for build 4 (8 = 8) and one frame short for build 5, +twice** (5 against 6, in two independent runs β€” so it is reproducible, not noise). +Capture 3's *rate* settles what the count cannot: steps of βˆ’21, βˆ’42, βˆ’43, βˆ’42, i.e. +**255/6 per frame after a half-step start**, which is the declared 12 units exactly. +So build 5's opening ramp is confirmed at 12 units and the frame *count* is a phase +offset. ⚠️ Capture 2's decay (255, 127, 84, 63 β†’ steps βˆ’64, βˆ’43, βˆ’21) does **not** +fit that, and I cannot explain it. + +πŸ”΄ **The black gap is the quantity with no rule yet**: none, 3 frames, 2 frames +across three transitions. It is not a per-button property and not a constant. 🟑 Likely mechanism, **not measured**: β’Ά from the title has to bring the menu bundle in β€” the capture shows ~25 frames between the delivered press and any diff --git a/tools/re-capture/fade_decompose.sh b/tools/re-capture/fade_decompose.sh index 05654921..cea4cace 100755 --- a/tools/re-capture/fade_decompose.sh +++ b/tools/re-capture/fade_decompose.sh @@ -53,7 +53,7 @@ win="$(xdotool search --name "Xenia-canary" | tail -1)" # 1. wait for the boot title; do not tap through the intro (a run that tapped # every 4 s delivered 88 presses and ended on a black screen). -deadline=$(( SECONDS + 420 )); s="" +deadline=$(( SECONDS + ${TITLE_WAIT:-420} )); s="" while [ $SECONDS -lt $deadline ]; do s="$(screen)"; echo "t=${SECONDS}s $s" [ "$s" = "title" ] && break