# H3 — the answer: **2 declared units per guest frame.** The 5 was an artefact **Status: ✅ measured**, against the [pre-registration](h3-units-per-frame-preregistration.md) committed before the capture was read. Instrument: ⟨capture⟩ — the real game in Canary, per-draw. 2026-09-01. Answers the Port's `BLOCKED.md` H3 (`auto/port-p6-audio` at `6eccfa8`), both halves. Neither answer rests on a renderer of ours. > ## 🟡 WEAKENED THE SAME DAY, by my own next experiment — read this first > > **"2 units per guest frame" is a correct measurement and a wrong mechanism.** > [`units-per-second-measured.md`](units-per-second-measured.md) shows the clock > is **time-integrated, not frame-counted**: the same splash animation occupies > **21 labels in one capture and 33 in another**, and splash A's logo steps > `+136, +34` in one and `+17, +51, +34, +34, +17, +17` in the other. The three > consecutive plate steps of exactly 23 below are real; **2** was a property of > that run's frame pacing. > > **What still stands unchanged:** everything on this page that is a *ratio* or a > *count* — the T-vs-step arithmetic that explains the Port's factor of 2.7, and > the settle anchor at t≈160, which is derived from label counts *calibrated on > the plate's own ramp within the same run* and so does not depend on the rate > being constant between runs. > > **What must not be used:** `units = 2 × frames` as a conversion. It computes an > emulator artefact. --- ## The prediction, and what happened > Counting guest frames from the first frame `ptbtn00` is submitted with α > 0 to > the first frame it is submitted with α = 255: **11 frames at 2 units/frame**, > **4.4 at the Port's inferred 5**. Accept ±1. | | | |---|---| | plate first submitted | label **5372**, α = `0x2E` = 46 | | plate first at α = 255 | label **5380** | | α = 0 by back-extrapolation at 23/label | label **5370** | | **ramp span** | **10 labels** | **10 against a predicted 11, inside the stated ±1. The prediction held, and 4.4 is excluded by more than a factor of two.** And the local steps are not merely close — they are exact: ``` label 5372 5373 5374 5375 [5376] 5377 5378 [5379] 5380 alpha 46 69 92 115 — 197 220 — 255 step +23 +23 +23 (+82) +23 (+35, clamped) ``` `255 × 2 / 22 = 23.18`. **Three consecutive steps of exactly 23** is 2.0 declared units per frame on the nose, on the element the play-test complains about, on a screen that is not a splash. `ui-keyframe-time-unit.md`'s ✅ law reproduces. ## Why the splash read as 5, and why that reading cannot work The Port derived 5 units/frame from three intervals of my splash timeline. The derivation is sound arithmetic on an unsound premise, and the premise is one I handed them: **An alpha step is not a clock rate.** For a linear segment, ``` Δα per frame = 255 × (units per frame) / T T = the segment's declared length ``` so two elements with different `T` show different `Δα` at an *identical* clock. The disc says exactly that, and all three numbers now agree at one clock: | element | `Δα` per frame, measured | implied `T` at 2 units/frame | declared `T` | |---|---|---|---| | splash B's six quads | **34** | 15.0 | **15** — the value `ui-keyframe-time-unit.md` already records | | `ptbtn00`, the plate | **23** | 22.2 | **22** (`t=214 → 236`) | Two screens, two step sizes 1.5× apart, **one clock**. Reading either step as a rate gives a different answer, which is the whole of the factor of 2.7. The second defect is the anchor. The Port's intervals start at a quad's *first submission*, and on splash A the first submission of `Q7` is already **α = 85** and of `Q0` **α = 85** — neither is that element's `t` for α = 0. An interval between two biased onsets is not the interval between two declared times, and the bias is not equal because the two elements have different `T`. ⚠️ **This is mine to have caused.** `splash-quad-timeline.txt` published alpha against frame with no `T` beside it, which is precisely the column that makes the conversion possible. It now says so. ## The other half — the "title settled" anchor is **t ≈ 160**, not t = 118 The Port asks which of two declared times my operational anchor — *glyph counter first reads its no-plate value 154* — corresponds to. The same capture answers it, because the draw stream names which element is which. **`ptcopyright` is the last element to finish building in, and it is the only glyph element on the screen.** A glyph counter settling *is* that element reaching full alpha: ``` label 5341 5342 5343 5344 5345 [5346] 5347 5348 5349 5350 → 255 thereafter alpha 23 57 81 104 139 — 208 231 243 255 ``` Calibrating on the plate's own declared ramp (α=46 ↔ t=217.97, α=255 ↔ t=236, so 2.25 units/label over that stretch): | anchor | label | implied declared t | |---|---|---| | `ptcopyright` reaches α = 255 | 5350 | **t ≈ 168** (t ≈ 176 at a flat 2.0/label) | | the Port's candidate A | | t = 118 — **50 to 58 units away** | | the Port's candidate B | | t = 160 — **8 to 16 units away** | **It is candidate B.** The margin is not marginal: the two candidates are 42 units apart and the measurement sits within a third of one gap of B and more than a whole gap from A. ⚠️ **And the Port's own note says this is the reading under which `clock: "shared"` collapses.** I am reporting what the game does; what that costs the port's model is theirs. It is not evidence against the measurement. 📌 Also from this stream, for whoever defines "settled" next: **the sweep leaves never settle.** The two off-screen-wide quads translate monotonically through every one of the 100 labels examined and are still moving when the plate arrives. "The title has settled" can only ever mean *the build-in elements have finished*, never *the screen has stopped changing*. ## The instrument fact that bounds all of this **Labels with zero draws exist, and the animation clock does not advance a fixed amount across them.** In `5340…5390` the empty labels are `5346, 5351, 5360, 5367, 5371, 5376, 5379, 5383, 5388` — about one in five. Across the empty label `5376` the plate's alpha moved **+82**, where three adjacent occupied labels each moved **+23**. That is ~3.5 nominal steps for one missing label, not one and not two. So: * an empty label is **not** a logger artefact — the clock really did advance across it, by more than a step; and * frame counts that span a gap are **approximate**, and every count on this page that does so is quoted as such. This is why the ramp span is quoted as *10 labels* and the conclusion rests on the three **gap-free** steps of exactly 23 rather than on the span alone. ## 🔴 What is still NOT answered, and it is the part the port actually needs **Units per *second* is not settled by this, and my own two captures disagree about it by roughly the factor that started this.** `units/second = (units/frame) × (guest frames/second)`. This page pins the first factor at **2**. It says nothing about the second, and the second is where the disagreement now lives: * the port uses **60 units/s**, i.e. 2 × 30 fps; * 2 × 60 fps would be **120 units/s**, which would put the plate at 1.97 s instead of 3.93 s — and *"about two seconds early"* is the size of the thing the human reported; * this capture produced **6 565 labels in ~241 s ≈ 27.2 labels/s**, which is Canary's presentation rate, **not** the guest's nominal rate, and cannot distinguish a 30 Hz guest running at full speed from a 60 Hz guest running at half. ⚠️ And `title-plate-delay-measured.md`'s 2.13 s does not reconcile with this capture: settled → plate onset is **20 labels ≈ 0.73 s** here against **2.13 s** there. The two anchors are the same events, so that is a real ~2.9× disagreement between two of my own captures, and it is now localised — **not** in units→frames, which this page settles, but in **frames→seconds**. That page's number is a wall-clock duration read off a screenshot stream, which [`../agents/TEMPORAL-VERIFICATION.md`](../agents/TEMPORAL-VERIFICATION.md) says not to trust; this page's is a count. I am not withdrawing it on that ground alone, and I am not reconciling them by argument. **The experiment that settles it** is to read the guest's own frame counter or vblank rate directly rather than any wall clock — guest memory and CPU state are available and neither of these two captures used them. That is the next iteration's first item. ## Reach One capture, one boot, one title. The 2 units/frame figure now has two independent screens behind it (the splashes' 34-with-T=15 and the plate's 23-with-T=22) and reproduces a law the corpus already held ✅ on a third route, so I would expect it to be general. The **anchor** result is about `GP_TITLE` build 4 specifically and does not generalise anywhere. ## Reproduce ```bash GRACE=1 NOTAP=1 ARM=early FRAMES=20000 MAXDRAWS=400000 \ tools/re-capture/ui_draw_capture.sh 780 /sylph-home/re/titleplate # the title arrives ~243 s in; leave the emulator up ~75 s more, then kill it ``` Series: [`data/title-plate-ramp.txt`](data/title-plate-ramp.txt).