port: the capture has NEW GAME focused, and my harness had been rendering no focus
The Decoder attached an honest caveat to its reproduction of the tone-curve
refutation -- its bins included the focus-state mismatch, so it was "not a clean
second opinion". Removing that caveat found a defect of mine.
IDENTIFYING THE FOCUSED BUTTON, with a known-answer control. Walking focus
through all five buttons and comparing each against a capture:
vs -options-focused vs live-main-menu
ptbtn01 NEW GAME 6351 531
ptbtn02 LOAD GAME 7087 7094
ptbtn03 TUTORIAL 6230 6237
ptbtn04 OPTIONS 1292 6364
ptbtn05 EXTRAS 6073 6080
The control picks OPTIONS by 4.7x -- the answer its own filename gives -- so the
test is trustworthy, and live-main-menu.png has NEW GAME focused by 11.5x. That
is what the port already focuses. Corroboration, NOT a decode: Q5's instability
stands (four boots gave TUTORIAL, TUTORIAL, NEW GAME, NEW GAME) and this
identifies one frame rather than a rule. Recorded in the authored entry.
THE DEFECT: `verify-capture` rendered menus with `--screen=`, which draws no
focus record, so it had been comparing main_menu to the oracle in a state the
oracle was never in.
main_menu 0.25% differing, RMSE 14.79 -> 0.06%, RMSE 13.21
extras 0.46%, RMSE 15.29 -> 0.20%, RMSE 13.38
A 4x improvement that was entirely my harness posing the port wrong rather than
the port drawing wrong. The first run of a new correctness harness reported a
discrepancy and three quarters of it was the harness.
AND THE DECODER'S CAVEAT RESOLVES TO NOTHING, measured rather than assumed:
re-deriving the transfer curve on the correctly-posed pair gives 1.20 / 1.26 /
1.18 / 1.10 / 1.03 / 0.94 at render 8..48, unchanged from the mismatched run. Its
reproduction stands as a second opinion after all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
@@ -40,12 +40,21 @@ OUT="${OUT:-$(mktemp -d)}"; mkdir -p "$OUT"
|
||||
CAPS=docs/re/captures/title-builds
|
||||
|
||||
# screen : capture : how to pose it
|
||||
# 🔴 A MENU CAPTURE HAS A BUTTON FOCUSED, AND THE FIRST VERSION OF THIS TOOL
|
||||
# RENDERED WITH NONE. `--screen=` draws no focus record at all, so `main_menu`
|
||||
# was being compared to the oracle in a state the oracle was never in: 2 159
|
||||
# differing pixels, of which 74 % sat inside the focus signature. Rendered with
|
||||
# focus it is 531 -- 0.06 % of the frame, a 4x improvement that was entirely my
|
||||
# harness posing the port wrong.
|
||||
#
|
||||
# `--menu=` applies `authored/flow.json`'s initial focus and `--script=wait`
|
||||
# shoots one settled frame and exits.
|
||||
MAP=(
|
||||
"main_menu:$CAPS/live-main-menu.png:--time=99"
|
||||
"extras:$CAPS/live-extras.png:--time=99"
|
||||
"title:$CAPS/live-title-build4-no-plate.png:--time=99"
|
||||
"publisher_logo:$CAPS/live-splash-publisher.png:--time=99"
|
||||
"developer_logos:$CAPS/live-splash-developer.png:--time=99"
|
||||
"main_menu:$CAPS/live-main-menu.png:menu"
|
||||
"extras:$CAPS/live-extras.png:menu"
|
||||
"title:$CAPS/live-title-build4-no-plate.png:screen"
|
||||
"publisher_logo:$CAPS/live-splash-publisher.png:screen"
|
||||
"developer_logos:$CAPS/live-splash-developer.png:screen"
|
||||
)
|
||||
CURVE=""
|
||||
if [ "${1:-}" = "--curve" ]; then CURVE=1; shift; fi
|
||||
@@ -59,8 +68,14 @@ for row in "${MAP[@]}"; do
|
||||
IFS=: read -r name cap pose <<<"$row"
|
||||
if [ ${#want[@]} -gt 0 ] && ! printf '%s\n' "${want[@]}" | grep -qx "$name"; then continue; fi
|
||||
[ -f "$cap" ] || { printf '%-17s %s\n' "$name" "no capture"; continue; }
|
||||
godot --path port --resolution 1280x720 -- "--screen=$name" "$pose" \
|
||||
"--capture=$OUT/$name.render.png" >"$OUT/$name.log" 2>&1 || true
|
||||
if [ "$pose" = menu ]; then
|
||||
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"
|
||||
else
|
||||
godot --path port --resolution 1280x720 -- "--screen=$name" --time=99 \
|
||||
"--capture=$OUT/$name.render.png" >"$OUT/$name.log" 2>&1 || true
|
||||
fi
|
||||
[ -f "$OUT/$name.render.png" ] || { printf '%-17s %s\n' "$name" "render failed"; continue; }
|
||||
# Crop the render to the capture's frame. The capture is the crop, not a scale.
|
||||
convert "$OUT/$name.render.png" -crop 1279x675+0+0 +repage "$OUT/$name.crop.png"
|
||||
@@ -68,7 +83,7 @@ for row in "${MAP[@]}"; do
|
||||
raw=$(python3 -c "print('%.2f' % (float('$raw')*255))" 2>/dev/null || echo "?")
|
||||
note=""
|
||||
case "$name" in
|
||||
main_menu|extras) note="focus state may differ from the capture" ;;
|
||||
main_menu|extras) note="rendered with authored initial focus" ;;
|
||||
title) note="ptloop sweeps never stop -- one moment vs another" ;;
|
||||
esac
|
||||
# Where the difference lives. This comes FIRST because it is what the gamma
|
||||
|
||||
Reference in New Issue
Block a user