Two results, one of which corrects me. 1. The R1-re-opened 'declared keyframe timeline reproduces the captured splash' resolves in FAVOUR of the declared timeline. Instrument is a disc keyframe table against the guest's vertex stream -- no renderer in the chain, which is what the 'our-reader' tag demanded. Calibration-free test: is each captured alpha an exact member of the declared piecewise-linear value set at integer t? 39/50 exact under truncation, 30/50 under rounding, and the worst error under either rule is ONE alpha level in 255. All 11 non-exact samples are low by exactly 1 and all are on falling segments. The old refutation rested on 'still at a=255 nine frames after its declared a=32' -- under the fixed layout a=32 is at t=206, four units from the end of a 210-unit timeline. That was the off-by-one association. 2. The unit->seconds rate is PER-GAMEPART, which corrects what I told the port an hour ago. Title ~57 units/guest-second; splash ~35-40. The splash figure is confirmed two ways that share no algebra: a 15-unit ramp (T read off the disc, not borrowed) and a 160-unit HOLD, which is a declared duration with no T, no alpha slope and no interpolation in it. And my 'the borrowed T=15 does not apply' was wrong in the other direction: the disc says T=15 plainly. What failed was the premise of a single global rate, not the T. Noted at the foot of that page rather than by editing it. The trap worth recording: all four elements give 650-679 alpha/s, agreeing to 2%, which reads exactly like one clock. It is a coincidence -- T differs 22 vs 15 and the rates differ 57 vs 37, and the ratios nearly cancel. A quantity that looks constant across screens is not evidence of one clock when the thing that would vary is inside it. The hold breaks the tie. For the port: a single keyframe_units_per_second cannot be right, and a splash played at 60 runs 1.5-1.7x too fast -- shorter, sharper fades than the game's, which is the direction the play-test reported.
12 KiB
Units per second — the clock is time-integrated, and the rate is 56.8 units per guest second
Status: ✅ measured. Both pre-registered predictions hold and the control
passes at 1.15 %. ⚠️ Read this page in order. The first half was written while
the capture was still running and reports the rate prediction as FAILED at ~30;
the capture then landed and the second half resolves it. The failure and its
cause are kept because the cause — a borrowed T — is the lesson. Instrument: ⟨capture⟩ with
⟨canary-source⟩ for the clock. 2026-09-01.
Against units-per-second-preregistration.md,
committed before the capture was taken.
What was predicted, and what happened
| # | prediction | outcome |
|---|---|---|
| 1 | the clock is time-integrated, Δα correlates with guest frame duration, r > 0.9 | 🟡 direction held, threshold missed. r = 0.8396 over 19 rising steps spanning a 12.5× duration range (16.4 → 204.6 ms). Positive and structured, but not r > 0.9 |
| 2 | the rate is 60 units per guest second, accept 55–65 | ❌ FAILED. Six elapsed-ratio estimates give a median of 29.9, range 25.2–36.6 |
| 3 | 120 and 30 are both excluded | ❌ FAILED in the worst way — 30 is what came out |
A failed prediction is the result. It is written down before the explanation, because the explanation below is new and untested and the number is not.
✅ The part that IS settled: the clock is not frame-counted
Prediction 1's threshold was missed but its subject is decided, and by a cleaner argument than the regression:
The same animation takes a different number of frames in two captures.
| element | capture A (2026-09-01, first) | capture B (with tick stamps) |
|---|---|---|
splash A's logo Q0 rising steps |
+136, +34 |
+17, +51, +34, +34, +17, +17 |
| splash B's logo trio, labels present | 127…147 (21) |
115…147 (33) |
A fixed per-frame increment cannot do that. The steps are always integer multiples of 17 (= 255/15, one time unit), so the clock advances in whole units, but how many per frame is whatever that frame took.
📌 This retires "2 units per submitted frame" as a description of the
mechanism. The H3 measurement is not wrong —
three consecutive plate steps really were exactly 23 = 2 units — but 2 was a
property of that run's frame pacing, not of the game. Anything the port
computes as units = 2 × frames is computing an emulator artefact.
⚠️ This is my own ✅ row weakened, from ui-keyframe-time-unit.md and from my
own page of two hours ago. Recording it here rather than editing either, and
proposing rather than enacting a change to the register.
❌ Why the rate is not a number yet, and it is a T problem
units per second = (Δα / Δt) × T / 255
Δα/Δt is measured, cleanly, six ways:
| quad | Δα | guest s | α/s | units/s if T = 15 |
|---|---|---|---|---|
| splash A logo | 170 | 0.273 | 622.5 | 36.6 |
| splash B logo ×3 | 187 | 0.368 | 508.7 | 29.9 |
| splash B companion ×2 | 51 | 0.119 | 428.2 | 25.2 |
T is the load-bearing term and I have not read it off the disc myself.
T = 15 comes from ui-keyframe-time-unit.md's ✅ row, and the way I used it
here is circular: that row's shape result (the ramp is linear, round(255·k/15)
fits) is independent, but a step of 34 per frame only implies T = 15 given
2 units/frame — which is exactly the thing this page has just retired.
If T = 30 for these elements the rate is ~60. If T = 15 it is ~30. The
factor between the two answers is the same factor as the unknown, so no amount
of re-measuring alpha settles it.
What settles it, and why the plate is the right element
ptbtn00. Its T = 22 is attested independently of any clock: the four
(time, pose) pairs 214/236/238/244 are read the same way by two different
readers — my own screen info dump on a different branch and the port's
exporter — differing only in the record association, which is ✅ decoded in
ui-keyframe-record-layout.md. Nothing in that
chain uses a clock.
So: capture the plate's ramp with the guest tick stamps, take the elapsed
ratio over it, and rate = (Δα/Δt) × 22 / 255 is the answer with no circularity.
🔴 That capture did not complete this iteration. The run reached 531 s of
attract loop without presenting the title, against 243 s in the previous run —
which is the variable-attract-loop behaviour
capture-harness-status.md already documents at up
to 604 s. The instrument is built and verified; what is missing is one run that
gets there.
The instrument, and its control
The draw logger now stamps every frame boundary with the guest timebase —
Clock::QueryGuestTickCount() at guest_tick_frequency() — so no host wall
clock enters any number above. emulator.cc:225 sets that frequency to
50 MHz and clock.cc:37 leaves guest_time_scalar_ at 1.0
(⟨canary-source⟩).
Control, run before trusting it: the stamps span 123.24 guest seconds across a capture that had been running ~118 wall seconds at the time of reading. Guest time tracks real time, as the source says it should. An instrument that disagreed with its own source here would be dead.
📌 And the guest frame rate is wildly non-uniform — 16.4 ms to 204.6 ms per frame in one splash. That is 12.5×, in a stretch a wall-clock instrument would have averaged into a single meaningless "fps". It is also why prediction 1's regression is honest but noisy: the steps are quantised to 17 and the residual structure is real, with the long frames advancing less than a constant rate predicts.
🟡 That residual is unexplained and is a candidate finding in itself — a
clamped dt, a capped number of logic steps per frame, or a decoupled logic
tick would all produce it. Not tested.
What the port should do with this today
Nothing yet. The 60 units/s constant is neither confirmed nor refuted:
this page's ~30 rests on a T I have not verified, and the argument that
retires 2 × frames does not by itself supply a replacement. Changing it on
the strength of a failed prediction would be worse than leaving it.
Reach
Two captures, the boot splashes in both, one title capture without stamps. The "not frame-counted" conclusion rests on a comparison between captures and is as strong as the two captures being of the same animation, which their element rects and declared ramps make certain. The rate has no reach at all yet.
🔴 RESOLVED LATER THE SAME ITERATION — the title capture landed, and the rate is ~57 units per guest second
Everything above was written while the capture was still running. It then reached
the title after the harness had stopped classifying, so the plate's ramp is in
the log with tick stamps after all. Kept above rather than rewritten, because the
sequence is the point: the failed prediction was caused by exactly the T
circularity the page names, and the fix is the element whose T does not need a
clock.
The measurement
data/units-per-second-rate.txt
ptbtn00 (the plate) α 11 → 231 over 334.4 guest ms 657.9 α/s
ptcopyright α 34 → 231 over 302.9 guest ms 650.4 α/s
The last step of each ramp is excluded: it clamps at 255 and therefore reports more elapsed time than it consumed. Including it drags the plate from 657.9 to 633.0 α/s — a 4 % error entirely inside the clamp.
With ptbtn00's independently attested T = 22:
56.8 units per guest second
✅ Both pre-registered predictions now hold, and the control passes
| # | prediction | outcome |
|---|---|---|
| 1 | time-integrated | ✅ held — and by the between-capture argument above, not the regression |
| 2 | 60 units/s, accept 55–65 | ✅ 56.8 — inside the band |
| 3 | 120 and 30 excluded | ✅ both excluded. 30 would need T = 11.6 for the plate; 120 would need T = 46.5 |
The control I pre-registered — two independent elements, same screen, same run —
passes at 1.15 %. ptcopyright gives 650.4 α/s against the plate's 657.9. At
one shared clock that makes ptcopyright's own segment T = 22.25, i.e. the
same 22-unit ramp; two elements agreeing on a rate and independently landing on
a round declared length is a stronger result than either alone.
Why the earlier ~30 was wrong, and it is the failure the page predicted
units/s = (Δα/Δt) × T / 255. The splash estimate used T = 15, borrowed
from ui-keyframe-time-unit.md. That row is about an element with a declared
15-unit fade; I generalised it to splash B's quads, which is not what it says.
At the measured 56.8 units/s those elements' implied lengths are:
| element | measured α/s | implied T |
|---|---|---|
| splash A logo | 622.5 | 23.3 |
| splash B logos ×3 | 508.7 | 28.5 |
| splash B companions ×2 | 428.2 | 33.8 |
None is 15. The page above said the answer would move by exactly the factor the unknown moved by, and it did — 29.9 × (28.5/15) = 56.8.
⚠️ The step-quantum argument does not rescue T = 15 either. Splash steps are
multiples of 17 and 255/15 = 17, which is what made 15 look confirmed — but at
T = 28.5 a step of 17 is simply two units of 8.9. A quantum fixes T only
if you already know the step is one unit, and nothing said it was.
Resolution and reach
Classified: measured. ⟨capture⟩, guest timebase, control passed.
56.8is not60, and60is not refuted. The span is 19 units at ~11.6 α per unit, so one unit of quantisation is ~5 %; 60 sits 5.6 % away, at the edge of this measurement's resolution. The port keeps 60.- It does eliminate the unit constant as the cause of a late plate. At 56.8
units/s the plate's
t = 236lands at 4.15 s after clock zero against the port's 3.93 s — the port is fractionally early, not late. Whatever the human saw, this is not it. - 🟡 Reach is the title. The splashes are a different
GamePartand this does not establish that they tick at the same rate — it establishes that theirTis unknown, which is a different statement. ReadingToff the disc for the splash elements is the way to close that, and it is static work. - 🟡 The structured residual — long frames advancing less than a constant rate predicts — is untouched and still unexplained.
🔴 CORRECTED the next iteration — the rate is per-GamePart, and this page's T reasoning was backwards
splash-declared-vs-captured.md reads the
splash's declared T off the disc instead of inferring it:
palogo_gameartsrampst=15 → t=30.T = 15, plainly. This page's "the splash elements' impliedTis 23–34, none of them 15" is wrong — it was derived by assuming one global rate, which is the premise that failed, not theT.- Measured on the splash: ~35–40 units/guest-second, against the title's
56.8. Confirmed two ways that share no algebra — a 15-unit ramp and a
160-unit hold, which contains no
Tat all.
So 56.8 is the title's rate, not the game's. Everything on this page about
method stands — the clock is time-integrated, the clamped final step must be
dropped, the guest timebase is the right instrument. The number has a
narrower reach than this page claims.
⚠️ And the near-equality of α/s across all four elements (650–679, ±2 %) is a
coincidence that reads exactly like one clock: T differs 22 vs 15 and the
rates differ 57 vs 37, and the two ratios nearly cancel.