re: 210 focus records pulse, not 2 -- and 8 of them fail in a way that looks right

The port censused focus-record alpha over its own export -- 34 elements, 2
varying, both `ptbtn00f` -- and concluded there is nothing to fix. That is
correct and correctly scoped. This asks the same question of the whole disc.

1 130 focus records, 2 664 timed elements, 210 with a varying alpha. 202 have
`rest()` returning the PEAK, the `ui-settle-time` pathology. By pak:
PILOTLOG 116, MOVIE_THEATER 54, HANGAR_ARSENAL 30, LEADERBOARD 8, GP_TITLE 2.

So the port's 2 is right because GP_TITLE has 2. The scope was load-bearing
and was not stated as a limit -- "only 2 have a varying alpha" reads as a fact
about the format and is a fact about one pak. The pathology is concentrated in
exactly the screens a wider port reaches next.

The 8 LEADERBOARD ones are the worse mode. `py_ranking_btn01f` swings
255->127->255 with no two adjacent keyframes equal, so `rest()` falls through
to its longest-dwell rule and returns 244 -- neither the peak nor the trough.
A glow stuck at its peak is visibly wrong; one stuck at 244 of a 127..255
range looks entirely plausible and nothing reports it.

Verified rather than asserted: two hits dumped keyframe by keyframe, and a
control on `ptbtn01f`, which is genuinely constant across its cycle and is
correctly NOT flagged. `py_ranking_btn01f` also confirms the loop-length
decode independently -- its ramp ends at t=90 inside a declared 120-unit
cycle, holding bright for 30 units.

Reach stated: 210 is a floor. Focus records are matched by the `Xf.rat` name
rule, and elements with constant alpha but varying scale, rotation or
position have the same problem and are not counted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
sylph-decoder
2026-08-29 19:45:17 +00:00
parent 07e93ce041
commit f9638a05cf
4 changed files with 402 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
//! Which focus records have a VARYING alpha — disc-wide, not export-wide?
//!
//! `rest()` returns an element's last hold keyframe. For a constant-alpha
//! element that is harmless. For one that pulses it returns the PEAK, which is
//! the `ui-settle-time.md` pathology: the plate's `ptbtn00f` ramps 0→80→0 and
//! `rest()` reports 80, its maximum.
//!
//! The port censused this over its own export (34 records, 2 varying) and
//! concluded there is nothing to fix. That conclusion is only as wide as the
//! export. This asks the same question of the whole disc.
use sylpheed_formats::{pak, ratc, ui_layout};
fn main() {
let root = std::env::var("SYLPHEED_DISC").unwrap_or_else(|_| "/disc".into());
let mut paks: Vec<_> = std::fs::read_dir(format!("{root}/dat")).expect("dat/")
.flatten().map(|e| e.path())
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("pak")).collect();
paks.sort();
let (mut n_rec, mut n_elem, mut varying) = (0usize, 0usize, 0usize);
let (mut at_peak, mut mid_ramp) = (0usize, 0usize);
let mut by_pak: std::collections::BTreeMap<String, usize> = Default::default();
let mut hits: Vec<String> = Vec::new();
for p in &paks {
let pn = p.file_name().unwrap().to_string_lossy().to_string();
let Ok(ar) = pak::PakArchive::open(p) else { continue };
for (ei, e) in ar.entries().iter().enumerate() {
let Ok(by) = ar.read(e) else { continue };
if !ratc::is_ratc(&by) { continue }
let Some(b) = ui_layout::parse_build(&by) else { continue };
for (rn, &(o, s)) in &b.records {
// A focus record is one whose name is another record's plus `f`.
let Some(stem) = rn.strip_suffix("f.rat") else { continue };
if !b.records.contains_key(&format!("{stem}.rat")) { continue }
if o + s > by.len() { continue }
let Some(lb) = ui_layout::parse_build(&by[o..o + s]) else { continue };
n_rec += 1;
for el in &lb.elements {
if el.keyframes.is_empty() { continue }
n_elem += 1;
let a: Vec<u32> = el.keyframes.iter().map(|k| k.fade >> 24).collect();
let (lo, hi) = (*a.iter().min().unwrap(), *a.iter().max().unwrap());
if lo == hi { continue }
varying += 1;
let rest = el.rest().map(|k| k.fade >> 24).unwrap_or(0);
if rest == hi { at_peak += 1 } else { mid_ramp += 1 }
*by_pak.entry(pn.clone()).or_default() += 1;
hits.push(format!(
"{pn} [{ei}] {rn}::{} alpha {lo}..{hi} rest()={rest}{}",
el.name, if rest == hi { " 🔴 == PEAK" } else { "" }));
}
}
}
}
println!("focus records disc-wide : {n_rec}");
println!(" their timed elements : {n_elem}");
println!(" with a VARYING alpha : {varying}");
println!(" of which rest() == the PEAK : {at_peak} <- burns bright forever");
println!(" of which rest() is MID-RAMP : {mid_ramp} <- neither extreme; looks plausible");
println!("\nby pak:");
for (k, v) in &by_pak { println!(" {k:<34} {v}") }
println!("\nevery varying one:");
hits.sort(); hits.dedup();
for h in &hits { println!(" {h}") }
println!("\n({} distinct)", hits.len());
}

