re: F6 unit 10 -- the parent's declared alpha gates the sweep, and it multiplies
Build 4 declares ptloop01/02 alpha 0 until t=70, full at t=100, with 238..250 an EXIT ramp -- which answers the brief's "is 238..250 an entry or an exit" for these elements. Builds 5/6 declare the same records flat 255, so the build must be named before the question has an answer. Control ran in the direction that could have flattered the hypothesis and did not: the leaf's own alpha FALLS 255->128 where the capture RISES 8->255. Decomposing against the leaf's declared curve leaves an implied parent that pins at 255.0 +/-1.5 across hundreds of frames while the drawn alpha swings 242->132->145. Parent alpha is multiplied in; closes that standing 🟡. Restores unit 8's 0.514: leaf/title = 0.4795 and 0.4667 across two runs that differ 2x in frames. I over-withdrew it last iteration by discarding the ratio along with the frames it had been quoted in. Adds examples/ptloop_parent_keyframes.rs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
This commit is contained in:
32
crates/sylpheed-formats/examples/ptloop_parent_keyframes.rs
Normal file
32
crates/sylpheed-formats/examples/ptloop_parent_keyframes.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
//! The PARENT elements that host the sweep leaves — `ptloop01`/`ptloop02` as
|
||||
//! they are declared in the title build itself, not in their nested records.
|
||||
//!
|
||||
//! The leaves' own alpha is non-zero at their t=0 (`pteff03` declares 255), yet
|
||||
//! the capture shows the sweep fading in from ~8. So the gate is the parent's
|
||||
//! alpha, and this prints it.
|
||||
//!
|
||||
//! cargo run -p sylpheed-formats --example ptloop_parent_keyframes -- GP_TITLE 5
|
||||
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 argv: Vec<String> = std::env::args().skip(1).collect();
|
||||
let pak = argv.iter().find(|a| a.parse::<usize>().is_err())
|
||||
.cloned().unwrap_or_else(|| "GP_TITLE".to_string());
|
||||
let ar = PakArchive::open(root.join(format!("dat/{pak}.pak"))).expect("pak");
|
||||
let builds: Vec<usize> = argv.iter().filter_map(|a| a.parse().ok()).collect();
|
||||
for e in if builds.is_empty() { vec![5usize] } else { builds } {
|
||||
let Ok(by) = ar.read(&ar.entries()[e]) else { continue };
|
||||
let Some(b) = ui_layout::parse_build(&by) else { continue };
|
||||
println!("=== {pak} entry {e}: {} elements ===", b.elements.len());
|
||||
for el in &b.elements {
|
||||
for (i, k) in el.keyframes.iter().enumerate() {
|
||||
println!(" {:<20} kf{i:<2} t={:<5} x={:<6} y={:<6} sx={:<4} sy={:<4} fade={:08X} (alpha {:3})",
|
||||
el.name,
|
||||
k.time.map(|t| t.to_string()).unwrap_or_else(|| "-".into()),
|
||||
k.x, k.y, k.scale_x, k.scale_y, k.fade, k.fade >> 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
docs/re/f6-unit10-parent-alpha-gates-the-sweep.md
Normal file
80
docs/re/f6-unit10-parent-alpha-gates-the-sweep.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# F6 unit 10 — what makes the sweep start, and when
|
||||
|
||||
**Question:** why is the sweep hidden for the first part of the title, and what
|
||||
turns it on?
|
||||
|
||||
**What the human looks at:** the sweep should be absent at the very start, fade
|
||||
up once the title art is established, and then keep looping. Pass = it fades in
|
||||
partway through the build-in. Fail = present from frame one, or popping in.
|
||||
|
||||
**What this does NOT cover:** F5, the plate's identity, and the loop period.
|
||||
|
||||
**Instruments:** ⟨disc⟩ for the declarations, ⟨capture⟩ for the two runs.
|
||||
|
||||
## ✅ Decoded — the gate is the PARENT's alpha, and it is declared
|
||||
|
||||
`GP_TITLE` **build 4** (and 7) declare both hosts with a five-key ramp:
|
||||
|
||||
```
|
||||
ptloop01.rat / ptloop02.rat t=0 α0 · t=70 α0 · t=100 α255 · t=238 α255 · t=250 α0
|
||||
```
|
||||
|
||||
**Alpha 0 until `t=70`, up to full by `t=100`, and `238…250` is an EXIT ramp.**
|
||||
That answers the brief's open question directly: for *these* elements 238…250
|
||||
starts nothing, it ends them.
|
||||
|
||||
⚠️ **Build matters.** Builds **5 and 6** declare the same two records as a single
|
||||
keyframe at flat α255 — no ramp at all. So "what does `ptloop01` do" has no
|
||||
answer until the build is named, and the one the human is watching is 4/7.
|
||||
|
||||
## ✅ Measured — the parent's alpha is multiplied into the leaf's
|
||||
|
||||
The leaf `pteff03` declares α **255 falling to 128** across its own `t=0…150`.
|
||||
The capture shows the sweep **rising 8→255** in that same window, so the leaf
|
||||
alone predicts the wrong direction — the control could have flattered the
|
||||
hypothesis and did not.
|
||||
|
||||
Decomposing `observed = parent × leaf / 255` using the leaf's declared curve, the
|
||||
implied parent **ramps up and then pins at 255.0 and holds**: 254.0–256.9 (f6)
|
||||
and 253.9–254.9 (f6b) across hundreds of frames, while the observed alpha swings
|
||||
242 → 132 → 145. Over that whole swing the leaf's declared curve predicts the
|
||||
drawn alpha **to within one alpha level**.
|
||||
|
||||
A flat 255.0 residual across a large excursion is the part that could have
|
||||
failed. It settles the standing 🟡 on whether parent alpha is multiplied in:
|
||||
**it is.**
|
||||
|
||||
## ✅ Leaf runs at half the title's clock — and this restores a number I withdrew
|
||||
|
||||
Using the parent's declared 30-unit ramp (`t=70…100`) as an in-capture title
|
||||
clock, and the leaf's declared 600-unit loop as the leaf clock:
|
||||
|
||||
| | title clock | leaf clock | **leaf / title** |
|
||||
|---|---|---|---|
|
||||
| f6 | 1.0714 u/fr | 0.5137 u/fr | **0.4795** |
|
||||
| f6b | 2.1429 u/fr | 1.0000 u/fr | **0.4667** |
|
||||
|
||||
2.7% apart, ≈ **½**. The two runs differ 2× in frames and agree on the ratio.
|
||||
|
||||
🔴 **I over-withdrew unit 8's 0.514 last iteration.** Frames-based rates were the
|
||||
thing that failed, and I threw the ratio out with them. **The ratio was right:**
|
||||
`leaf ≈ 0.5 × title` now has two independent runs and a declared calibration
|
||||
behind it. The port should reinstate it, not drop it.
|
||||
|
||||
## What this says about F6
|
||||
|
||||
The sweep is switched on by its parent at **`t=70`**, full at **`t=100`** — not at
|
||||
`t=0`, and not by anything to do with the plate. It never plays its `238…250`
|
||||
exit because the title clock freezes inside `[160,236]`
|
||||
([`ui-clock-freezes-at-settle.md`](structures/ui-clock-freezes-at-settle.md)),
|
||||
which is why it loops indefinitely on a held title.
|
||||
|
||||
## Not settled
|
||||
|
||||
* 🟡 **The element I have been calling "the plate" is unidentified** — it is
|
||||
tracked by screen position only. The declared plate is at `t≈236`; in-capture it
|
||||
lands at `t≈137` on this title clock. Until it is named, that 1.7× stays
|
||||
unexplained and no plate-relative number should be trusted. Unit 9's onset
|
||||
*fraction* is measured against it, so it inherits this.
|
||||
* `pteff03a` (`ptloop02`'s leaf) is still absent from every capture.
|
||||
* Wrap-to-wrap period; F5, untouched.
|
||||
Reference in New Issue
Block a user