re: RETRACT "the game never draws eff3" -- a batched draw merged two quads
The console draws all five title flashes. My claim that ptlogo_back2eff3 is never drawn was an instrument artefact, and I had reported it to the port with three alternative explanations "ruled out". A GPU draw can batch several quads -- indices=4 is one, indices=8 two, indices=24 six -- and the UI draw log dumps only the first 8 vertices. Taking min/max over a line's whole vertex list merges quads into one box. eff3 is batched with eff4, and because the wipe family is right-aligned, eff3 (788..1196) lies ENTIRELY INSIDE eff4 (447..1196). The union is exactly eff4's own extent, so the merged box matched eff4 to 1 px, eff3 vanished, and nothing looked wrong. Parsed per quad, all five fire in both title entries in the declared stagger: eff1 130-131, eff2 133, eff3 133-134, eff4 133-135, eff/eff5 134+, back2 136+; and 5953-5955 / 5955-5957 / 5957-5958 / 5957-5959 / 5958+ / 5962+ in entry 2. Frames 133 and 134 are t=60.1 and 62.3, inside eff3's declared t in (58,64). Also retracts "the developer splash is one composited quad" -- the same bug, which the port refuted by arithmetic first (a 259-tall box cannot contain three logos spanning y 164..585). It draws three logos and three glows as separate quads in one indices=24 call; the 525x259 was gamearts_eff merged with seta_eff. The 9-unit black hold is unaffected: those glows are the developer splash's first draw. The three "ruled out" explanations were all aimed at the wrong failure. In particular the invisible-draw check counted draws with NO geometry line, when the hiding place was draws with PARTIAL geometry. Refuting three wrong hypotheses is not evidence for a fourth, and a list of failure modes written by whoever built the instrument is the least likely to contain its blind spot. Recorded in METHOD.md, along with the tell that was present and explained away: a merged box carries the first quad's colour, which made one element's alpha read 255/127/254 on consecutive frames. New tool: tools/re-capture/quads_per_frame.py parses vertices in groups of four and warns when the logged quad count falls short of indices/4. Also guards a double-A-tap in ui_draw_capture.sh: the movie branch ignored that TARGET=menu had already tapped, so a run tapped A on the title at t=23s and again at t=27s on the transition; the guest faulted and Xenia dumped registers to stdout until the file reached 519 MB. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
@@ -2028,8 +2028,9 @@ decoded rule about vertex colour.
|
||||
|
||||
## 2026-08-29 — `ptlogo_back2eff3` is declared on the disc and never drawn by the game
|
||||
|
||||
✅ **measured**, and this one is actionable: **you draw `eff3` at t=60–62 and the
|
||||
console does not.**
|
||||
🔴 ~~**measured**, and this one is actionable: **you draw `eff3` at t=60–62 and the
|
||||
console does not.**~~ **RETRACTED — see the correction at the end of this file.
|
||||
The console DOES draw it. You were right to keep drawing all five.**
|
||||
|
||||
Last time I called `eff3`'s absence unexplained and withdrew a bad explanation for
|
||||
it. Re-examined against the **second** title build-in in the same capture — the
|
||||
@@ -2142,3 +2143,63 @@ differing pixels, not the difference.
|
||||
|
||||
Detail: [`docs/re/structures/boot-splash-gap-measured.md`](../re/structures/boot-splash-gap-measured.md).
|
||||
|
||||
## 2026-08-29 — RETRACTION: the console draws all five flashes, including `eff3`
|
||||
|
||||
🔴🔴 **My "the game never draws `ptlogo_back2eff3`" was wrong.** You declined to act
|
||||
on it — *"I will not stop drawing an element on a claim whose own identification
|
||||
excludes that element from its bounding box"* — and that judgement was correct
|
||||
twice over: the identification was broken, and so was the finding built on the
|
||||
same instrument.
|
||||
|
||||
Parsed properly, **all five flashes fire in both title entries in the declared
|
||||
stagger**:
|
||||
|
||||
| element | entry 1 | entry 2 | declared |
|
||||
|---|---|---|---|
|
||||
| `eff1` | 130–131 | 5953–5955 | flash t54–58 |
|
||||
| `eff2` | 133 | 5955–5957 | flash t58–62 |
|
||||
| **`eff3`** | **133–134** | **5957–5958** | **flash t60–64** |
|
||||
| `eff4` | 133–135 | 5957–5959 | flash t62–66 |
|
||||
| `eff`/`eff5` | 134 → | 5958 → | holds |
|
||||
| `ptlogo_back2` | 136 → | 5962 → | holds |
|
||||
|
||||
Frames 133/134 are t = 60.1 and 62.3 — inside `eff3`'s declared window. **The disc
|
||||
was right about every element; my reading of the oracle was wrong.**
|
||||
|
||||
### The mechanism, because it invalidated your developer-splash correction's twin
|
||||
|
||||
A draw **batches several quads** — `indices=4` is one, `indices=8` two,
|
||||
`indices=24` six — and the log dumps only the first **8 vertices**. Min/max over a
|
||||
line's vertex list therefore *merges* quads.
|
||||
|
||||
`eff3` is batched with `eff4`, and because the wipe family is right-aligned, `eff3`
|
||||
(788…1196) lies **entirely inside** `eff4` (447…1196). The union is **exactly
|
||||
`eff4`'s extent** — the merged box matched `eff4` to 1 px and `eff3` simply
|
||||
disappeared, with nothing anomalous to notice.
|
||||
|
||||
🔴 **And your developer-splash refutation was the same bug**, which you found by
|
||||
arithmetic before I found it by measurement. `525×259` was `gamearts_eff` merged
|
||||
with `seta_eff`. The splash draws three logos and three glows as separate quads.
|
||||
⚠️ The **9-unit black hold is unaffected** — those glows are the developer
|
||||
splash's first draw, so frame 130 is still its first drawn frame.
|
||||
|
||||
### The part worth keeping
|
||||
|
||||
I reported three alternative explanations "ruled out". All three were aimed at the
|
||||
wrong failure — in particular, my "a draw the log cannot see" check counted draws
|
||||
with **no** geometry line, when the hiding place was draws with **partial**
|
||||
geometry. **Refuting three wrong hypotheses is not evidence for a fourth**, and a
|
||||
list of failure modes written by whoever built the instrument is the least likely
|
||||
to contain that instrument's blind spot.
|
||||
|
||||
`tools/re-capture/quads_per_frame.py` now parses vertices in groups of four and
|
||||
warns whenever the logged quad count falls short of `indices / 4`.
|
||||
|
||||
✅ Your independent derivation of **239.816** from the exported keyframes, against
|
||||
my 239.8 from the draw stream, is the check that conversion needed — it is the
|
||||
denominator of the 9-unit hold you now ship.
|
||||
|
||||
❔ **Still not settled: the main-menu sweeps.** Two capture attempts failed — one
|
||||
crashed the guest (a double Ⓐ tap, now guarded), one drifted to a flight screen.
|
||||
The title answer stands; the menu is unmeasured.
|
||||
|
||||
|
||||
@@ -171,5 +171,5 @@ files, which is how the same ground got covered twice.
|
||||
| [`structures/ui-tie-break-cost-at-settle.md`](structures/ui-tie-break-cost-at-settle.md) | What the unknown paint-order tie-break costs, in pixels | ✅ **decoded**, closing the open half of Q3: at the settled instant the tie-break costs **at most 1 px at Δ1**, on the **Japanese title only** (`ptlogo2`×`ptlogo_tm`, 5 px shared ink); **exactly 0 px on all five port screens**. The earlier 24-pair bound was a `rest()` count — and 10 of the title's 11 tied pairs are between `ptlogo_back2eff1`…`eff5`, five transient flashes that are **transparent** on the settled screen ([`ui-settle-time.md`](structures/ui-settle-time.md)). Live pairs at settle: entry 4 → **1**, entry 7 → **2**, the four loading bundles → **0**. ✅ Not a knife-edge — sweeping every keyframe time and midpoint, the count is **flat across the whole settle window**, and the loading bundles' tie is live only at t17–t33. ✅ Controls: an overlapping *different*-key swap moves 25 310 / 268 698 / ~765 000 px on the entries reporting zero; zeros are explained by shared-ink counts (the `ptframe` pairs share **0 px** of ink). ⚠️ Entries 0/1/12/15 have **no live control** — their zeros rest on keyframe data, not a render. 🟡 Refutation attempt on the corpus's "24 pairs": **survives** as a rest-pose bound, 16/16 on entry 7. ❔ *Why* ties order as they do is still unknown — and now worth one pixel |
|
||||
| [`structures/ui-record-loop-length.md`](structures/ui-record-loop-length.md) | Where a looping record's cycle restarts — and the `PRESS Ⓐ` plate's real period | ✅ **decoded**: a nested record is itself a RATC bundle and its header **`+0x08` is the loop length**; its keyframes need not fill it, and the slack is a hold at the final pose. Disc-wide over **1 781** timed nested records: 92.3 % declare exactly their last keyframe time, **7.7 % declare more**, and **0 declare less** — the falsifier (a cycle cannot restart before its own last pose) never fires. 🔴 **The plate's `ptbtn00f` is 105 units of ramp inside a 120-unit cycle, so it holds dark for 15 units** — the port was shipping **105**, and the answer is **120**. ✅ Falsification test against the running game, using a pacing factor measured *independently* on the focus ring (declared 120 → **2.177 s**, factor **1.0885**): to reach the corpus's measured 2.12–2.34 s, 105 units needs a factor of **1.211–1.337** (🔴 excludes the ring's) while 120 needs **1.060–1.170** (✅ contains it). Different elements, different bundles, separate runs — tied only by both declaring 120. ⚠️ Says where a cycle *ends*, not which records cycle. ❔ the **top-level** `+0x08` (300 on every `GP_TITLE` entry, elements ending at 244–269) is a different question, untouched |
|
||||
| [`structures/ui-focus-record-pulse-census.md`](structures/ui-focus-record-pulse-census.md) | Every focus record whose glow pulses, and where `rest()` puts it | ✅ **decoded**, disc-wide: **1 130** focus records, **2 664** timed elements, **210 with a varying alpha** — of which **202** have `rest()` == the **peak** (burns bright forever) and **8** land **mid-ramp**. By pak: `PILOTLOG` 116, `MOVIE_THEATER` 54, `HANGAR_ARSENAL` 30, `LEADERBOARD` 8, **`GP_TITLE` 2**. 🟡 Bounds rather than refutes the port's "34 in the export, 2 varying, nothing to fix" — correct, and correct *because* `GP_TITLE` has 2; the pathology sits in the screens a wider port needs next. 🔴 The 8 mid-ramp ones are the worse mode: `py_ranking_btn01f` swings 255→127→255 and `rest()` returns **244**, neither extreme, which looks entirely plausible and nothing reports it. ✅ Control: `ptbtn01f` is genuinely constant (255 throughout) and is **not** flagged; two hits verified keyframe by keyframe. ⚠️ A pulsing element has no resting pose — the question is malformed, not mis-answered; `pose_at(t)` inside the record's declared cycle ([`ui-record-loop-length.md`](structures/ui-record-loop-length.md)) is the only well-formed query. ⚠️ 210 is a **floor**: focus records are matched by the `Xf.rat` name rule, and varying scale/rotation/position is not counted |
|
||||
| [`structures/ui-title-buildin-measured.md`](structures/ui-title-buildin-measured.md) | The title's build-in and the plate glow, read out of the guest's own draw stream | ✅ **measured** (Canary, `ARM=early` draw capture): the decoded *mechanism* is observed, not just its end state. **The five flashes fire in a six-frame window and are absent from all 155 other sampled frames**; `ptlogo_back2eff1` is drawn in exactly 2 frames at **t = 54.0** against a decoded peak of **t54–56**, and `ptlogo1` first appears at **t = 42.2** against a decoded **t42** — with units/frame taken from the **glow's period alone**, a different element. The two holders (`ptlogo_back2eff`, `ptlogo_back2`) are continuous from frame 134. ✅ The glow's per-vertex colour alpha IS its fade alpha: **observed range 0…80 against a decoded peak of 80**, exact and unfitted; **period 51.158 presented frames** over 20 cycle starts; fitting the decoded ramp gives RMS **13.16** against **38.18 reversed** (2.9×), so the asymmetry is real and correctly directed. Structure: the settled title is 10–11 draws naming no sprite — which is why arming at the title sees nothing. ⚠️ Frame **107** is a 27-draw spike between the movie's last frame and the title's first; calling it "the composite" was an **over-read** — it binds **no texture** and only 4 of its 27 draws log geometry. The second title entry has no such frame. ⚠️ The two entries are the same animation at **different sampling phases** (only 4 of 46 aligned frames match), which is what makes the `eff3` result robust. 🔴 **The game does not draw `ptlogo_back2eff3` at all** — reproduced over **two** title entries 5 800 frames apart, and three alternative explanations tested and failed: *phase* (its window is **6 units** against a **2.23-unit** step, so it cannot be missed — frames 133/134 sit at t=60.1/62.3 inside it and draw `eff2` and `eff4` instead), *an unlogged draw* (exactly 2 blind draws/frame, always the same full-screen-triangle shader, present when no wipe is active), and *a bad position guess* (dropping position entirely, **zero** quads anywhere have a width within ±30 of 408; the spectrum jumps 262 → 748). Draw counts across both entries: eff1 **4**, eff2 **3**, eff3 **0**, eff4 **6**. 🔴 **The port draws `eff3` at t=60–62 and the console does not.** ❔ Why is not established — nothing in its element record differs from its neighbours. ⚠️ An earlier "sub-frame phase" explanation and the advice that drawing all five "shows more sweep than the console" are both **withdrawn**. ⚠️ What a frame-by-frame build-in comparison *will* show is disagreement about which flash lands in which frame — 2 units/submitted frame against this run's 2.231 units/presented frame — and neither side is wrong. 🔴 **Trap:** matching a bound texture's dimensions to a sprite fails both ways — it missed every flash *and* read the intro movie's 640×360 YUV planes as `ptbase2`. ✅ A regression of five events' observed frames against their declared times (residuals ≤0.9 frames) recovers the intercept at frame **106.1** when the composite spike, not in the fit, is frame **107**. ⚠️ Per-vertex alpha = fade alpha holds for the **glow** and does not generalise — `eff4` reads 255/127/254 on consecutive frames. ❔ Frame rate not recorded, so nothing is in seconds; the glow's period implies a **114**-unit cycle against a declared 120, unexplained; `eff5` vs `ptlogo_back2eff` not separated |
|
||||
| [`structures/boot-splash-gap-measured.md`](structures/boot-splash-gap-measured.md) | The black gap between the two boot splashes | ✅ **measured** in the guest's **draw stream**, which separates true black from a fade tail where luminance cannot: the publisher's last sprite is frame 125 (alpha 7), then **frames 126–129 submit NO sprite quad at all**, then the developer fades in at alpha 34. **The gap is 4 presented frames.** Converted with the disc as its own clock — `palogo_sqex` declares alpha≥1 for **239.8 units** and is drawn in **105** frames → **2.284 units/frame** (the title capture independently gave 2.231) — that is **~9.1 units ≈ 0.152 s**, against the **12** the port authored; ⚠️ and the true black is *shorter*, since both boundary frames still carry picture. ✅ Second finding: the **developer splash is ONE composited 525×259 quad** at the bounding box of its three declared logos, none of whose individual sizes is ever submitted. ❌ Not declared on the disc: `palogo_eff0.prm` is a single static keyframe, and the top-level `+0x08` is a **family constant** (300 / 60) whose slack ranges 12–226 units. ❔ The executable is **not** looked at — named, not claimed. 🔴 The instrument was perturbing the measurement: the capture script taps Ⓐ on "screen changed a lot", which is also true of a fading splash — it tapped through the publisher and the developer never appeared. `GRACE=1` and `NOTAP=1` knobs added |
|
||||
| [`structures/ui-title-buildin-measured.md`](structures/ui-title-buildin-measured.md) | The title's build-in and the plate glow, read out of the guest's own draw stream | ✅ **measured** (Canary, `ARM=early` draw capture): the decoded *mechanism* is observed, not just its end state. **The five flashes fire in a six-frame window and are absent from all 155 other sampled frames**; `ptlogo_back2eff1` is drawn in exactly 2 frames at **t = 54.0** against a decoded peak of **t54–56**, and `ptlogo1` first appears at **t = 42.2** against a decoded **t42** — with units/frame taken from the **glow's period alone**, a different element. The two holders (`ptlogo_back2eff`, `ptlogo_back2`) are continuous from frame 134. ✅ The glow's per-vertex colour alpha IS its fade alpha: **observed range 0…80 against a decoded peak of 80**, exact and unfitted; **period 51.158 presented frames** over 20 cycle starts; fitting the decoded ramp gives RMS **13.16** against **38.18 reversed** (2.9×), so the asymmetry is real and correctly directed. Structure: the settled title is 10–11 draws naming no sprite — which is why arming at the title sees nothing. ⚠️ Frame **107** is a 27-draw spike between the movie's last frame and the title's first; calling it "the composite" was an **over-read** — it binds **no texture** and only 4 of its 27 draws log geometry. The second title entry has no such frame. ⚠️ The two entries are the same animation at **different sampling phases** (only 4 of 46 aligned frames match), which is what makes the `eff3` result robust. 🔴🔴 **RETRACTED — the game DOES draw `ptlogo_back2eff3`, and all five flashes fire in both entries in the declared stagger** (`eff3` at frames 133–134 / 5957–5958, i.e. t=60.1 and 62.3, inside its declared t∈(58,64)). The absence was an **instrument artefact**: a draw batches several quads (`indices=8` is two) and the log dumps only the first 8 vertices, so min/max over a line **merges** them — and because the wipe is right-aligned, `eff3` (788…1196) lies entirely inside `eff4` (447…1196), making the union *exactly* `eff4`'s extent. The merged box matched `eff4` to 1 px. 🔴 Three explanations had been "ruled out" and all three were aimed at the wrong failure — notably the invisible-draw check counted draws with **no** geometry, where the hiding place was **partial** geometry. Superseded text follows: ~~three alternative explanations tested and failed: *phase* (its window is **6 units** against a **2.23-unit** step, so it cannot be missed — frames 133/134 sit at t=60.1/62.3 inside it and draw `eff2` and `eff4` instead), *an unlogged draw* (exactly 2 blind draws/frame, always the same full-screen-triangle shader, present when no wipe is active), and *a bad position guess* (dropping position entirely, **zero** quads anywhere have a width within ±30 of 408; the spectrum jumps 262 → 748). Draw counts across both entries: eff1 **4**, eff2 **3**, eff3 **0**, eff4 **6**.~~ (all from the merged-box parse, and wrong) 🔴 **The port draws `eff3` at t=60–62 and the console does not.** ❔ Why is not established — nothing in its element record differs from its neighbours. ⚠️ An earlier "sub-frame phase" explanation and the advice that drawing all five "shows more sweep than the console" are both **withdrawn**. ⚠️ What a frame-by-frame build-in comparison *will* show is disagreement about which flash lands in which frame — 2 units/submitted frame against this run's 2.231 units/presented frame — and neither side is wrong. 🔴 **Trap:** matching a bound texture's dimensions to a sprite fails both ways — it missed every flash *and* read the intro movie's 640×360 YUV planes as `ptbase2`. ✅ A regression of five events' observed frames against their declared times (residuals ≤0.9 frames) recovers the intercept at frame **106.1** when the composite spike, not in the fit, is frame **107**. ⚠️ Per-vertex alpha = fade alpha holds for the **glow** and does not generalise — `eff4` reads 255/127/254 on consecutive frames. ❔ Frame rate not recorded, so nothing is in seconds; the glow's period implies a **114**-unit cycle against a declared 120, unexplained; `eff5` vs `ptlogo_back2eff` not separated |
|
||||
| [`structures/boot-splash-gap-measured.md`](structures/boot-splash-gap-measured.md) | The black gap between the two boot splashes | ✅ **measured** in the guest's **draw stream**, which separates true black from a fade tail where luminance cannot: the publisher's last sprite is frame 125 (alpha 7), then **frames 126–129 submit NO sprite quad at all**, then the developer fades in at alpha 34. **The gap is 4 presented frames.** Converted with the disc as its own clock — `palogo_sqex` declares alpha≥1 for **239.8 units** and is drawn in **105** frames → **2.284 units/frame** (the title capture independently gave 2.231) — that is **~9.1 units ≈ 0.152 s**, against the **12** the port authored; ⚠️ and the true black is *shorter*, since both boundary frames still carry picture. 🔴 **RETRACTED**: "the developer splash is ONE composited 525×259 quad" — the same batching artefact. It draws three logos and three glows as separate quads in one `indices=24` call; the 525×259 was `gamearts_eff` merged with `seta_eff`. The port refuted it with arithmetic (a 259-tall box cannot hold logos spanning y 164…585) before I checked. ⚠️ The gap measurement is unaffected — those glows are the developer splash's first draw. ❌ Not declared on the disc: `palogo_eff0.prm` is a single static keyframe, and the top-level `+0x08` is a **family constant** (300 / 60) whose slack ranges 12–226 units. ❔ The executable is **not** looked at — named, not claimed. 🔴 The instrument was perturbing the measurement: the capture script taps Ⓐ on "screen changed a lot", which is also true of a fading splash — it tapped through the publisher and the developer never appeared. `GRACE=1` and `NOTAP=1` knobs added |
|
||||
|
||||
@@ -1080,3 +1080,44 @@ title binds only 1280×768 pages — both were there to be read first.
|
||||
|
||||
The general shape: **a coincidence of size is not an identification.** Before
|
||||
matching on one attribute, ask what else in the frame shares it.
|
||||
|
||||
## A batched draw merges quads, and the merge can be invisible
|
||||
|
||||
A GPU draw can carry several quads — `indices=4` is one, `indices=8` two,
|
||||
`indices=24` six — and the UI draw log dumps **only the first 8 vertices**. Taking
|
||||
min/max over a log line's whole vertex list therefore silently *merges* quads into
|
||||
one bounding box.
|
||||
|
||||
This produced two wrong findings in one session, one of them reported to another
|
||||
agent with three alternative explanations "ruled out":
|
||||
|
||||
* **`ptlogo_back2eff3` "is never drawn by the game".** It is batched with
|
||||
`ptlogo_back2eff4`, and because the wipe family is right-aligned, `eff3`
|
||||
(788…1196) lies **entirely inside** `eff4` (447…1196). The union is *exactly*
|
||||
`eff4`'s extent — so the merged box matched `eff4` to 1 px, `eff3` vanished, and
|
||||
nothing looked wrong.
|
||||
* **"the developer splash is one composited quad."** `gamearts_eff` and
|
||||
`seta_eff` merged into a box that was read as the bounding box of three logos —
|
||||
which it could not have been, since it was 259 px tall and they span 421.
|
||||
|
||||
**Why the checks failed.** Three hypotheses were tested and refuted — sampling
|
||||
phase, a draw with no geometry logged, a bad position guess. All three were aimed
|
||||
at the wrong failure. In particular the "invisible draw" check counted draws with
|
||||
**no** geometry line; the hiding place was draws with **partial** geometry, which
|
||||
was never looked for.
|
||||
|
||||
> 🔴 **Refuting three wrong hypotheses is not evidence for a fourth.** The
|
||||
> confidence gained from "I ruled out everything I could think of" is worth
|
||||
> exactly as much as the list was complete, and a list of failure modes assembled
|
||||
> by the person who built the instrument is the least likely to contain that
|
||||
> instrument's own blind spot.
|
||||
|
||||
Parse vertices in groups of four, one per quad, and **compare the logged quad
|
||||
count against `indices / 4`** — `tools/re-capture/quads_per_frame.py` does both and
|
||||
warns on the shortfall.
|
||||
|
||||
⚠️ A related tell that was present and ignored: a merged box carries the *first*
|
||||
quad's vertex colour, which made one element's alpha read 255 / 127 / 254 on
|
||||
consecutive frames. That non-monotonicity was noticed, written down as "the
|
||||
vertex-alpha identity does not generalise", and not chased. **An anomaly you
|
||||
explain away is cheaper to chase than to re-derive later.**
|
||||
|
||||
@@ -58,15 +58,24 @@ the last publisher frame still carries alpha 7 and the first developer frame
|
||||
alpha 34, so both boundary frames contain some picture that this count treats as
|
||||
black.
|
||||
|
||||
## ✅ A second thing the draw stream shows: the developer splash is ONE quad
|
||||
## 🔴 RETRACTED: "the developer splash is ONE composited quad"
|
||||
|
||||
The developer bundle declares three logos — `palogo_gamearts` at (390,164),
|
||||
`palogo_seta` at (521,316), `palogo_anima` — and **none of their sizes is ever
|
||||
submitted**. What is submitted is a single **525×259 quad at (378,155)**, which is
|
||||
the bounding box of the three. The game composites them and blits the group.
|
||||
**It is not.** The three logos and their glows are drawn as separate quads,
|
||||
**batched into a single draw call** — `indices=24` is six quads — and the log dumps
|
||||
only the first 8 vertices. The "525×259 quad at (378,155)" was min/max taken across
|
||||
two *different* quads: `palogo_gamearts_eff` (525×91 at 378,154) and
|
||||
`palogo_seta_eff` (262×108 at 512,306).
|
||||
|
||||
This is why an earlier pass reported "developer splash: 0 frames" — it was
|
||||
matching individual logo sizes that the game never draws.
|
||||
The port refuted it with arithmetic before I had checked: a 259-tall box cannot
|
||||
contain three logos spanning y 164…585, and `palogo_anima` alone starts 35 px below
|
||||
its bottom edge. They were right, and they were right to keep drawing three.
|
||||
|
||||
⚠️ **The gap measurement is unaffected.** Those glows are the *first* thing the
|
||||
developer splash draws (`t0 a0 → t15 a255`), so frame 130 is still the developer
|
||||
screen's first drawn frame, and frames 126–129 still submit nothing at all.
|
||||
|
||||
See [`ui-title-buildin-measured.md`](ui-title-buildin-measured.md) for the same
|
||||
trap producing a worse error on the title.
|
||||
|
||||
## Is the gap declared anywhere? Not that I can find
|
||||
|
||||
|
||||
@@ -79,52 +79,58 @@ a different element**, taking the composite spike (frame 107) as t=0:
|
||||
other 155 frames sampled.** The two holders are present continuously from frame
|
||||
134 onward. That is the decoded mechanism, observed.
|
||||
|
||||
## 🔴 The game does not draw `ptlogo_back2eff3`
|
||||
## 🔴🔴 RETRACTED: "the game does not draw `ptlogo_back2eff3`"
|
||||
|
||||
**Reproduced over two title entries, 5 800 frames apart, in one run.** The disc
|
||||
declares `ptlogo_back2eff3` — alpha 0 at t58, **255 at t60–62**, 0 at t64, at
|
||||
(788, 117), sprite 408×203 — and the running game never submits it.
|
||||
**It draws it. All five flashes fire, in both title entries, in exactly the
|
||||
declared stagger.** The claim was an instrument artefact, and the instrument was
|
||||
mine.
|
||||
|
||||
The wipe family is right-aligned: `eff2` 938+258, `eff3` 788+408, `eff4` 447+749,
|
||||
`eff5` 64+1133 all end at x≈1196. It is a left-growing wipe in four widths, and
|
||||
**the game draws three of them.**
|
||||
|
||||
| element | width | draws across both build-ins | expected at ~2.23 units/frame |
|
||||
| element | entry 1 | entry 2 | declared |
|
||||
|---|---|---|---|
|
||||
| `eff1` | 167 | 4 | ~5 |
|
||||
| `eff2` | 258 | 3 | ~5 |
|
||||
| **`eff3`** | **408** | **0** | **~5** |
|
||||
| `eff4` | 749 | 6 | ~5 |
|
||||
| `ptlogo_back2eff1` | 130–131 | 5953–5955 | flash t54–58 |
|
||||
| `ptlogo_back2eff2` | 133 | 5955–5957 | flash t58–62 |
|
||||
| **`ptlogo_back2eff3`** | **133–134** | **5957–5958** | **flash t60–64** |
|
||||
| `ptlogo_back2eff4` | 133–135 | 5957–5959 | flash t62–66 |
|
||||
| `ptlogo_back2eff` / `eff5` | 134 → | 5958 → | holds |
|
||||
| `ptlogo_back2` | 136 → | 5962 → | holds |
|
||||
|
||||
⚠️ An earlier version of this page called this a **sub-frame phase effect**. That
|
||||
was wrong and is withdrawn. Three explanations were tested and all fail:
|
||||
Frames 133 and 134 sit at t = 60.1 and 62.3 — inside `eff3`'s declared t ∈ (58, 64).
|
||||
The disc was right about every one of them.
|
||||
|
||||
* **Sampling phase.** `eff3`'s non-zero window is t ∈ (58, 64) — **six units**,
|
||||
against a step of **2.23 units per presented frame**. A window wider than the
|
||||
step *cannot* be missed: at least two frames must land inside it, and frames 133
|
||||
(t = 60.1) and 134 (t = 62.3) do. Both draw `eff2` and `eff4`; neither draws
|
||||
`eff3`.
|
||||
* **A draw the log cannot see.** Exactly **2** draws per frame carry no geometry,
|
||||
on all 932 settled title frames — always the same full-screen-triangle shader
|
||||
(`prim=8 indices=3`, `vs=0x72CBCAA6A7984111`), present on frames where no wipe
|
||||
element is active at all. `eff3` cannot be one of them.
|
||||
* **A bad position guess on my side.** Dropping the position entirely and
|
||||
searching *every* quad submitted anywhere on screen during both build-in
|
||||
windows: **zero** have a width within ±30 of 408. The width spectrum jumps
|
||||
straight from 262 to 748.
|
||||
### Why it looked absent, and why the checks that "ruled that out" did not
|
||||
|
||||
❔ **Why the game skips it is not established.** Nothing in its element record
|
||||
distinguishes it — same kind (`0x0`), same keyframe shape, same `u4`/`u8`, same
|
||||
scale, as `eff2` and `eff4` either side of it.
|
||||
**A draw can batch several quads.** `indices=4` is one quad, `indices=8` is two,
|
||||
`indices=24` is six — and the log dumps **only the first 8 vertices**. Taking
|
||||
min/max over a line's whole vertex list therefore *merges* quads into a single
|
||||
box.
|
||||
|
||||
🔴 **For the port: you draw `eff3` at t=60–62 and the console does not.** That is
|
||||
one extra frame of wipe, at the widest-but-one step. It is small, and it is real.
|
||||
`eff3` is batched with `eff4` in an `indices=8` draw. And `eff3` (788…1196) sits
|
||||
**entirely inside** `eff4`'s x-range (447…1196), because the wipe family is
|
||||
right-aligned — so the union of the two is **exactly `eff4`'s own extent**. The
|
||||
merged box matched `eff4` to 1 px, `eff3` disappeared, and nothing looked wrong.
|
||||
|
||||
🔴 **A second thing this page previously claimed, also withdrawn: that a port
|
||||
drawing all five flashes shows "more sweep than the console".** There is no
|
||||
evidence for that. The port draws them sequentially at their declared times, never
|
||||
more than two at once, which is what frames 131–135 above show the game doing.
|
||||
The pile-up worth warning about was the `rest()` bug, and that is fixed.
|
||||
Every check I ran was aimed at the wrong failure:
|
||||
|
||||
* "sampling phase" — correctly refuted, and irrelevant;
|
||||
* "a draw the log cannot see" — I counted draws with **no** geometry line. The
|
||||
hiding place was draws with **partial** geometry, which I never looked for;
|
||||
* "a bad position guess" — I searched for a 408-wide box. The box did not exist
|
||||
because it had been merged, not because the quad had not been drawn.
|
||||
|
||||
**Three refutations of the wrong hypothesis do not add up to one confirmation.**
|
||||
|
||||
`tools/re-capture/quads_per_frame.py` now parses vertices in groups of four, one
|
||||
per quad, and warns when a batch exceeds the 8-vertex cap.
|
||||
|
||||
### What this also explains
|
||||
|
||||
`eff4`'s alpha read 255 / 127 / 254 on consecutive frames — non-monotonic, which I
|
||||
flagged as "the vertex-alpha identity does not generalise". It was not the
|
||||
identity failing; those were **merged boxes carrying the first quad's colour**.
|
||||
|
||||
🔴 **A second claim, also withdrawn: that a port drawing all five flashes shows
|
||||
"more sweep than the console".** The opposite is true — the console draws all
|
||||
five. Drawing them sequentially at their declared times is exactly right.
|
||||
|
||||
⚠️ **What a frame-by-frame comparison of the build-in WILL show, and it is not a
|
||||
defect on either side.** The game's timeline is 60 units/s against a 30 Hz
|
||||
|
||||
Reference in New Issue
Block a user