diff --git a/authored/rendering.json b/authored/rendering.json index c07df108..84ae7abc 100644 --- a/authored/rendering.json +++ b/authored/rendering.json @@ -13,19 +13,29 @@ "one consistent time, then PREDICTED the quad centres to ~11 px. That covers", "`ptloop01` and `ptloop02` and nothing else." ], - "draw_leaf_for": ["ptloop01", "ptloop02"], + "draw_leaf_for": [ + "ptloop01", + "ptloop02" + ], "draw_leaf_why": [ "The two the decode covers. `docs/re/structures/ui-leaf-vs-parent-alpha.md`.", "", "NOT DRAWN, though the exporter flags them and ships their data:", "", - " `title_jp/ptlogo_eff2` -- parent 125% at (412,96), leaf 100% at (402,66).", - " It is the same SHAPE as the ptloop case and it is the element DECISIONS has", - " recorded since P1 as the largest render disagreement in the export. The", - " Decoder said in as many words: 'I have not tested it.' Drawing it would be", - " extending a decode past the case it was fitted on, which is the failure", - " this port has made four times this session.", + " `title_jp/ptlogo_eff2` -- OUT OF SCOPE, which is a better reason than", + " the caution this entry first gave. MISSION section 7 scopes out", + " 'localisation beyond English', and this element exists only on the", + " Japanese title. So it is not a thing the menu port has to answer, and the", + " parked Japanese-locale capture does not need reviving on its account --", + " that is the human's call and not something either agent widens quietly.", "", + " It is ALSO undecidable here even if it were in scope. Its 125% is a POP,", + " not a steady scale: scale-0 -> 125% -> scale-0 between t=50 and t=107,", + " about 0.95 s. The leaf draws at 100%, as two superimposed copies at alpha", + " 160 and 80, each rotating 360 degrees over 960 units -- 16 s a turn. If", + " parent scale gates the leaf it is a 0.95 s flash; if the leaf runs free it", + " spins for 16 s. Nothing on the disc chooses and title_jp has no oracle", + " capture.", " `build_12,15/pgloading_loop5` -- leaf scale (0,0). A zero scale is one of", " the three historical failures this corpus names, so it is exactly where a", " guess is most expensive.", diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 39f96a94..27e6d0b7 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -4257,3 +4257,56 @@ at alpha 160 and 80, each rotating 360° over 960 units — 16 s per revolution. **If parent scale gates the leaf it is a 0.95 s flash; if the leaf runs free it spins for 16 s.** Nothing on the disc chooses, `title_jp` has no oracle capture, and the Japanese-locale capture MISSION has parked is what would settle it. + +## The 11.5 px was the fit's resolution, and the lesson inverts + +The Decoder closed it **by adding observables, not by tuning** — the vertex +buffer carries positions *and* colours at the same instant, so all four +quantities must agree on one `t`: + +| observable | solved t | precision | +|---|---|---| +| quad A x | **357.88** | ±0.12 units | +| quad B x | **357.58** | ±0.12 units | +| quad A alpha | 355.75 | ±1.54 units | +| quad B alpha | 354.09 | ±1.89 units | + +Alpha moves only 0.27–0.33 levels per keyframe unit, so **one byte of +quantisation is worth 1.5–1.9 units, which at 4 px/unit is 6–8 px of sweep**. +That is the whole of the 11.5 px. At t = 357.7 the centres land within 0.70 px +and both alphas inside one level. + +⚠️ **The lesson is the earlier one inverted, and this is the half worth keeping.** +Checking a wrong rule against alpha made it *look confirmed*. Here the same +insensitivity **manufactured a residual that did not exist**. So an insensitive +quantity does not merely fail to falsify — **it invents error.** Solve on the +fastest-moving field; check the slow one; never the reverse. + +I was already looking for a pivot rule to explain 11.5 px when they wrote. There +was nothing to find. + +### Refutation attempt — the pivot claim, checked here and survived with a nuance + +They state the leaf pivot is (200, 90) on a 399×180 sprite, *"the pivot is the +centre, so rotation displaces it by nothing."* Checked against my own export: +pivot **[200, 90]**, sprite **399×180**, true centre **199.5, 90**. + +✅ Survives. ⚠️ With one correction of no consequence: the sprite is **odd-width**, +so the pivot is the centre to within **half a pixel**, not exactly. Against their +−0.70/−0.48 px agreement that changes nothing, and it is worth stating only +because "displaces it by nothing" is the kind of sentence that later gets leaned +on for a sub-pixel claim. + +`verify-capture` now poses the title at **t=357.7** rather than 355: RMSE +21.07 → **20.92**, differing 1.82 % → **1.81 %**. Marginal, and it is the right +pose for a stated reason rather than a better number. + +### `ptlogo_eff2` is withheld for a better reason than mine + +I was withholding it out of caution about untested generalisation. The Decoder +points out something stronger: **it is on `title_jp`, and MISSION §7 scopes out +"localisation beyond English"** — so it is not a question the menu port has to +answer at all, and the parked Japanese-locale capture does not need reviving on +its account. `authored/rendering.json` now says that first and the undecidability +second. **Widening scope to close a residual would have been the wrong trade**, +and it is the human's call either way. diff --git a/tools/port/verify-capture b/tools/port/verify-capture index 1205ba3d..a92bd518 100755 --- a/tools/port/verify-capture +++ b/tools/port/verify-capture @@ -52,18 +52,29 @@ CAPS=docs/re/captures/title-builds MAP=( "main_menu:$CAPS/live-main-menu.png:menu" "extras:$CAPS/live-extras.png:menu" - # ⚠️ THE TITLE IS POSED AT t=355 UNITS, NOT AT ITS SETTLE, and the time is + # ⚠️ THE TITLE IS POSED AT t=357.7 UNITS, NOT AT ITS SETTLE, and the time is # MEASURED rather than chosen. The two `ptloop` sweeps are a continuous # animation whose leaf group ends at t=600 with the quads parked off-screen at # x=1521, so posing at the settle compares a still frame against a capture - # taken mid-sweep and simply omits them. The Decoder fitted t=355 from the - # game's own composed alpha -- per-draw vertex colours 195 and 182 against the - # two leaf ramps -- and the same t then predicted the quad centres to ~11 px. + # taken mid-sweep and simply omits them. + # + # t=357.7 is the Decoder's REFINED fit, and the refinement is worth knowing. + # Its first value, 355, came from the two per-draw alpha bytes alone and left + # an 11.5 px residual that looked like a pivot problem. Solving the same + # instant on the vertex POSITIONS instead gives t=357.88 and 357.58 to + # +/-0.12 units, against +/-1.54 and +/-1.89 from the alphas -- alpha moves + # only 0.27-0.33 levels per unit, so one byte of quantisation is worth 6-8 px + # of sweep. At 357.7 the centres land within 0.70 px and both alphas inside one + # level. THE 11.5 px WAS THE FIT'S RESOLUTION, NOT GEOMETRY. + # + # ⚠️ And there is no pivot correction: the leaf pivot is (200, 90) on a 399x180 + # sprite, so it is the centre to within half a pixel -- checked here against + # the export rather than taken. # # ⚠️ It is NOT the time that minimises the difference: t=390 measures 1.65 % # against 1.82 % here. Picking that one would be fitting the pose to the # score, which is the thing this harness exists not to do. - "title:$CAPS/live-title-build4-no-plate.png:t355" + "title:$CAPS/live-title-build4-no-plate.png:t357" "publisher_logo:$CAPS/live-splash-publisher.png:screen" "developer_logos:$CAPS/live-splash-developer.png:screen" ) @@ -83,8 +94,8 @@ for row in "${MAP[@]}"; do godot --path port --resolution 1280x720 -- "--menu=$name" --script=wait \ "--shots=$OUT/$name" >"$OUT/$name.log" 2>&1 || true [ -f "$OUT/${name}_00_start.png" ] && cp "$OUT/${name}_00_start.png" "$OUT/$name.render.png" - elif [ "$pose" = t355 ]; then - godot --path port --resolution 1280x720 -- "--screen=$name" --time=5.9167 \ + elif [ "$pose" = t357 ]; then + godot --path port --resolution 1280x720 -- "--screen=$name" --time=5.9617 \ "--capture=$OUT/$name.render.png" >"$OUT/$name.log" 2>&1 || true else godot --path port --resolution 1280x720 -- "--screen=$name" --time=99 \ @@ -98,7 +109,7 @@ for row in "${MAP[@]}"; do note="" case "$name" in main_menu|extras) note="rendered with authored initial focus" ;; - title) note="posed at t=355, the Decoder's fitted sweep time" ;; + title) note="posed at t=357.7, the Decoder's refined sweep fit" ;; esac # Where the difference lives. This comes FIRST because it is what the gamma # sweep has to be protected from.