Answers question 1 of the 2026-09-02 play-test: interpolate or hold. It interpolates, piecewise-linearly, evaluated once per present at one unit per present. palogo_sqex_eff gives 28 distinct alphas over 28 consecutive presents, changing on 26 of 27 adjacent pairs. It is not one slope, and the disc says why: that element declares 0:a=0 -> 15:a=255 -> 30:a=212 -> 45:a=0, three segments with three gradients. Predicted -2.87 and -14.13 per unit against measured modal steps of -3 (x6) and -14 (x9). The declared keyframes predict the per-frame steps, which makes this a prediction rather than a description. So the port must lerp: hold-to-next-key would emit 3 states where the game emits 28. And "eased" is the wrong description -- there is no easing function, the envelope only looks eased because consecutive declared segments have different gradients. Alpha lives in the per-vertex k_8_8_8_8 colour, rewritten into a fresh vertex buffer every frame. Not a PS constant (ps_c[n=0] on 1048/1048), not a blend factor, not a texture swap. 🔴 And the game's splash is ALSO mostly frozen. Measured with the same statistic the play-test used on the port: the game moves 21.2% and 27.8% against the port's 16.4%, and its longest frozen run is 3.34 s against the port's 3.20 s. The publisher declares 205 of 255 units -- 80% -- as a flat hold at full opacity. That refutes the play-test's second clause. "A fade does not hold one picture for 3.20 s" -- this one does, for 3.34 s. Its first clause stands: 26 states for a 45-unit build-in is too few, the game gives 49 and 51. The deficit is the state count, not the freeze: ~100 against 26. Acting on the second clause would have sent the port to remove the one part of its splash that is already right. Not answered: which function does it. This is the behaviour; the image-side half of question 1 is still open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
107 lines
4.9 KiB
Markdown
107 lines
4.9 KiB
Markdown
# ✅ The game **interpolates piecewise-linearly, every frame** — and its splash is *also* mostly frozen
|
||
|
||
**Status: ✅ measured, and the declared keyframes predict the measured steps.**
|
||
2026-09-02. Instrument: ⟨capture⟩ — per-frame vertex alpha off the guest's own
|
||
vertex buffer; ⟨disc⟩ for the keyframes that predict it.
|
||
Series: [`data/splash-per-frame-alpha-series.txt`](data/splash-per-frame-alpha-series.txt).
|
||
|
||
Answers question 1 of [`../agents/PLAYTEST-2026-09-02.md`](../agents/PLAYTEST-2026-09-02.md)
|
||
— *"what does it do BETWEEN keyframes — interpolate, or hold to the next key?
|
||
That single answer decides whether the port should lerp at all."*
|
||
|
||
---
|
||
|
||
## 1 — it interpolates. Every frame. Piecewise-linearly.
|
||
|
||
`palogo_sqex_eff`, 28 consecutive presents, **28 distinct alphas**, changing on
|
||
**26 of 27** adjacent pairs:
|
||
|
||
```
|
||
34 85 204 221 238 254 249 246 243 237 232 229 226 223 214 211 197 169 141
|
||
127 113 98 84 70 56 42 28 14
|
||
```
|
||
|
||
**It is not one slope, and the disc says why.** That element declares
|
||
`0:a=0 → 15:a=255 → 30:a=212 → 45:a=0`, which is three segments with three
|
||
different gradients. Predicted against measured, per unit:
|
||
|
||
| declared segment | predicted Δα/unit | measured modal step |
|
||
|---|---|---|
|
||
| `15 → 30` (255 → 212) | **−2.87** | **−3** ×6 |
|
||
| `30 → 45` (212 → 0) | **−14.13** | **−14** ×9 |
|
||
|
||
**The declared keyframes predict the per-frame steps.** That is the whole answer:
|
||
the game evaluates a linear interpolation between the two bracketing keyframes,
|
||
once per present, at one unit per present.
|
||
|
||
> **The port must lerp.** Hold-to-next-key would emit 3 states where the game
|
||
> emits 28.
|
||
|
||
⚠️ **And "eased" is the wrong description**, which matters because a port that
|
||
believes it will fit a curve. There is no easing function — the *envelope* looks
|
||
eased only because consecutive declared segments have different gradients. Every
|
||
segment is straight.
|
||
|
||
## 2 — where the alpha lives, so it can be watched
|
||
|
||
**The per-vertex `k_8_8_8_8` colour**, in a vertex buffer the guest rewrites into
|
||
a fresh address every frame. Ruled out by the same captures:
|
||
|
||
* **not a PS constant** — `ps_c[n=0]` on 1 048 / 1 048 splash draws;
|
||
* **not a blend factor** — the blend register is constant across the whole splash;
|
||
* **not a texture swap** — one texture is bound throughout.
|
||
|
||
## 3 — 🔴 the game's splash is ALSO mostly frozen, and the port's 3.2 s hold is CORRECT
|
||
|
||
Measured with the same statistic the play-test applied to the port:
|
||
|
||
| | **game** publisher | **game** developer | **port** (both) |
|
||
|---|---|---|---|
|
||
| moving | **21.2 %** | **27.8 %** | 16.4 % |
|
||
| longest frozen run | **3.34 s** | **2.50 s** | 3.20 s |
|
||
| distinct states | **49** | **51** | **26 total** |
|
||
|
||
📌 **The play-test's inference does not hold, though its observation does.** It
|
||
reads *"a fade does not hold one picture for 3.20 s"* as proof of breakage. **The
|
||
game holds one picture for 3.34 s.** The publisher's declared timeline is
|
||
`0:a=0 → 15:a=0 → 30:a=255 → 235:a=255 → …`, i.e. **205 of 255 units — 80 % — is
|
||
a flat hold at full opacity.** A splash that is static most of the time is what
|
||
the disc describes.
|
||
|
||
🔴 **So the deficit is not the freeze. It is the state count: ~100 against 26.**
|
||
The game changes alpha on *every present* during a ramp — 15 distinct values for
|
||
a 15-unit ramp — and the port produces roughly a quarter of that across both
|
||
splashes. **Fixing the hold would make it worse; the ramps are where the states
|
||
are missing.**
|
||
|
||
## What the port should do
|
||
|
||
1. **Lerp between bracketing keyframes, evaluated once per frame** — not
|
||
hold-to-next-key, and not an easing function.
|
||
2. **Keep the long hold.** ~3.3 s of genuinely identical frames is correct.
|
||
3. Expect **~15 distinct alphas per 15-unit ramp**, ~100 across both splashes.
|
||
4. Alpha is a **per-quad scalar**, uniform across the quad's four vertices.
|
||
|
||
## Refutation attempt, recorded per the adversarial duty
|
||
|
||
**Target:** the play-test's *"A 45-unit build-in cannot be drawn in 26 states, and
|
||
a fade does not hold one picture for 3.20 s."*
|
||
|
||
**Result: the first clause SURVIVES, the second is REFUTED.** 26 states for a
|
||
45-unit build-in is indeed too few — the game gives 49 and 51. But the game holds
|
||
one picture for **3.34 s**, longer than the port's 3.20 s, and the disc declares
|
||
80 % of the publisher splash as a flat hold. Recorded because acting on the second
|
||
clause would have sent the port to remove the one part of its splash that is
|
||
right.
|
||
|
||
## Reach
|
||
|
||
⟨capture⟩, one boot, both splashes, English locale. The interpolation law is
|
||
checked against ⟨disc⟩ keyframes on one element with three gradients, which is
|
||
what makes it a prediction rather than a description — **it has not been checked
|
||
on the title or the menus**, and doing so is the obvious next step.
|
||
|
||
❔ **Not answered here: which function does it.** This is the *behaviour*, measured.
|
||
The image-side half of question 1 — the function that advances the clock and
|
||
evaluates the segment — is not found yet.
|