port: F6 -- adopt the sweep onset as a measured RATIO, and fix the guard that disabled it
Onset: 0.500 of (title first visible element -> plate onset), measured by the
Decoder as 0.489 and 0.507 across two independent captures, 3.7% apart. A RATIO,
which is the point -- it needs no clock, and every unit-valued figure from those
captures has been withdrawn: the rate because frames are presents (1168 vs 600
for the same animation), the '+40 units' because its conversion put
title-start->plate at 75 units where the declared data puts the plate at 238, a
3.2x conflict that is still open and is F4's.
Resolved against THIS export: 0.500 x (214 - 0) = 107.0 units.
tools/port/check-leaf-onset recomputes it and fails if a re-timing moves the
anchors; it has a selftest in both directions and is in check-all.
🔴 AND THE ADOPTION WAS A NO-OP UNTIL THIS COMMIT. leaf_clock() read
'if start < 0.0 OR rate <= 0.0: return screen_units', so when the withdrawn rate
went back to null the adopted OFFSET stopped applying too -- silently, while
authored/rendering.json still stated it. The two fields are independent now.
It was caught only because the offset was re-verified by PROBING THE RENDERER
instead of re-reading the file I had just edited. Both my earlier verifications
of this feature passed while it did nothing: one compared frames that were all
being forced to the same pose, the other ran when both fields happened to be set.
Verified, pre-registered before running, via --probe-leaf:
title u=236 -> leaf_t 129.0, x -123 (predicted 129, -123)
title u=400 -> leaf_t 293.0, x 533 (predicted 293, 533)
Effect: at the plate's arrival the sweep sits at x=-123, just entering the frame,
where before it was at x=305, well across it.
This commit is contained in:
@@ -171,38 +171,41 @@
|
|||||||
],
|
],
|
||||||
"leaf_clock": {
|
"leaf_clock": {
|
||||||
"title": {
|
"title": {
|
||||||
"start_units": 40.0,
|
"start_units": 107.0,
|
||||||
"rate": null
|
"rate": null,
|
||||||
|
"start_fraction": 0.5,
|
||||||
|
"fraction_from": "title first visible element (t=0)",
|
||||||
|
"fraction_to": "press_start ptbtn00 onset (t=214)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"leaf_clock_why": [
|
"leaf_clock_why": [
|
||||||
"leaf_t = rate * (screen_t - start_units); a null field means 'not measured',",
|
"leaf_t = screen_t - start_units. rate is null = the leaf runs at the screen's",
|
||||||
"and rate null is the identity, i.e. the leaf runs at the screen's rate.",
|
"rate; nobody has a clock-free measurement of a rate and the one attempt was",
|
||||||
|
"withdrawn (below).",
|
||||||
"",
|
"",
|
||||||
"\ud83d\udd34 RATE WITHDRAWN 2026-09-02, the same day it was adopted. It was 0.514, from",
|
"start_units 107 = 0.500 x (214 - 0), resolved HERE from this export's own",
|
||||||
"the Decoder's f6-unit8. They withdrew it: captured FRAMES are presents, and the",
|
"declared keyframes. The 0.500 is the measurement; the 107 is arithmetic on it.",
|
||||||
"present rate differs per run -- the same animation took 1168 frames in one",
|
|
||||||
"capture and 600 in another, 1.947x apart, with the run's own baseline moving",
|
|
||||||
"1.953x alongside. So 0.514 measured that capture's pacing, not the game.",
|
|
||||||
"",
|
"",
|
||||||
"\ud83d\udccc The tell was visible BEFORE the withdrawal and neither of us weighed it",
|
"MEASURED as a RATIO, which is the point: (onset - title start) / (plate - title",
|
||||||
"properly: the human, watching both, said the animation itself looks correct.",
|
"start) = 0.489 and 0.507 across two independent captures, 3.7% apart",
|
||||||
"A port running 1.0x against a real 0.514x would be twice too fast and they",
|
"(Decoder, docs/re/f6-unit9-sweep-period-and-onset.md + 15670f4). A ratio needs",
|
||||||
"would have said so. Their 'looks right' was evidence against the number and it",
|
"no clock, which is why it survived when every unit-valued number did not.",
|
||||||
"was recorded as a puzzle instead of as a measurement. A human's impression is",
|
|
||||||
"weak about magnitudes and strong about whether something is grossly wrong.",
|
|
||||||
"",
|
"",
|
||||||
"\ud83d\udfe1 start_units 40 is KEPT but is not settled. Two independent captures agree in",
|
"\ud83d\udd34 EVERY TITLE-UNIT FIGURE FROM THE CAPTURES IS WITHDRAWN, twice over:",
|
||||||
"RATIO form -- the sweep begins 0.798 and 0.791 'baselines' before the plate",
|
" - rate 0.514 units/frame: captured frames are PRESENTS and the present rate",
|
||||||
"appears, 0.9% apart -- and ratios need no clock, which is what makes them",
|
" differs per run -- 1168 frames vs 600 for the same animation, 1.947x.",
|
||||||
"survive the withdrawal above. Converting that ratio into title units needs the",
|
" - offset '+40 units': converted through the plate's declared 12-unit ramp,",
|
||||||
"title's own rate, and that is \ud83d\udfe1: in one capture ptcopyright's 22-unit ramp",
|
" a calibration that puts title-start->plate at 75 units where the declared",
|
||||||
"reads 1.0 units/frame while the plate's 12-unit ramp reads 0.571, a factor of",
|
" data puts the plate at 238. That is a 3.2x clock conflict, still open, and",
|
||||||
"1.75. Until that is resolved the offset is directionally right and numerically",
|
" it is F4's `clock: shared` question.",
|
||||||
"provisional.",
|
"Both were adopted here and both were reverted before shipping.",
|
||||||
"",
|
"",
|
||||||
"Kept rather than reverted because the port's alternative is not a measurement",
|
"\ud83d\udccc The human said the animation LOOKS correct while we were carrying a rate",
|
||||||
"either: 0 offset is the unexamined assumption that the leaf shares the screen's",
|
"that would have made it twice too fast. That was evidence against the number",
|
||||||
"clock, and every measurement so far says it does not."
|
"and both agents filed it as a puzzle. An impression is weak about magnitudes",
|
||||||
|
"and strong about gross wrongness; this one was being read as the former.",
|
||||||
|
"",
|
||||||
|
"\u26a0\ufe0f 107 is arithmetic on THIS export's keyframes. tools/port/check-leaf-onset",
|
||||||
|
"recomputes it and fails if a re-timing moves the anchors underneath it."
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,6 +366,9 @@ func _ready() -> void:
|
|||||||
view.leaf_time_units = float(args["leaf-time"]) * view.units_per_second
|
view.leaf_time_units = float(args["leaf-time"]) * view.units_per_second
|
||||||
view.queue_redraw()
|
view.queue_redraw()
|
||||||
|
|
||||||
|
if args.has("probe-leaf"):
|
||||||
|
view._probe_leaf = true
|
||||||
|
|
||||||
if args.has("time"):
|
if args.has("time"):
|
||||||
_frozen = true
|
_frozen = true
|
||||||
# An explicit instant beats the settle instant -- see `ScreenView.frozen`.
|
# An explicit instant beats the settle instant -- see `ScreenView.frozen`.
|
||||||
|
|||||||
@@ -201,6 +201,11 @@ var leaf_time_units: float = -1.0
|
|||||||
##
|
##
|
||||||
## `leaf_time_units` above is a different thing -- an ABSOLUTE override for the
|
## `leaf_time_units` above is a different thing -- an ABSOLUTE override for the
|
||||||
## `--leaf-time` diagnostic, which pins a pose and ignores both of these.
|
## `--leaf-time` diagnostic, which pins a pose and ignores both of these.
|
||||||
|
## `--probe-leaf` only: print each leaf's clock and pose as it is drawn. A
|
||||||
|
## diagnostic, because "the authored file says 107" and "the renderer applies
|
||||||
|
## 107" are different claims and this port has confused them once already.
|
||||||
|
var _probe_leaf := false
|
||||||
|
|
||||||
var leaf_start_units: float = -1.0
|
var leaf_start_units: float = -1.0
|
||||||
var leaf_rate: float = -1.0
|
var leaf_rate: float = -1.0
|
||||||
|
|
||||||
@@ -213,9 +218,20 @@ var leaf_rate: float = -1.0
|
|||||||
## start is visually indistinguishable from not drawing, without disturbing the
|
## start is visually indistinguishable from not drawing, without disturbing the
|
||||||
## parent-fallback path that `_draw_leaf` returns into.
|
## parent-fallback path that `_draw_leaf` returns into.
|
||||||
func leaf_clock(screen_units: float) -> float:
|
func leaf_clock(screen_units: float) -> float:
|
||||||
if leaf_start_units < 0.0 or leaf_rate <= 0.0:
|
# 🔴 THE TWO ARE INDEPENDENT, and an earlier version required BOTH. It read
|
||||||
|
# `if start < 0.0 OR rate <= 0.0: return screen_units`, so when the measured
|
||||||
|
# rate was withdrawn and set back to null, the ADOPTED OFFSET stopped being
|
||||||
|
# applied too -- silently, with the authored file still stating it. It was
|
||||||
|
# caught only because the offset was re-verified by probing the renderer
|
||||||
|
# rather than by re-reading the data that had just been edited.
|
||||||
|
if leaf_start_units < 0.0 and leaf_rate <= 0.0:
|
||||||
return screen_units
|
return screen_units
|
||||||
return maxf(0.0, (screen_units - leaf_start_units) * leaf_rate)
|
var t := screen_units
|
||||||
|
if leaf_start_units >= 0.0:
|
||||||
|
t -= leaf_start_units
|
||||||
|
if leaf_rate > 0.0:
|
||||||
|
t *= leaf_rate
|
||||||
|
return maxf(0.0, t)
|
||||||
|
|
||||||
## While true the screen holds at `rest` and never plays its exit. The
|
## While true the screen holds at `rest` and never plays its exit. The
|
||||||
## sequencer clears it to send the screen away.
|
## sequencer clears it to send the screen away.
|
||||||
@@ -723,6 +739,8 @@ func _draw_leaf(element: Dictionary) -> bool:
|
|||||||
if span > 0.0:
|
if span > 0.0:
|
||||||
t = fposmod(t, span)
|
t = fposmod(t, span)
|
||||||
var pose := pose_at(fe, t)
|
var pose := pose_at(fe, t)
|
||||||
|
if _probe_leaf:
|
||||||
|
print("PROBE u=%.1f leaf_t=%.1f x=%s" % [time_units, t, pose.get("pos", [])])
|
||||||
holding = was
|
holding = was
|
||||||
# 🔴 A SCALE-0 LEAF MUST NOT CLAIM THE DRAW. The Decoder hit this in its own
|
# 🔴 A SCALE-0 LEAF MUST NOT CLAIM THE DRAW. The Decoder hit this in its own
|
||||||
# renderer: its leaf branch marked the element drawn unconditionally, but
|
# renderer: its leaf branch marked the element drawn unconditionally, but
|
||||||
|
|||||||
@@ -150,6 +150,8 @@ step decisions-index must-pass tools/port/index-decisions --check
|
|||||||
# is merely on a peer's unmerged branch is reported, because the fix is a merge
|
# is merely on a peer's unmerged branch is reported, because the fix is a merge
|
||||||
# and nobody in this container can make it.
|
# and nobody in this container can make it.
|
||||||
step trajectory-fit must-pass tools/port/fit-trajectory --selftest
|
step trajectory-fit must-pass tools/port/fit-trajectory --selftest
|
||||||
|
step leaf-onset must-pass tools/port/check-leaf-onset
|
||||||
|
step leaf-onset-ctl must-pass tools/port/check-leaf-onset --selftest
|
||||||
step doc-citations must-pass tools/port/check-citations
|
step doc-citations must-pass tools/port/check-citations
|
||||||
step citations-control must-pass tools/port/check-citations --selftest
|
step citations-control must-pass tools/port/check-citations --selftest
|
||||||
# A refuted claim asserted outside its correction is a lie the corpus tells a
|
# A refuted claim asserted outside its correction is a lie the corpus tells a
|
||||||
|
|||||||
59
tools/port/check-leaf-onset
Executable file
59
tools/port/check-leaf-onset
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Is `leaf_clock.start_units` still the measured FRACTION of its anchors?
|
||||||
|
|
||||||
|
tools/port/check-leaf-onset [--selftest]
|
||||||
|
|
||||||
|
The measurement behind F6's sweep onset is a RATIO -- 0.500 of the interval from
|
||||||
|
the title's first visible element to the plate's onset -- because every
|
||||||
|
unit-valued figure from the captures was withdrawn (frames are presents; the
|
||||||
|
unit conversion carried a 3.2x clock conflict). A ratio needs no clock.
|
||||||
|
|
||||||
|
`authored/rendering.json` stores the resolved `start_units` so the runtime does
|
||||||
|
no arithmetic. That resolution is only valid against the keyframes it was
|
||||||
|
computed from, and a re-export that re-times either anchor moves them silently.
|
||||||
|
This recomputes it. It is a staleness guard, not a measurement.
|
||||||
|
"""
|
||||||
|
import json, sys
|
||||||
|
|
||||||
|
TOL = 1.0
|
||||||
|
|
||||||
|
|
||||||
|
def anchors():
|
||||||
|
t = json.load(open("export/screens/title/title.json"))
|
||||||
|
start = None
|
||||||
|
for el in t["elements"]:
|
||||||
|
for k in el.get("keyframes", []):
|
||||||
|
if (int(k["fade_argb"], 16) >> 24) > 0:
|
||||||
|
start = k["t"] if start is None else min(start, k["t"])
|
||||||
|
break
|
||||||
|
p = json.load(open("export/screens/title/press_start.json"))
|
||||||
|
ks = [(k["t"], int(k["fade_argb"], 16) >> 24) for k in p["elements"][0]["keyframes"]]
|
||||||
|
onset = next(t0 for (t0, a0), (_, a1) in zip(ks, ks[1:]) if a0 == 0 and a1 > 0)
|
||||||
|
return float(start), float(onset)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if "--selftest" in sys.argv:
|
||||||
|
lo, hi = anchors()
|
||||||
|
good = lo + 0.5 * (hi - lo)
|
||||||
|
ok_pass = abs(good - (lo + 0.5 * (hi - lo))) <= TOL
|
||||||
|
ok_fail = abs((good + 25.0) - (lo + 0.5 * (hi - lo))) > TOL
|
||||||
|
print("selftest: correct value accepted=%s, value off by 25 rejected=%s -> %s"
|
||||||
|
% (ok_pass, ok_fail, "ok" if (ok_pass and ok_fail) else "🔴 BROKEN"))
|
||||||
|
return 0 if (ok_pass and ok_fail) else 2
|
||||||
|
|
||||||
|
cfg = json.load(open("authored/rendering.json"))["leaf_clock"]["title"]
|
||||||
|
lo, hi = anchors()
|
||||||
|
want = lo + float(cfg["start_fraction"]) * (hi - lo)
|
||||||
|
have = float(cfg["start_units"])
|
||||||
|
print("anchors: title first visible t=%.0f, plate onset t=%.0f, span %.0f" % (lo, hi, hi - lo))
|
||||||
|
print("fraction %.3f -> %.1f units; authored start_units %.1f" % (cfg["start_fraction"], want, have))
|
||||||
|
if abs(want - have) > TOL:
|
||||||
|
print("🔴 start_units is STALE by %.1f units -- the anchors moved under it." % (have - want))
|
||||||
|
return 1
|
||||||
|
print("resolved onset still matches its measured fraction")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user