sylpheed-port found ptloop01/02 free-running in their renderer on the menu path, pinned them, and was explicit that pinning picks one pose rather than the game's: "a capture question, not a harness one". It is, and it lands in my lane. On the title it is now answered. Those leaves rest at (441,270) 200x90, INSIDE the box the ptlogo_eff3 era adjudication uses, and across my two JP captures from different sessions they are byte-identical: 0 of 18 000 px, max |d| 0, against a whole-frame contrast of 116 492 px differing. So they are static at rest, and the in-box between-session noise of 0.32 is not theirs -- the 645 differing pixels all lie in a 30-row band at y 99..128, nowhere near the loop rect. That also closes the reach caveat on the EN->JP noise transfer. The MENU is a different bundle and is not settled. Build 5 declares the same rect with a single static keyframe, and that is where their row drifted. menu_loop_rest.sh was written to capture five settled menu frames and diff the rect; it did not complete. The run reached a title at t=146 s and (A) did not take across six attempts -- the documented intermittency where the attract loop's title accepts nothing, unlike the boot title. Recorded rather than re-rolled. Two committed main-menu captures cannot substitute: they differ across 57 % of the surface (different geometries and capture paths), so the 88 % differing on the loop rect measures the mismatch, not the loops. The control fails and the comparison is void. navigation.md gains the trap that cost this iteration a run: kill -9 on xenia orphans /tmp/xenia-canary.lock, the next run-canary refuses to STDERR where a polling script never looks, and a probe then sampled a dead display for 484 s reporting `other` every 4 s -- because screen_id.py on an empty screen returns `other` and "not the title yet" is indistinguishable from "there is no emulator". Kill plainly so it clears its own lock, and assert the emulator is alive before entering any wait loop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
57 lines
2.6 KiB
Bash
Executable File
57 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Do ptloop01/02 ANIMATE on the settled main menu?
|
|
#
|
|
# sylpheed-port pinned a leaf phase for these and was explicit that doing so
|
|
# picks ONE pose rather than the one the game shows -- "a capture question, not a
|
|
# harness one". On the JP title, two captures from different sessions are
|
|
# byte-identical over the ptloop rect (0 of 18 000), so they do not free-run
|
|
# there. The menu is a different bundle and is where their row actually drifted.
|
|
#
|
|
# If the loops animate at all, consecutive frames of a SETTLED menu differ over
|
|
# their rect. A whole-frame count runs alongside as the contrast control: if the
|
|
# frame is entirely static the instrument cannot see motion and the zero is void.
|
|
#
|
|
# Usage: menu_loop_rest.sh OUTDIR
|
|
set -u
|
|
export HOME=/sylph-home/re SDL_AUDIODRIVER=dummy DISPLAY=:98
|
|
SD="$(cd "$(dirname "$0")" && pwd)"
|
|
OUT="${1:-/sylph-home/re/menuloop}"; mkdir -p "$OUT"
|
|
alive(){ ps -o pid=,stat= -C xenia_canary 2>/dev/null | awk '$2 !~ /^Z/ {print $1}'; }
|
|
shot(){ screenshot "$1" >/dev/null 2>&1; }
|
|
screen(){ shot /tmp/mlr.png; python3 "$SD/screen_id.py" /tmp/mlr.png | awk '{print $1}'; }
|
|
|
|
ps -o pid= -C xenia_canary | xargs -r kill -9
|
|
( cd "$OUT" && nohup run-canary --mem_watch=false \
|
|
--logged_profile_slot_0_xuid=B13EBABEBABEBABE \
|
|
>"$OUT/canary.stdout" 2>"$OUT/canary.stderr" & )
|
|
sleep 8
|
|
deadline=$(( SECONDS + 900 )); s=""
|
|
while [ $SECONDS -lt $deadline ]; do
|
|
s="$(screen)"; echo "t=${SECONDS}s $s"; [ "$s" = "title" ] && break; sleep 4
|
|
done
|
|
[ "$s" = "title" ] || { echo "NEVER REACHED THE TITLE"; exit 1; }
|
|
python3 "$SD/pad.py" tap A 0.5
|
|
for _ in 1 2 3 4 5 6; do sleep 4; s="$(screen)"; echo " after A: $s"; [ "$s" = "menu" ] && break; done
|
|
[ "$s" = "menu" ] || { echo "NO MENU (screen=$s)"; exit 2; }
|
|
sleep 6 # let the menu settle past its build-in
|
|
for i in 0 1 2 3 4; do shot "$OUT/menu-$i.png"; sleep 2; done
|
|
python3 - "$OUT" <<'PY'
|
|
import sys, numpy as np
|
|
from PIL import Image
|
|
out=sys.argv[1]
|
|
def load(i):
|
|
a=np.asarray(Image.open(f"{out}/menu-{i}.png").convert("RGB"),dtype=int)
|
|
return a, (45 if a.shape[0]>=716 else 0)
|
|
a0,o0=load(0)
|
|
print("\nptloop01/02 rect, 200x90 at design (441,270) -- do they move?")
|
|
for i in (1,2,3,4):
|
|
ai,oi=load(i)
|
|
la=a0[o0+270:o0+360, 441:641]; lb=ai[oi+270:oi+360, 441:641]
|
|
d=np.abs(la-lb)
|
|
h=min(a0.shape[0]-o0, ai.shape[0]-oi); w=min(a0.shape[1], ai.shape[1])
|
|
dw=np.abs(a0[o0:o0+h,:w]-ai[oi:oi+h,:w]).sum(axis=2)
|
|
print(f" frame {i} vs 0: loop rect {int((d.sum(axis=2)>0).sum()):6d}/18000 px max |d| {int(d.max()):3d}"
|
|
f" | CONTRAST whole frame {int((dw>0).sum()):7d} px")
|
|
PY
|
|
echo "MENU LOOP PROBE DONE"
|