Files
Sylpheed/crates/sylpheed-formats/examples/palogo_eff_check.rs
sylph-decoder ad9cd948c6 re: the port's two extra elements are PLATEAU cases -- refutation succeeds, and its point gets bigger
The port listed palogo_gamearts_eff and palogo_seta_eff among GP_TITLE's four
visible dwell-fallback fires; this census listed only palogo_sqex_eff and
palogo_anima_eff. Checked, and the census is right: gamearts_eff and seta_eff
hold a=255 at identical x, y and scale from t=15 to t=30, which is a plateau at
pair index 1, so rest_plateau() handles them and t=15 is the CORRECT answer. They
are not fallback cases.

The distinction is not cosmetic -- a plateau is a pose the element genuinely
holds, and only the dwell fallback is the unsound path.

But the refutation makes the port's underlying point STRONGER. Its rest pose for
those two really is the flash's peak, reached by the SOUND path. So 'a rest
render is not a frame to score against a capture' does not follow from the
fallback being unsound: a plateau can itself be the held peak of a transient. The
rule covers both paths, and the fallback census understates the exposure rather
than bounding it.

Also records the port's oracle number for the rule -- publisher splash against
the committed capture, timeline RMSE 2.17 / 0.01 % differing against --pose=rest
9.05 / 0.75 %, 75x the differing area.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 11:54:43 +00:00

41 lines
2.2 KiB
Rust

//! Are `palogo_gamearts_eff` / `palogo_seta_eff` dwell-FALLBACK cases, or PLATEAU
//! cases? The port agent lists them among `GP_TITLE`'s four visible fallback
//! fires; this census listed only `palogo_sqex_eff` and `palogo_anima_eff`.
//!
//! It matters because the two are different defects. A plateau is a pose the
//! element genuinely HOLDS, and `rest_plateau()` returning it is correct. Only the
//! fallback is the unsound path.
//! cargo run -p sylpheed-formats --example palogo_eff_check
use sylpheed_formats::{pak::PakArchive, ui_layout};
use std::path::PathBuf;
fn main() {
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE");
for (i, e) in ar.entries().iter().enumerate() {
let Ok(by) = ar.read(e) else { continue };
let Some(b) = ui_layout::parse_build(&by) else { continue };
for el in &b.elements {
if !el.name.starts_with("palogo") || !el.name.contains("eff") { continue }
// A single-keyframe element has no gap to maximise, so neither path
// applies and `rest()` trivially returns the only pose. Excluding it
// here matches the census, which filters `len < 2`.
if el.keyframes.len() < 2 { continue }
let plateau = el.keyframes.windows(2).position(|w| {
w[0].x == w[1].x && w[0].y == w[1].y && w[0].scale_x == w[1].scale_x
&& w[0].scale_y == w[1].scale_y && w[0].fade == w[1].fade
});
let ks: Vec<String> = el.keyframes.iter().map(|k| format!(
"{}:a{} {},{} {}%",
k.time.map(|v| v.to_string()).unwrap_or("-".into()),
(k.fade >> 24) & 0xff, k.x, k.y, k.scale_x)).collect();
let r = el.rest();
println!("e{i:<3} {:24} kf=[{}]", el.name, ks.join(" "));
println!(" plateau at pair {:?} -> path: {} rest a={} t={:?}",
plateau,
if plateau.is_some() { "PLATEAU (sound: the pose is held)" } else { "DWELL FALLBACK (unsound)" },
r.map(|k| (k.fade >> 24) & 0xff).unwrap_or(0),
r.and_then(|k| k.time));
}
}
}