Files
Sylpheed/crates/sylpheed-formats/examples/black_backdrop_predicate.rs
sylph-decoder 82b20bc51d re: test the port's black-backdrop predicate disc-wide -- exact locally, rare globally
sylpheed-port proposed that a screen declaring a full-screen .prm at t=0 with
fade == 0xff000000 is standalone, and one without it is composited: 12/4 across
their sixteen exported screens, every exception independently known to be
composited. They asked for it against archives they do not have. That is my lane.

CONTROL: the predicate reproduces their split exactly. GP_TITLE's sixteen bundles
give 12 with and 4 without, the four without being entries 0, 1, 2, 3 --
build_00, build_01, press_start, press_start_jp -- and the element names match
(pteff00.prm, palogo_eff0.prm, pgloading_eff00.prm). Independent derivation from
the disc, not a re-run of their tool.

DISC-WIDE it is rare: 76 of 965 screen builds, 7.9 %. GP_STAGE_CLEAR 4/4,
GP_SYSTEM 2/2 and GP_TUTORIAL 2/2 are all-yes; GP_HANGAR_ARSENAL is 0 of 390, and
GP_READY_ROOM, GP_OPTIONS, GP_PAUSE_MENU and GP_GAMEOVER are all zero.

So it is not a general standalone/composited test. GP_OPTIONS and GP_PAUSE_MENU
are screens a player plainly sees as screens and declare no backdrop; read as
"composited" the rule would make 92 % of the game's screens composited, which the
archives do not support. What it appears to separate is narrower: screens that
BEGIN FROM BLACK from everything else. A pause menu over gameplay, a hangar over a
3D scene and a plate over a title all lack a backdrop without being the same kind
of thing -- the negative class is heterogeneous, which is what a two-way rule
cannot express.

For the port: exact within GP_TITLE, so --black for those twelve is justified from
the file rather than assumed; do not carry it into the four archives they have yet
to export, where in three of them it classifies every screen alike.

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

79 lines
3.5 KiB
Rust

//! Does a screen declare its own OPAQUE BLACK backdrop? Disc-wide.
//!
//! `sylpheed-port` observed that the splash builds declare `palogo_eff0.prm` as a
//! full-screen primitive at t=0 with `fade_argb 0xff000000` -- alpha 255 over RGB
//! 000000 -- and turned it into a candidate predicate: a declared opaque-black
//! backdrop separates STANDALONE screens from COMPOSITED ones. On their sixteen
//! exported screens it splits 12 / 4, with all four exceptions independently known
//! to be composited (the two `press_start` plates, and two loading builds that
//! carry the `pgloading_*` set without its backdrop).
//!
//! That matters because the corpus previously told them "no content rule exists,
//! take the entry index" -- correct for the question asked (recognise the splash),
//! but this is a content rule for a different and useful question. They asked for
//! it to be tested against an archive they do not have. This is that test.
//!
//! CONTROL: it must reproduce the 12/4 split on GP_TITLE's sixteen composable
//! bundles before its disc-wide numbers mean anything.
//!
//! cargo run -p sylpheed-formats --example black_backdrop_predicate
use sylpheed_formats::{pak::PakArchive, ui_layout};
use std::io::Write;
use std::path::PathBuf;
/// A screen declares its own backdrop if some `.prm` primitive holds
/// `fade == 0xff000000` at t = 0: full alpha over black.
fn has_black_backdrop(b: &ui_layout::UiBuild) -> Option<String> {
for el in &b.elements {
if !el.name.ends_with(".prm") { continue }
if let Some(k) = el.keyframes.iter().find(|k| k.time == Some(0)) {
if k.fade == 0xff00_0000 { return Some(el.name.clone()) }
}
}
None
}
fn main() {
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
println!("== CONTROL: GP_TITLE's 16 composable bundles (port reports 12 with, 4 without)");
let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE.pak");
let (mut y, mut n) = (0, 0);
for e in 0..16usize {
let Ok(by) = ar.read(&ar.entries()[e]) else { continue };
let Some(b) = ui_layout::parse_build(&by) else { continue };
match has_black_backdrop(&b) {
Some(nm) => { y += 1; println!(" entry {e:>2} YES {nm}") }
None => { n += 1; println!(" entry {e:>2} no") }
}
}
println!(" -> {y} with, {n} without\n");
println!("== DISC-WIDE, over every screen build");
let mut paks: Vec<PathBuf> = std::fs::read_dir(root.join("dat")).expect("dat/")
.filter_map(|e| e.ok().map(|e| e.path()))
.filter(|p| p.extension().is_some_and(|x| x == "pak")).collect();
paks.sort();
let (mut tot, mut with) = (0usize, 0usize);
for pak in &paks {
let Ok(ar) = PakArchive::open(pak) else { continue };
let name = pak.file_name().unwrap().to_string_lossy().to_string();
let (mut t, mut w) = (0usize, 0usize);
for e in ar.entries() {
let Ok(by) = ar.read(e) else { continue };
if !ui_layout::is_build(&by) { continue }
let Some(b) = ui_layout::parse_build(&by) else { continue };
t += 1;
if has_black_backdrop(&b).is_some() { w += 1 }
}
if t > 0 {
println!("{name:30} {w:4} / {t:<4} declare a black backdrop");
std::io::stdout().flush().ok();
}
tot += t; with += w;
}
println!("\n{with} of {tot} screen builds disc-wide declare an opaque-black backdrop \
({:.1} %)", 100.0 * with as f64 / tot as f64);
println!("--- END ---");
}