From 82b20bc51d00f670499748a782bdd69374ffdf5f Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Sun, 30 Aug 2026 17:36:10 +0000 Subject: [PATCH] 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) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- .../examples/black_backdrop_predicate.rs | 78 +++++++++++++++++++ docs/re/data/black-backdrop-predicate.txt | 55 +++++++++++++ docs/re/structures/ui-forced-backdrop.md | 42 ++++++++++ 3 files changed, 175 insertions(+) create mode 100644 crates/sylpheed-formats/examples/black_backdrop_predicate.rs create mode 100644 docs/re/data/black-backdrop-predicate.txt diff --git a/crates/sylpheed-formats/examples/black_backdrop_predicate.rs b/crates/sylpheed-formats/examples/black_backdrop_predicate.rs new file mode 100644 index 00000000..f2813dbc --- /dev/null +++ b/crates/sylpheed-formats/examples/black_backdrop_predicate.rs @@ -0,0 +1,78 @@ +//! 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 { + 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 = 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 ---"); +} diff --git a/docs/re/data/black-backdrop-predicate.txt b/docs/re/data/black-backdrop-predicate.txt new file mode 100644 index 00000000..e825e352 --- /dev/null +++ b/docs/re/data/black-backdrop-predicate.txt @@ -0,0 +1,55 @@ +# Does a screen declare its own OPAQUE-BLACK backdrop? Disc-wide. 2026-08-30. +# instrument: crates/sylpheed-formats/examples/black_backdrop_predicate.rs +# predicate: some .prm element holds fade == 0xff000000 at t=0. +# +# sylpheed-port proposed this as a rule separating STANDALONE screens from +# COMPOSITED ones, split 12/4 across their sixteen exported screens, and asked +# for it to be tested against archives they do not have. +# +== CONTROL: GP_TITLE's 16 composable bundles (port reports 12 with, 4 without) + entry 0 no + entry 1 no + entry 2 no + entry 3 no + entry 4 YES pteff00.prm + entry 5 YES pteff00.prm + entry 6 YES pteff00.prm + entry 7 YES pteff00.prm + entry 8 YES pteff00.prm + entry 9 YES pteff00.prm + entry 10 YES palogo_eff0.prm + entry 11 YES palogo_eff0.prm + entry 12 YES pgloading_eff00.prm + entry 13 YES palogo_eff0.prm + entry 14 YES palogo_eff0.prm + entry 15 YES pgloading_eff00.prm + -> 12 with, 4 without + +== DISC-WIDE, over every screen build +GP_BUNK.pak 6 / 8 declare a black backdrop +GP_CHALLENGE.pak 6 / 78 declare a black backdrop +GP_DEBRIEFING_PILOTLOG.pak 0 / 18 declare a black backdrop +GP_DIALOG.pak 34 / 105 declare a black backdrop +GP_GAMEOVER.pak 0 / 10 declare a black backdrop +GP_HANGAR_ARSENAL.pak 0 / 390 declare a black backdrop +GP_LEADERBOARD.pak 0 / 4 declare a black backdrop +GP_MAIN_GAME_D2D.pak 0 / 18 declare a black backdrop +GP_MAIN_GAME_E2D.pak 0 / 18 declare a black backdrop +GP_MAIN_GAME_F2D.pak 0 / 18 declare a black backdrop +GP_MAIN_GAME_I2D.pak 0 / 18 declare a black backdrop +GP_MAIN_GAME_J2D.pak 0 / 18 declare a black backdrop +GP_MAIN_GAME_S2D.pak 0 / 18 declare a black backdrop +GP_MISSION_LOG.pak 0 / 4 declare a black backdrop +GP_MISSION_SELECT.pak 2 / 66 declare a black backdrop +GP_MOVIE_THEATER.pak 2 / 56 declare a black backdrop +GP_OPTIONS.pak 0 / 14 declare a black backdrop +GP_PAUSE_MENU.pak 0 / 6 declare a black backdrop +GP_READY_ROOM.pak 0 / 60 declare a black backdrop +GP_SAVE_LOAD.pak 10 / 18 declare a black backdrop +GP_STAGE_CLEAR.pak 4 / 4 declare a black backdrop +GP_SYSTEM.pak 2 / 2 declare a black backdrop +GP_TITLE.pak 8 / 12 declare a black backdrop +GP_TUTORIAL.pak 2 / 2 declare a black backdrop + +76 of 965 screen builds disc-wide declare an opaque-black backdrop (7.9 %) +--- END --- diff --git a/docs/re/structures/ui-forced-backdrop.md b/docs/re/structures/ui-forced-backdrop.md index 0934682c..063667b9 100644 --- a/docs/re/structures/ui-forced-backdrop.md +++ b/docs/re/structures/ui-forced-backdrop.md @@ -472,3 +472,45 @@ cargo run -p sylpheed-formats --example prm_forced_first cargo run -p sylpheed-formats --example prm_occlusion_check SYLPHEED_DISC=/disc cargo test -p sylpheed-formats --test ui_forced_backdrop_disc ``` + + +## ๐ŸŸก The opaque-black backdrop as a PREDICATE โ€” sound where it is used, not general + +`sylpheed-port` turned the splash's `palogo_eff0` into a candidate rule: *a screen +declaring a full-screen `.prm` at `t=0` with `fade == 0xff000000` is **standalone**; +one without it is **composited***. On their sixteen exported screens it splits 12/4 +with every exception independently known to be composited. They asked for it +against archives they do not have. Tested: +[`data/black-backdrop-predicate.txt`](../data/black-backdrop-predicate.txt). + +โœ… **The control reproduces their split exactly** โ€” `GP_TITLE`'s sixteen bundles +give 12 with and 4 without, and the four without are entries **0, 1, 2, 3**: +`build_00`, `build_01`, `press_start`, `press_start_jp`. Element names match too +(`pteff00.prm`, `palogo_eff0.prm`, `pgloading_eff00.prm`). + +๐Ÿ”ด **Disc-wide it is rare: 76 of 965 screen builds, 7.9 %.** + +| archive | with / total | +|---|---| +| `GP_STAGE_CLEAR`, `GP_SYSTEM`, `GP_TUTORIAL` | 4/4, 2/2, 2/2 โ€” **all** | +| `GP_SAVE_LOAD` | 10/18 | +| `GP_DIALOG` | 34/105 | +| `GP_HANGAR_ARSENAL` | **0 / 390** | +| `GP_READY_ROOM` | 0/60 ยท `GP_OPTIONS` 0/14 ยท `GP_PAUSE_MENU` 0/6 ยท `GP_GAMEOVER` 0/10 | + +โš ๏ธ **So it is not a general standalone/composited test.** `GP_OPTIONS` and +`GP_PAUSE_MENU` are screens a player plainly sees as screens, and they declare no +backdrop; `GP_HANGAR_ARSENAL` declares none across **390** builds. Read as +"composited", that would make 92 % of the game's screens composited, which the +archives do not support. + +๐ŸŸก **What it does appear to separate is narrower and still useful: 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 legitimately lack a black backdrop, but +they are not the same kind of thing โ€” the negative class is **heterogeneous**, and +that is exactly what a two-way rule cannot express. + +๐Ÿ“Œ **For the port: keep using it where you found it.** Within `GP_TITLE` it is +exact, and `--black` for those twelve is justified from the file rather than +assumed. Do **not** carry it into the four archives you have yet to export โ€” in +three of them it would classify every screen the same way.