The exporter transcodes ADV.wmv and S00A.wmv to Ogg Theora and records the exact
ffmpeg command in the manifest, per MISSION §6, so a modder who dislikes the
quality re-runs one line rather than reverse-engineering what was done.
Quality was MEASURED, not judged: SSIM against the decoded source over a 10 s
sample is 0.9863 / 0.9896 / 0.9924 at -q:v 6 / 8 / 10, and at 200 % zoom on the
reel's hardest case -- fine serif text and soft gradients over near-black, where
Theora breaks first -- q8 is indistinguishable. So MISSION §6's permitted
FFmpeg-GDExtension fallback is NOT needed and is NOT being proposed. No new
runtime dependency.
-ac 2 because the source is 6-channel WMA Pro; that downmix is a decision, so it
lives in the recorded command rather than in prose.
Encoding is cached on a .cmd sidecar holding the command and the source size --
any change to either re-encodes. export/ is still regenerated wholesale; this is
derived state validating derived state, not a hand-edit, and without it every
re-export pays ~4 minutes to produce a byte-identical file.
The player renders INTO the design SubViewport. Parenting it to the Boot node
played the movie to the window instead, and every captured frame came out black
-- which is worth more than a capture-bug note: a movie outside the 1280x720
design space is outside the coordinate system every screen is expressed in.
(A) skips a movie, because Q9 measured that (title at 57 s vs a 193 s baseline).
NOT VERIFIED, and stated as such: audible playback. This container has no audio
device and Godot falls back to the dummy driver. The Vorbis stream exists, is
2-channel and decodes; whether Godot emits it is unconfirmed.
P3. The exit is the group playing ITSELF out, not a black rect over a frozen
screen -- and that was settled by a test that discriminates rather than by
plausibility. Under the black-rect model every region is scaled by the same
1-alpha, so the button/background brightness RATIO would hold constant through
the fade; measured, it falls 6.495 -> 5.574 -> 3.105 -> 2.125 -> 1.935.
Implemented by giving the final untimed keyframe a SYNTHETIC time,
exit_ramp_units after the last timed one, then interpolating it like any other
frame. One code path: arriving and leaving differ only in how far `t` is allowed
to run, not in kind. `holding` is what the sequencer clears to send a screen away.
The sequencer waits on nothing the disc does not carry. A screen holds until its
own group has arrived, then plays out; `dwell` in flow.json is deliberately empty
because each screen's dwell IS its keyframe group (publisher wordmark 3.92 s,
developer logos 3.17 s, both read from the disc). Any extra hold would be a
number nobody measured.
The last screen keeps holding -- nothing is taking the title's place, and a boot
that ends by fading to black looks like a boot that crashed.
flow.json reproduces an OBSERVATION and says so in its header: Q6 closed with a
negative, the order is on the disc nowhere, a transition is a call with a name
argument chosen by code. The intro video's place in the real boot is named as a
gap rather than the order being quietly rewritten to hide it.
P2. A keyframe is the start of a linear ramp toward the next; `ScreenView` walks
them at `time_units` and `boot.gd` advances that in real time, or freezes it with
`--time=<seconds>`.
`authored/timing.json` holds the ONE constant this needs. HANDOFF Q1 is answered
-- linear, 2 units per rendered frame, 1 unit = 1/60 s -- but that conversion was
MEASURED off the running game, not read from a file, so it is authored rather
than exported and it says so at length. Expressed as units-per-second, because
60 is exact and 0.01666... is a decimal a reader has to recognise.
The timeline stops at the last TIMED keyframe and never plays the exit. Every
group's final keyframe carries no `t` -- across this export it is a fade-out for
116 of 134 elements, a scale-and-slide exit for 12, and identical for 6 -- so
playing into it would mean inventing how long the ramp takes. That duration is
the screen transition, it is measured at ~0.4 s, and it is P3's to author with
its own evidence. `exit_ramp_seconds` is therefore null on purpose, not missing.
`--pose=rest` keeps the P1 behaviour available: since the port's default is now
the timeline and the two DISAGREE, renderer-vs-renderer diffing has to be able to
ask for the same assumption the reference renderer makes.
The interpolation is checked by where it lands: on 8 of the 12 screens the
settled timeline is byte-identical to the rest render.
P1. The project reads only `export/` -- the manifest, a screen's JSON and its
PNGs -- and draws every element at `rest`, in the export's own `paint_order`.
Three choices worth the words:
* `ExportTree` addresses screens by manifest NAME, never by path, and checks
`format` on the manifest and on each screen before drawing. Textures are
decoded from bytes at runtime rather than Godot-imported: `export/` is
gitignored and regenerated wholesale, and a `.import` per sprite would be
derived state next to derived state, invalidated on every re-export.
* One CanvasItem draws the whole screen. `paint_order` is already back-to-front,
so honouring it is a loop; spreading it across sixteen nodes' z-indices would
hide the one unresolved thing about that order -- the ties -- behind Godot's
sibling rules.
* The screen renders into a SubViewport sized to the export's `design` rect.
Capturing the window instead gave 1280x720 of screen minus a window manager's
title bar: 1235x695. A gate that rescales that to compare against a 1280x720
composite is measuring the compositor.
Nearest-neighbour filtering, because the export is a 1:1 copy of the disc's
texels, elements draw at up to 500 %, and it is what `ui_layout::blit` does --
so a filter difference cannot masquerade as a placement difference in the diff.
No keyframe interpolation and no focus state: both depend on constants that are
MEASURED rather than decoded (HANDOFF Q1, Q5), and a pixel-diff gate must not
have one of those inside it. P2 and P5.