#!/usr/bin/env python3 """Wait for the interactive title, press Ⓐ once, and watch what happens. The A/B this exists for: does a signed-in profile prevent the Ⓐ fault (`docs/re/structures/title-a-press-fault.md`)? A press sent before the title is up tests nothing, so the wait is a **control on the press**, not a convenience — `is_title.py`'s glyph counter has to clear its threshold first. wait_and_press.py OUTDIR [wait_s] [watch_s] 🔴 The first version of this used a SINGLE frame over a glyph threshold, and it fired on the intro MOVIE — twice, voiding both legs of an A/B. The movie throws green flashes of 1298…5433 lasting under a second, which clears any threshold the title also clears. This is the same trap `is_title.py` records `screen_id.py` falling into (the SQUARE ENIX logo called "title" 151 s in). The title is distinguished by the **plate's pulse**, not by brightness: a sustained oscillation that never drops below ~700 and never exceeds ~1600 (`docs/re/structures/plate-pulse-measured.md` measured 714…1520). So the detector requires HOLD consecutive samples inside a band. A movie flash is 2–4 samples and overshoots the top of it. """ import os import subprocess import sys import time import numpy as np from PIL import Image OUT = sys.argv[1] WAIT = float(sys.argv[2]) if len(sys.argv) > 2 else 420 WATCH = float(sys.argv[3]) if len(sys.argv) > 3 else 90 W, H = 1280, 720 NEED = 500 # the plate is up; the floor with no plate is 159 CEIL = 2500 # a movie flash overshoots this; the plate peaks at ~1520 HOLD = 12 # consecutive in-band samples (~3 s at 4 Hz) def _open(): return subprocess.Popen( ["ffmpeg", "-loglevel", "error", "-f", "x11grab", "-draw_mouse", "0", "-video_size", f"{W}x{H}", "-i", ":98", "-r", "4", "-f", "rawvideo", "-pix_fmt", "rgb24", "-"], stdout=subprocess.PIPE, bufsize=W * H * 3 * 2) def glyph(a): r, g, b = a[:, :, 0], a[:, :, 1], a[:, :, 2] return int(((g > 130) & (g - r > 45) & (g - b > 45)).sum()) p, n, t0, seg = _open(), W * H * 3, time.time(), time.time() log = open(f"{OUT}/series.tsv", "w") log.write("# t_s\tglyph\tmean\tphase\n") phase, pressed_at, streak = "wait", None, 0 while True: el = time.time() - t0 if phase == "wait" and el > WAIT: print(f"TITLE NEVER APPEARED in {WAIT}s"); break if phase == "watch" and time.time() - pressed_at > WATCH: print("watch window complete"); break if time.time() - seg > 30: p.kill(); p = _open(); seg = time.time() buf = p.stdout.read(n) if len(buf) < n: p.kill(); p = _open(); seg = time.time(); continue a = np.frombuffer(buf, np.uint8).reshape(H, W, 3).astype(int) c = glyph(a) log.write(f"{el:.3f}\t{c}\t{a.mean():.3f}\t{phase}\n"); log.flush() if phase == "wait": streak = streak + 1 if NEED <= c <= CEIL else 0 if phase == "wait" and streak >= HOLD: Image.fromarray(a.astype(np.uint8)).save(f"{OUT}/before-press.png") print(f"TITLE UP at {el:.1f}s (glyph {c}, {streak} in-band samples) — pressing A") subprocess.run([sys.executable, os.path.join(os.path.dirname(os.path.abspath(__file__)), "pad.py"), "tap", "A", "0.12"], check=False) pressed_at = time.time(); phase = "watch" p.kill() # a last frame, whatever state it ended in try: p2 = _open(); buf = p2.stdout.read(n); p2.kill() if len(buf) == n: a = np.frombuffer(buf, np.uint8).reshape(H, W, 3).astype(int) Image.fromarray(a.astype(np.uint8)).save(f"{OUT}/after-watch.png") print(f"final glyph {glyph(a)} mean {a.mean():.1f}") except Exception as e: print("final grab failed:", e) log.close()