port: the plate's lateness is the unit, not our clock -- and the splash blur is an asset we already draw
H3, the PRESS (A) plate. Established which half it is, as the brief asked, and
the answer moved once during the iteration -- both readings are recorded because
the first one was confident and wrong.
Eliminated, ours:
rest.t not in the causal path. The plate's ARRIVAL is a declared keyframe
(transparent to t=214, opaque at t=236); rest.t=236 only picks
where `holding` parks it, and 236 is that ramp's own peak.
clock origin the two builds share one clock exactly -- 85 of 85 filmed title
frames have view_units == overlay_units to 3 dp.
NOT eliminated, the Decoder's: the unit->seconds constant. I first ruled it out
"by sign" using the emulator's 28.1 fps presentation rate. That conflates a
wall-clock conversion with units-per-game-frame; the correction is written down
rather than edited away. The Decoder's splash draw capture (3cc1b51) then gave
an independent handle on it, from a screen with nothing to do with the plate:
three intervals of the publisher splash all read 5 units per guest frame against
the declared 2. At 30 fps the plate would land at 1.57 s rather than 3.93 s --
this port ~2.4 s late, the right magnitude for what the human saw. It collides
with title-plate-delay-measured.md (~55 units/s) by a factor of 2.7. Both are
oracle measurements; asked in BLOCKED.md H3, not picked between.
Finding 4, the splash blur. The Decoder found no post-process pass; the human
says the logos go blurred -> sharp in about a second. Those resolve each other:
every logo ships a pre-blurred copy ~21x20 px larger and concentric, drawn alone
first and crossfaded out as the sharp logo fades in.
🔴 So "the port applies no blur at all" -- in BLOCKED.md H2 and in the
play-test -- is FALSE, and it came from our side. The port draws all seven
quads of the developer splash, companions included, and always has. Shown by a
frozen sweep 3 units a step: companions alone at u=3..15, all seven at
u=18..42, sharp only from u=45.
The instrument had to be fixed before any of this counted. `--film` scheduled
frame n for n*interval and reported nothing; one 1280x720 save_png costs ~0.24 s
under llvmpipe, so a request for 0.05 s delivered 247 frames in 60 s where 1200
were asked for -- an achieved 4.1 fps against a requested 20 -- and the deficit
accumulated silently into the frame index. It now writes <film>_frames.tsv with
the second each frame was ACTUALLY taken at, and prints achieved against
requested. The schedule is deliberately not rebased onto _elapsed: catching up
would hide the shortfall.
check-all now reimports the Godot project first. `port/.godot/` is gitignored, so
merging a commit that adds a `class_name` leaves a stale class cache and the
whole project fails to parse -- which is exactly what merging the human's
gamepad.gd did in this container.
Refutation attempts, four:
survived the title's settle window [160, 236] -- our exporter still computes
[160, 236, 198] under the corrected record layout
survived the Decoder's Q0/Q7 quad mapping -- this export's declared rects
reproduce the guest's vertex stream to ~2 px and ~4 px
refuted "ptlogo1 rests at t=251 and stops moving at t=42" -- rest.t is now
42. The record-layout fix repaired the very element that was the
headline evidence for rest.t != settle. The conclusion survives on
other elements; the example does not
refuted ours: "ptbtn00 reaches a=255 at t=238" (it is 236, so 118 units not
120) and "pteff00 is 7 % opaque at 243" (it is 0 %; that quad clears
by t=16 and 261..269 is the fade-OUT, not a fade-in)
Not settled: which of the two oracle rates is right; whether the t=118 or the
t=160 anchor is what the glyph counter saw; whether the game holds the blurred
companion longer than we do.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
This commit is contained in:
@@ -83,10 +83,20 @@ var audio: MenuAudio = null
|
||||
## 2 -- arrives later.
|
||||
##
|
||||
## **They share one clock, started together, and there is no authored delay.**
|
||||
## The plate arrives at its own declared `t = 238`; build 4's visible build-in
|
||||
## ends at `t = 118`; the 120-unit difference is 2.000 s, against an oracle that
|
||||
## measured 2.138 s and 2.132 s at an emulator presenting 28.1 fps rather than
|
||||
## 30. A port running at a true 30 Hz wants the declared 120, not the wall clock.
|
||||
## The plate reaches full alpha at its own declared `t = 236`; build 4's effect
|
||||
## quads end their ramps together at `t = 118`; the 118-unit difference is
|
||||
## 1.967 s, against an oracle that measured 2.138 s and 2.132 s at an emulator
|
||||
## presenting 28.1 fps rather than 30.
|
||||
##
|
||||
## 🔴 THIS SAID `t = 238` AND `120 units = 2.000 s`, AND BOTH ARE OFF BY TWO.
|
||||
## `ptbtn00`'s declared alpha reaches `0xff` at **t = 236** and *holds* it to
|
||||
## t = 238, then ramps back to 0 by t = 244 -- so 238 is the last opaque frame,
|
||||
## not the arrival. `236 - 118 = 118`. The port has been printing the
|
||||
## contradiction in one sentence on every boot: *"plate reaches full alpha at
|
||||
## t=236 ... 120 units after build 4's last build-in ramp at t=118"*. The
|
||||
## correction moves the reconciliation by 0.033 s and changes no conclusion,
|
||||
## which is why it survived; a cited number that is wrong is still wrong.
|
||||
## See `docs/port/plate-arrival-halves.md`.
|
||||
##
|
||||
## A second ScreenView rather than a second screen inside one, because that is
|
||||
## what "two builds at once" actually is: each has its own timeline, its own
|
||||
@@ -1053,14 +1063,59 @@ func _capture(path: String) -> void:
|
||||
|
||||
## A frame every 0.25 s for the whole run, so an unattended boot leaves a
|
||||
## filmstrip behind rather than requiring someone to be watching it.
|
||||
##
|
||||
## 🔴 A FRAME INDEX IS NOT A CLOCK, AND THIS TOOL WAS BEING READ AS ONE.
|
||||
##
|
||||
## `_film_next += _film_interval` schedules frame `n` for `n * interval`. When a
|
||||
## frame costs more than the interval -- and it does; one 1280x720 `save_png`
|
||||
## under llvmpipe measured ~0.24 s, so any `--film-interval` under a quarter of
|
||||
## a second is unreachable -- the deficit accumulates silently and every later
|
||||
## frame is taken late by a growing amount. Asking for 0.05 s over 60 s
|
||||
## requested 1 200 frames and produced **247**, an achieved 4.1 fps against a
|
||||
## requested 20. Nothing in the output said so, and `f_071.png` still looks
|
||||
## exactly like the frame that was meant to be 3.55 s in.
|
||||
##
|
||||
## `TEMPORAL-VERIFICATION.md` §1 is explicit that a capture that asked for one
|
||||
## rate and delivered another "is not a slow capture, it is a **different**
|
||||
## capture", and that an instrument which cannot report its own completeness may
|
||||
## not be trusted (R3). So the film now carries its own timebase: one TSV row per
|
||||
## frame with the elapsed second it was ACTUALLY taken at and both builds' clocks
|
||||
## at that moment, appended as it goes so a run killed by `timeout` still leaves
|
||||
## a complete index.
|
||||
##
|
||||
## The schedule is deliberately NOT rebased onto `_elapsed`. Catching up would
|
||||
## hide the shortfall, which is the defect; falling behind and saying so is the
|
||||
## fix. The achieved rate is printed every 40 frames and the row is the record.
|
||||
func _film_capture() -> void:
|
||||
var index_path := "%s_frames.tsv" % _film
|
||||
var index := FileAccess.open(index_path, FileAccess.WRITE)
|
||||
if index == null:
|
||||
push_error("cannot write %s (%d)" % [index_path, FileAccess.get_open_error()])
|
||||
return
|
||||
index.store_line("frame\telapsed_s\trequested_s\tlag_s\tscreen\tview_units\toverlay_units")
|
||||
print("film: %s, requested one frame every %.3f s; index -> %s"
|
||||
% [_film, _film_interval, index_path])
|
||||
while true:
|
||||
await RenderingServer.frame_post_draw
|
||||
if _elapsed >= _film_next:
|
||||
var at := _elapsed
|
||||
var img := viewport.get_texture().get_image()
|
||||
img.save_png("%s_%03d.png" % [_film, _film_frame])
|
||||
# The overlay's clock, or -1 where there is no second build. A blank
|
||||
# would read as zero, and zero is a real instant on that timeline.
|
||||
var over := -1.0
|
||||
if overlay != null:
|
||||
over = overlay.time_units
|
||||
index.store_line("%d\t%.4f\t%.4f\t%.4f\t%s\t%.3f\t%.3f" % [
|
||||
_film_frame, at, _film_next, at - _film_next,
|
||||
String(view.screen.get("name", "?")) if view != null else "?",
|
||||
view.time_units if view != null else -1.0, over])
|
||||
index.flush()
|
||||
_film_frame += 1
|
||||
_film_next += _film_interval
|
||||
if _film_frame % 40 == 0 and at > 0.0:
|
||||
print("film: %d frames in %.2f s -- achieved %.2f fps against a requested %.2f"
|
||||
% [_film_frame, at, _film_frame / at, 1.0 / _film_interval])
|
||||
|
||||
|
||||
# Godot passes everything after `--` through untouched; take `--key=value`.
|
||||
@@ -1447,16 +1502,27 @@ func _raise_overlay(name: String) -> void:
|
||||
# no log line.
|
||||
if _sequence.is_empty():
|
||||
return
|
||||
# %d - 118, computed rather than spelled: the literal "120" here disagreed
|
||||
# with the "t=236" printed beside it in the same sentence, for weeks.
|
||||
print(" plate reaches full alpha at t=%d (%.2f s on the shared clock), \
|
||||
120 units after build 4's last build-in ramp at t=118"
|
||||
% [int(overlay.settle_time()), visible_at])
|
||||
%d units after build 4's effect quads end together at t=118"
|
||||
% [int(overlay.settle_time()), visible_at, int(overlay.settle_time()) - 118])
|
||||
if not _play and _film == "":
|
||||
# The LATER of the two, not the overlay's alone. The plate arrives at
|
||||
# t=238 and build 4 is still fading up from black until t=261 -- its
|
||||
# `pteff00` quad is 7 % opaque at 243 -- so quitting when the plate
|
||||
# lands photographs a title that has not finished presenting. The first
|
||||
# capture taken this way was visibly darker than the one before it, and
|
||||
# nothing in the log said why.
|
||||
# The LATER of the two, not the overlay's alone.
|
||||
#
|
||||
# 🔴 THE REASON GIVEN HERE WAS BACKWARDS AND IS REPLACED. It said build 4
|
||||
# "is still fading up from black until t=261 -- its `pteff00` quad is
|
||||
# 7 % opaque at 243". `pteff00` is the screen's black veil and it does
|
||||
# BOTH fades: opaque at t=0, clear by **t=16**, transparent all the way
|
||||
# to t=261, then back to opaque by t=269. At t=243 it is 0 % opaque, not
|
||||
# 7 %, and 261..269 is the fade-OUT. So build 4 finishes arriving 16
|
||||
# units in, not 261.
|
||||
#
|
||||
# The line still stands, for the reason underneath it rather than the
|
||||
# one that was written: build 4's own last hold is t=160 (`ptcopyright`
|
||||
# reaching full alpha) and the plate's is t=236, so ending on the
|
||||
# overlay alone would still be ending on the earlier of two clocks. The
|
||||
# darker capture that prompted this was real; the explanation was not.
|
||||
var ends_at := maxf(view.settle_time(), overlay.settle_time()) / view.units_per_second
|
||||
_overlay_quit_at = _elapsed - (view.time_units / view.units_per_second) + ends_at
|
||||
print(" boot ends at %.2f s, once both builds have arrived (t=%d)"
|
||||
|
||||
Reference in New Issue
Block a user