Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit cd3b127f7411811d5d559e5af12a35d1ae3f4809
parent ab896086dcd349edcd13f4b1b4d8db304408ffce
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  1 Oct 2026 14:35:48 -0400

plans: finale B2 as built — the review fixes, muteFrom, render.endFade, the fitted QR host label, the gates

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Mplans/deck-posts.md | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+), 0 deletions(-)

diff --git a/plans/deck-posts.md b/plans/deck-posts.md @@ -205,3 +205,67 @@ Left for R2 (umtool): for a cut that was never fully built. - The preview's posts geometry is now the frame's edge (`postsGeometry`). The preview does not show the footage move or the hold; both happen in ffmpeg, at the join. + +Both items above were done after R1: R2 (b584c129) shows the move and the hold in the preview, and +df062b37 reads a deck cut's offsets from its `schedule.json` when there is no `chapters.ffmeta`. + +## Finale B2, as built + +Branch `deck/finale-b2` from df062b37. It starts with the fixes from the read-only review of the +room work (SHIP AFTER FIXES). + +| Commit | What | +|---|---| +| 2f0e852b | Review fixes. The footage move now runs AFTER the hold, so a first post inside the hold still moves the frozen frame (before, it never moved or froze part-way). verify-build's freeze check samples only between the hold's start (or the move's landing) and the dissolve, and reports under three frames of still picture as not checked. `postHolds` rounds a hold to whole frames. The README and changelog say `--no-chrome` still holds and moves. | +| 2ea53246 | A clip's `muteFrom` and `render.endFade`, joined on that input's chain; the `<id>.cut.json` record beside each clip segment; validation; the QR host label fitted to the code's height | +| ebe10c84 | README, quirks, one `[Unreleased]` bullet | + +Where it adds to the rulings above: + +- **`muteFrom`** is in SOURCE seconds and must lie within the clip's `start`–`end`. The sound is + silent from that second, after a 40 ms `afade` that ENDS there, and it is digital zeros after + that. A hold on the clip stays silent. The mute is mapped to the segment's clock through + `<id>.cut.json`, which every clip build now writes: the source seconds the segment was really + cut from after snapping. A segment with no record, or one whose record does not match its + length, falls back to the unsnapped `playWindow` start, and the build says so in a note. +- **`render.endFade`** applies to the cut's last segment, whatever it is, hold included. The + picture reaches `palette.bg` and the sound reaches silence on the last frame. The picture fade + is a `geq` blend in yuv420p, enabled from its first frame. `fade=…:color=` would work too, but + only in RGB, and the concat filter would then convert every segment of the cut to rgb24 and back. +- Both are joins (`withCutEdits`, `cutJoins`), so they apply with or without the deck, on + crossfades and hard cuts, and `--chrome-only` changes them without rebuilding a segment. The + hard-cut record names them only when present. `validateCutEdits` (in `deck.mjs`) is what the + build refuses with, and `validateChrome` also checks `endFade`. +- **The QR's host label** is sized at load from the string's ink in the loaded face (canvas + `measureText`). Tracking counts between letters only, and the first side bearing is indented + away. On the ferret cut its ink covers rows 31–180, the same rows as the code. Before, it + covered 54–180. + +Gates on ebe10c84: + +- Workspace tsc clean. `test:scripts` 341 pass, 2 skipped. Capped umtool `next build` with the + corpus linked exit 0 (31 s), link removed. +- Byte-identical: `--only c07 --skip-fetch` without `render.chrome` gives md5 + `6a92235fa12ca181bb81993129c9ee9d`. The unchanged ferret deck manifest writes a `schedule.json` + byte-equal at df062b37 and at the tip. With no muteFrom or endFade, the crossfade graph, the + hard-cut graph and the record equal 2f0e852b's. Against df062b37 the only difference is the + move and hold order on the four carrying clips. +- Ferret, scratch copy with c20 `muteFrom: 24029.30` and `endFade: 1.0`, `--chrome-only` over + copied segments with no cut records: + - c20 muted 6.70 s into its segment, falling back to the unsnapped start, which the run notes; + - 360.2 s, verify-build ok, all four freezes found; + - QR 17/17 deck and 7/7 posts; + - the last sample that is not zero is at 359.613 s of the audio, and everything after it is + digital silence; + - the last frame above the deck is bg (mean 1.0, worst 3 levels over rows 0–881). + +Found and left: + +- **The crossfade concat drifts the sound ahead of the picture, before this branch too.** + Crossfaded segments have audio up to 40 ms shorter than their video (AAC framing), and + `acrossfade` joins the sound by its own lengths while `xfade` uses the picture's. The ferret + cut's audio is 359.901 s against 360.200 s of picture, as in the build made before this branch, so by the last + clip the sound runs 0.3 s early. A `muteFrom` silences the right sound in the clip's own audio, + but in the final it falls up to that drift before the matching picture. Padding each input's + sound to its picture's length (`apad=whole_dur`) before the join would fix it, but that changes + every crossfaded cut's graph.