# ❔ The keyframe interpolator is not found — but four routes are now excluded **Status: ❔ undecodable so far, with reach.** 2026-09-02. Instrument: ⟨image⟩ — mechanical scans of `/image/sylpheed.pe`, no database rows. Question 1 of [`../agents/PLAYTEST-2026-09-02.md`](../agents/PLAYTEST-2026-09-02.md) has two halves. **The behavioural half is answered** — the game interpolates piecewise-linearly, every frame, and the declared keyframes predict the measured per-frame steps ([`splash-interpolates-every-frame.md`](splash-interpolates-every-frame.md)). **This page is the other half: *which function*, and it is not found.** Recorded because a bounded negative stops the next attempt repeating four searches that cost nothing to state and an hour to redo. --- ## What was excluded, and how The UI region throughout is `0x82200000 … 0x823FFFFF`, which is where the corpus places the screen/bundle subsystem and the quad-emitter chain ([`ui-quad-class-foothold.md`](ui-quad-class-foothold.md)). | route | search | result | |---|---|---| | **integer lerp** | a `divw`/`divwu` with both a `mullw` and a `subf` in the preceding 10 instructions — the shape of `v0 + (v1−v0)·(t−t0)/(t1−t0)` | **28 sites image-wide, NONE in the UI region.** The evaluator is not integer multiply-divide there | | **indexed record access** | `mulli rD,rA,40` — the keyframe record stride is 40 bytes ⟨disc⟩ | **31 sites, NONE in the UI region.** Records are not addressed by multiply | | **pointer walk by stride** | `addi rX,rX,40` inside the UI region | 43 sites. The ones in the screen/bundle subsystem — `0x823CCA6C`, `0x823CCA94` — disassemble to a **40-byte container copy loop** (`mtspr CTR,10` then a 10-word copy), i.e. a `vector<40-byte>` reallocation. **Not an evaluator** | | **float lerp** | `fmadd`-family ops in the UI region | **811 sites over 142 pages** — far too diffuse to select on. Not excluded; **not narrowed either** | 📌 **The useful part is the first two.** Together they say the evaluator does not compute a fraction with integer multiply-and-divide, and does not index its records by multiplication. Combined with the measured behaviour — steps that land on exact integers like −3 and −14 — the likeliest remaining shape is a **float lerp with a reciprocal computed once per segment**, then converted to a byte. That is a hypothesis, and the `fmadd` scan shows it cannot be found by opcode shape alone. ## What would find it, in cost order 1. **Trace down from the quad emitter.** `sub_823C2AC0` — the accessor that hands out the vertex pointer — has exactly **6 callers**, four of them sibling quad emitters (`sub_821D6A40`, `sub_822380B0`, `sub_82234610`, `sub_821BC718`). `sub_822380B0` calls it and then reads its colour from fields of `this` (`+0x04`, `+0x08`, `+0x0C`, `+0x10`). **Whoever writes those fields is one step from the interpolator**, and the caller set is small enough to enumerate. This is the route I would take next and did not have budget for. 2. **Watch it from the guest instead of reading for it.** The alpha is in a vertex buffer at a known address each frame; a watchpoint on the byte that becomes `k_8_8_8_8` alpha would name the writer directly. `/canary` is read-write and already carries four RE logger patches. ## Why this is not blocking the port **It is not.** The port needs to know *whether to lerp and how*, and that is answered and measured. Naming the function would let the answer generalise from the splashes to every screen without further captures — worth having, not worth holding the port for. ## Reach ⟨image⟩, exhaustive over the whole 9.2 MB for the two excluded opcode shapes, so those negatives are complete rather than sampled — the instruction forms searched genuinely do not occur in that address range. **They do not exclude the interpolator living outside `0x82200000…0x823FFFFF`**, which is an assumption inherited from `ui-quad-class-foothold.md` and not independently checked here.