View File

@@ -170,3 +170,4 @@ files, which is how the same ground got covered twice.
| [`structures/ui-settle-time.md`](structures/ui-settle-time.md) | Which instant a "settled screen" composite depicts | ✅ **decoded**: a settled screen is **one instant every element is posed at**, and the disc names it — the midpoint of the **longest keyframe-free interval** in the build (`UiBuild::settle_time` / `settle_window`). 🔴 `rest()` is *not* that: it picks each element's last hold **independently**, so a two-frame flash holds at its **peak** and burns forever. `GP_TITLE` build 4 has five staggered flashes (`ptlogo_back2eff1``eff5`, all extinguished by t110) that `rest()` draws simultaneously and permanently, saturating the light arc. Predicted t=198 from `[160,236]` **before scoring**: arc band **33.22 → 11.79**, clipped pixels **8 581 → 1 452** against the console's **1 459** (an unfitted statistic), whole frame 14.07 → 12.06; controls at t=100 and t=358 are far worse, and a hand-picked visibility list reaches the identical 12.06/11.79/1 452. Controls: `at=None` byte-identical (`cmp`), pre- and post-rotation tags both 14.07, 13 paint-order tests green. ⚠️ **Reach**: of 1 758 bundles with ≥2 keyframe times only **30 %** have a window ≥ 30 units and **42 %** under 10 — mostly `loop*` fragments that never settle; check the width. 🔴 Withdraws two claims in [`ui-rotation-implemented.md`](structures/ui-rotation-implemented.md) — its "Flat. No minimum." (`at` posed **leaves only**) and its "Reborn does not draw `ptlogo1`/`ptlogo2`" (both **are** drawn; only kind-`0x4` ghosts are skipped, and hiding the real ones makes the error *worse* by +5.20/+7.47). ❔ its **10.92** baseline is unreproducible — 14.07 at both tags |
| [`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 t17t33. ✅ 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.122.34 s, 105 units needs a factor of **1.2111.337** (🔴 excludes the ring's) while 120 needs **1.0601.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 244269) 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 |

View File

@@ -0,0 +1,226 @@
focus records disc-wide : 1130
their timed elements : 2664
with a VARYING alpha : 210
of which rest() == the PEAK : 202 <- burns bright forever
of which rest() is MID-RAMP : 8 <- neither extreme; looks plausible
by pak:
GP_DEBRIEFING_PILOTLOG.pak 116
GP_HANGAR_ARSENAL.pak 30
GP_LEADERBOARD.pak 8
GP_MOVIE_THEATER.pak 54
GP_TITLE.pak 2
every varying one:
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn01f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn02f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn03f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn04f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn05f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn06f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn07f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn08f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn09f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn10f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn11f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn12f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn13f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn14f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn15f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn16f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn17f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn18f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn19f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn20f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn21f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn22f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn23f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [10] pp_order_btn24f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn01f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn02f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn03f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn04f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn05f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn06f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn07f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn08f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn09f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn10f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn11f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn12f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn13f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn14f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn15f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn16f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn17f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn18f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn19f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn20f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn21f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn22f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn23f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [11] pp_order_btn24f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [136] pl_main_btn0f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [136] pl_main_btn1f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [136] pl_main_btn2f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [136] pl_main_btn3f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [166] pl_main_btn0f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [166] pl_main_btn1f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [166] pl_main_btn2f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [166] pl_main_btn3f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [22] pl_main_btn0f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [22] pl_main_btn1f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [22] pl_main_btn2f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [22] pl_main_btn3f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [24] pl_main_btn0f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [24] pl_main_btn1f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn01f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn02f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn03f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn04f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn05f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn06f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn07f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn08f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn09f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn10f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn11f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn12f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn13f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn14f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn15f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn16f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn17f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn18f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn19f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn20f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn21f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn22f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn23f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [3] pp_order_btn24f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [43] pl_main_btn0f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [43] pl_main_btn1f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [43] pl_main_btn2f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [43] pl_main_btn3f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [53] pl_main_btn0f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [53] pl_main_btn1f.rat::pl_main_eff06.t32 alpha 0..128 rest()=128 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn01f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn02f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn03f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn04f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn05f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn06f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn07f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn08f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn09f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn10f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn11f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn12f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn13f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn14f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn15f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn16f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn17f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn18f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn19f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn20f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn21f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn22f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn23f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_DEBRIEFING_PILOTLOG.pak [5] pp_order_btn24f.rat::pp_order_btn_f.t32 alpha 0..212 rest()=212 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [129] psbtn2f.rat::pspylon_nose.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [129] psbtn3f.rat::pspylon_main2.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [129] psbtn4f.rat::pspylon_main3.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [129] psbtn5f.rat::pspylon_main1.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [167] psbtn2f.rat::pspylon_nose.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [167] psbtn3f.rat::pspylon_main2.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [167] psbtn4f.rat::pspylon_main3.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [167] psbtn5f.rat::pspylon_main1.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [239] psbtn2f.rat::pspylon_nose.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [239] psbtn3f.rat::pspylon_main2.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [239] psbtn4f.rat::pspylon_main3.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [239] psbtn5f.rat::pspylon_main1.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [24] psselect_slotf.rat::psselect_slotf_eff1.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [253] psbtn2f.rat::pspylon_nose.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [253] psbtn3f.rat::pspylon_main2.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [253] psbtn4f.rat::pspylon_main3.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [253] psbtn5f.rat::pspylon_main1.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [31] psselect_slotf.rat::psselect_slotf_eff1.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [42] psselect_slotf.rat::psselect_slotf_eff1.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [43] psselect_slotf.rat::psselect_slotf_eff1.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [455] psbtn2f.rat::pspylon_nose.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [455] psbtn3f.rat::pspylon_main2.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [455] psbtn4f.rat::pspylon_main3.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [455] psbtn5f.rat::pspylon_main1.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [458] psbtn2f.rat::pspylon_nose.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [458] psbtn3f.rat::pspylon_main2.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [458] psbtn4f.rat::pspylon_main3.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [458] psbtn5f.rat::pspylon_main1.t32 alpha 64..192 rest()=192 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [60] psselect_slotf.rat::psselect_slotf_eff1.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_HANGAR_ARSENAL.pak [61] psselect_slotf.rat::psselect_slotf_eff1.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_LEADERBOARD.pak [11] py_ranking_btn01f.rat::py_ranking_btn01f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [11] py_ranking_btn02f.rat::py_ranking_btn02f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [11] py_ranking_btn03f.rat::py_ranking_btn03f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [11] py_ranking_btn04f.rat::py_ranking_btn04f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [6] py_ranking_btn01f.rat::py_ranking_btn01f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [6] py_ranking_btn02f.rat::py_ranking_btn02f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [6] py_ranking_btn03f.rat::py_ranking_btn03f.t32 alpha 127..255 rest()=244
GP_LEADERBOARD.pak [6] py_ranking_btn04f.rat::py_ranking_btn04f.t32 alpha 127..255 rest()=244
GP_MOVIE_THEATER.pak [10] px_movie_tn030f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [11] px_movie_tn130f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [12] px_movie_tn040f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [13] px_movie_tn022f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [14] px_movie_tn121f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [15] px_movie_tn131f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [16] px_movie_tn041f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [17] px_movie_tn140f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [18] px_movie_tn050f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [19] px_movie_tn122f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [20] px_movie_tn150f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [21] px_movie_tn060f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [22] px_movie_tn151f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [23] px_movie_tn061f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [24] px_movie_tn160f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [25] px_movie_tn070f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [26] px_movie_tn152f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [27] px_movie_tn071f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [28] px_movie_tn090f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [29] px_movie_tn000f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [2] px_movie_tn000f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [30] px_movie_tn100f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [31] px_movie_tn010f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [32] px_movie_tn110f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [33] px_movie_tn020f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [34] px_movie_tn111f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [35] px_movie_tn021f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [36] px_movie_tn120f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [37] px_movie_tn030f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [38] px_movie_tn130f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [39] px_movie_tn040f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [3] px_movie_tn100f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [40] px_movie_tn022f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [41] px_movie_tn121f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [42] px_movie_tn131f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [43] px_movie_tn041f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [44] px_movie_tn140f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [45] px_movie_tn050f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [46] px_movie_tn122f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [47] px_movie_tn150f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [48] px_movie_tn060f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [49] px_movie_tn151f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [4] px_movie_tn010f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [50] px_movie_tn061f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [51] px_movie_tn160f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [52] px_movie_tn070f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [53] px_movie_tn152f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [54] px_movie_tn071f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [55] px_movie_tn090f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [5] px_movie_tn110f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [6] px_movie_tn020f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [7] px_movie_tn111f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [8] px_movie_tn021f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_MOVIE_THEATER.pak [9] px_movie_tn120f.rat::px_movie_btnf.t32 alpha 64..255 rest()=255 🔴 == PEAK
GP_TITLE.pak [2] ptbtn00f.rat::ptbtn00f.t32 alpha 0..80 rest()=80 🔴 == PEAK
GP_TITLE.pak [3] ptbtn00f.rat::ptbtn00f.t32 alpha 0..80 rest()=80 🔴 == PEAK
(210 distinct)

View File

@@ -0,0 +1,110 @@
# Every focus record that pulses — and why `rest()` is wrong for 210 of them
**Classification: decoded.** A census of the whole disc, with a control on a
record the census does *not* flag, and two hits verified keyframe by keyframe.
## Why this exists
The `PRESS Ⓐ` plate's focus record `ptbtn00f` pulses 0 → 80 → 0, so its last hold
keyframe is the **peak**, and `rest()` leaves it at maximum brightness forever —
the pathology of [`ui-settle-time.md`](ui-settle-time.md) applied to a focus glow.
The port checked this over its own export and found **34 focus-record elements, 2
of them varying** — both `ptbtn00f`, EN and JP — and concluded there is nothing to
fix. **That is correct, and correctly scoped.** For the five screens the menu port
ships it is the whole story.
It does not survive leaving `GP_TITLE`.
## Disc-wide
[`focus-record-alpha-census.txt`](../data/focus-record-alpha-census.txt)
| | count |
|---|---|
| focus records (`Xf.rat` where `X.rat` also exists) | **1 130** |
| their elements carrying timed keyframes | **2 664** |
| **with a varying alpha** | **210** |
| …of which `rest()` returns the **peak** | **202** |
| …of which `rest()` lands **mid-ramp** | **8** |
| pak | varying focus elements |
|---|---|
| `GP_DEBRIEFING_PILOTLOG` | 116 |
| `GP_MOVIE_THEATER` | 54 |
| `GP_HANGAR_ARSENAL` | 30 |
| `GP_LEADERBOARD` | 8 |
| `GP_TITLE` | **2** |
So the port's 2 is right — and it is 2 because `GP_TITLE` has 2. The pathology is
concentrated in exactly the screens a wider port needs next.
## The three behaviours, verified by hand
**1. A seamless breathing loop**`GP_MOVIE_THEATER` `px_movie_tn000f`:
```
t=0 a=64 t=4 a=80 t=26 a=238 t=30 a=255
t=60 a=255 t=70 a=236 t=110 a=80 t=120 a=64 cycle +08 = 120
```
Starts and ends at 64 and fills its declared cycle exactly, so it loops with no
seam. `rest()` returns **255** — the peak. 54 elements in this pak do this.
**2. A ramp that holds**`GP_LEADERBOARD` `py_ranking_btn01f`:
```
t=0 a=255 t=8 a=244 t=42 a=140 t=50 a=127
t=56 a=140 t=84 a=244 t=90 a=255 cycle +08 = 120
```
The ramp ends at t=90 inside a 120-unit cycle, so it holds bright for 30 units —
another instance of [`ui-record-loop-length.md`](ui-record-loop-length.md). Here
`rest()` returns **244**, which is **neither the peak (255) nor the trough (127)**.
No two adjacent keyframes are equal, so `rest()` falls through to its longest-dwell
rule and lands mid-ramp.
🔴 **This is the worse failure mode.** A glow stuck at its peak is at least
visibly wrong. A glow stuck at 244 of a 127255 range looks entirely plausible and
nothing reports it.
**3. The control — genuinely constant**`GP_TITLE` `ptbtn01f`, one of the five
main-menu focus records:
```
ptbtneff01.t32 t=0 a=255 t=120 a=255
ptbtn01f.t32 t=0 a=255
```
Constant across its whole cycle. The census does **not** flag it, which is the
check that the census is detecting variation rather than flagging every focus
record it meets.
## What this does and does not change
***Nothing about the menu port.** `GP_TITLE`'s two are the plate's, the port
draws the plate through its loop path, and the other 32 elements in its export
are constant-alpha. Its conclusion stands for its scope.
* 🔴 **The scope is load-bearing and was not stated as a limit.** "Only 2 have a
varying alpha" reads as a fact about the format; it is a fact about `GP_TITLE`.
Extending the port to the Hangar, the Movie Theater or the Pilot Log meets 200
of these, and 8 of them fail in a way that looks correct.
* ⚠️ **A pulsing element has no resting pose at all.** For these records the
question `rest()` answers is malformed rather than mis-answered: the element's
state is a phase, not a value. `pose_at(t)` with `t` inside the record's own
declared cycle is the only well-formed query.
## Reach
⚠️ **"Focus record" here is a name rule** — `Xf.rat` where `X.rat` is also
present, the same pairing `mark_focused_states` uses. A record that animates while
focused but is not named that way is not counted, so 210 is a floor.
⚠️ **Varying alpha only.** An element with constant alpha and a varying scale,
rotation or position has the same problem and is not counted here.
## Reproducing
```bash
cargo run -p sylpheed-formats --example focus_alpha_census
```