# ✅ The main menu's focus ring spins continuously — period **2.18 s**, measured **Status:** ✅ **measured** (not on the disc as a period; the disc declares the ramp, the running game supplies the rate). Taken 2026-08-29 against Xenia Canary with the disc mounted at `/disc`. **Question this closes:** the port asked whether `ptbtneff01` — the 42×46 ring on the focused button — is *animated* while a button sits focused, or drawn once and held. It had shipped the ring at 0° and marked that known-wrong. [`structures/ui-button-focus-record.md`](structures/ui-button-focus-record.md) already said "the ring SPINS" from **one** frame showing it at a large angle; that is consistent with a continuous spin *and* with a static draw at a fixed angle, so it did not answer the question asked. ## What the ring actually does Five single frames from one run, 4 s apart, focus held on `TUTORIAL` throughout: ![five frames](captures/focus-ring/ring-single-frames-4s-apart.png) The ring carries a bright head, and the head is at a different angular position in every frame. It is still moving 16 s in, so it does **not** ramp once and stop. ⚠️ **The 20 s mean of the same run is a uniform circle** ([`ring-20s-mean-uniform.png`](captures/focus-ring/ring-20s-mean-uniform.png)) — that is the spin smearing itself out, and it is why an averaged frame must never be read as a single frame. A human looking at the live game sees the head; the average does not have one. ## The measurement, and why it is not an angle 🔴 **No angle is estimated anywhere.** The corpus's centroid estimator fails its own control by up to 19.8°, and a 360-bin angular cross-correlation written for this measurement **also failed its control** — a synthetic 30° rotation of a live frame came back as 0° (peak 0.596), while 90/180/270° came back exactly (peak 1.000), i.e. the estimator only resolves the exact pixel permutations. It was therefore not used. What was used needs no angle. Two observables separate *rotation* from a *brightness pulse*, and both were taken in the same run: | observable | rotation predicts | pulse predicts | **measured** | |---|---|---|---| | total annulus brightness | conserved | varies | **0.4 % spread over 16 s** (5 frames); **0.53 %** over 359 frames | | per-angular-bin brightness | varies (a travelling feature) | varies together | **per-bin sd 24.2**, max 80.3, against a per-frame angular sd of 42.2 | Brightness moves *around* the annulus while the total holds. A pulse is excluded. The temporal standard deviation over 103 frames is **an annulus** and nothing else — dark inside, dark outside, peaking exactly on the ring's stroke (radial std: r 0–4 → 1.08, r 10–13 → **36.75**, r 20–26 → 1.18): ![std annulus](captures/focus-ring/ring-temporal-std-annulus.png) ⚠️ A positional *jitter* would smear variation outside the stroke. It does not: variation falls to ~1 both inside and outside, so the ring is not moving, it is turning. ### The period A dense 359-frame filmstrip (24 s at **15.03 fps against a requested 15 fps** — the consumer kept up exactly, so these timestamps are not backlogged) gives the annulus's 360-bin profile per frame, correlated against frame 0. A rotating ring returns to itself once per revolution, so the trace's period **is** the spin period — again with no angle estimated. Autocorrelation local maxima, in seconds: ``` 2.18 4.36 6.52 8.70 10.86 13.02 15.22 17.42 spacings: 2.18 2.16 2.18 2.16 2.16 2.20 2.20 mean 2.177 s ``` **Eight consecutive evenly-spaced peaks over nine revolutions.** A drifting instrument cannot produce even spacing, which is the internal check on the number. Raw trace committed at [`data/focus-ring-period-corr.npy`](data/focus-ring-period-corr.npy) (rows: t, correlation-with-frame-0, annulus mean). ### What the period is in the game's own units ⚠️ **2.18 s is wall-clock under this emulator, and the emulator is not running the game at 30 Hz.** The corpus measures 27.6–28.8 fps here. `ptbtneff01` declares its first keyframe at **t = 120**, and under the settled reading (1 unit = 1/60 s, 2 units per rendered frame) 120 units is **60 rendered frames** — which at 27.6–28.8 fps spans **2.08–2.17 s**. The measurement sits at the top of that band. **So the spin is one revolution per 120 units = 60 frames = 2.00 s at a true 30 Hz**, and no new constant is needed to account for it. 🟡 The 2.18 s is consistent with the declared 120 rather than a re-derivation of it: the guest frame rate was not measured in this same run, so the agreement is consistency, not closure. ## Two other things the same run measured * ✅ **The focus ring is the ONLY moving thing on the settled main menu.** Over 103 frames / 20 s untouched, temporal std is **exactly 0.000** on every unfocused button box, on the `NEW GAME` label, and on the `ptmsg` footer. Only the focused button's box moves (std 4.46 against a background noise floor of 0.906). A port that draws the main menu statically plus a spinning ring is drawing everything that moves. * ✅ **The ring is `ptbtneff01`, positionally confirmed.** Its centre was located from the temporal-std map at game **(520.7, 339.7)**. The declared leaf offset applied to button 3's rest position (542, 322) predicts **(521, 340)**. That is a sub-pixel agreement between a decoded declaration and a live measurement, and it is what ties the annulus to the record rather than to "a circle near the cursor". ## Reach * One run, one emulator, English locale, `GP_TITLE` build 5. * The period is measured on **one** focused button (`OPTIONS`, button 4) and the spin is shown on a second (`TUTORIAL`, button 3). Not checked on all five, and not checked on `EXTRAS`. * Says nothing about the direction of rotation — the estimator that would give a signed angle failed its control and was not used.