Archilyzer · Source

archilyzer

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

commit 061d4aa48ec9a6d7f27079b3f4beb627e42abf43
parent c83389e06967a52149a336d97bd784f72c32bd87
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  8 Oct 2026 23:19:05 -0400

report-to-video README: the thread rail, the flips panel, panning screenshots, a source line that keeps its date

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

Diffstat:
Mumtool/report-to-video/README.md | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 63 insertions(+), 3 deletions(-)

diff --git a/umtool/report-to-video/README.md b/umtool/report-to-video/README.md @@ -411,7 +411,9 @@ characters, trimmed; an empty value deletes the key, the way the attribution fields do. Without it the deck's title is empty (a card falls back to `heading`) and the subtitle is auto-built: a clip's channel · title · date (the channel only when the cut spans more than one), an image's `title · date`, a -card's `sub`. The QR follows a clip's corner-QR rule unchanged (`citeUrl`, else +card's `sub`. A line too long for its column gives way in its middle parts +(the title ends in "…"): its first part and its last (the date) always show +whole. The QR follows a clip's corner-QR rule unchanged (`citeUrl`, else the site link at the clip's start); an image draws one only with an explicit `citeUrl`; a card never does. @@ -481,8 +483,10 @@ footage, so it rides on a clip. its day), `@handle · Bluesky` (or X), the words — paragraphs kept, clamped to `maxLines` with an ellipsis — and a QR of the post's page on the archive (below), or of its own `url`. A post with a `shot` draws the screenshot in - place of the words, as wide as the card's text and no taller than a full card - of words, or than `shotMaxHeight` px when that is set. + place of the words, always as wide as the card's text (so it reads), in a + viewport no taller than a full card of words, or than `shotMaxHeight` px when + that is set; a taller screenshot holds on its top for 1.2 s once the card has + landed, pans to its bottom, and holds there 1.2 s before the card leaves. - **Marks.** A post's own `accent`, `logo` and `flag` set one kind of card apart from another at a glance — a source document's sentence beside a platform post, say: the rail and rim in the accent, the logo above the QR in the top corner, @@ -597,6 +601,62 @@ a verdict named without a colour keeps the default's), the stamp's seconds and corner, and whether and where the tally is drawn; `validateChrome()` refuses an unknown key there as everywhere in the block. +### `thread` and `render.chrome.threads` — the thread rail + +A cut whose clips make a few lines of argument can draw them as a rail of cards +down the frame's left side. Each clip names its thread; the list names the +threads in the rail's order, each with an optional outcome. + +```jsonc +"render": { "chrome": { …, "threads": { "list": [ + { "id": "bet", "label": "The bet: her career", // ≤ 32 characters, one line + "outcome": { "verdict": "CONTRADICTED", "label": "Walked back" } }, // label optional (≤ 24): else the verdict's + { "id": "aside", "label": "An aside" } ] } } } // no outcome: never stamped +{ "type": "clip", "id": "c07", …, "thread": "bet" } +``` + +- **The layout.** With the rail on, the footage box moves to the frame's right + edge (24 px in) and the rail takes the left, as tall as the footage: a card + per thread (1–8), each its number, a dot per clip and its label. +- **The motion.** The card of the thread on screen is lit and a string draws + from it to the picture; a clip's dot fills as the clip comes in; when the + thread's last clip ends (1.8 s before it hands over), its outcome is stamped + on its card in the verdict's colour. Before its thread plays a card is dim, + after it rests quieter, so by the last clip the rail is the whole argument. + The rail steps aside while a popup post has moved the footage over it. +- **Checks.** `validateThreads()` (via `validateChrome()`) refuses a bad list + and the feed layout beside it; `validateThreadEntries()` refuses an entry + naming an unlisted thread, a teaser in a thread and a listed thread with no + clip. `schedule.json` gains `threads: { threads, runs, asides }` only when + the rail is on. `chrome-threads.mjs` is the page; `compose-chrome.mjs + --region threads` renders it; the build lays it last, like the stamps. + +### `render.chrome.flips` — THEN and NOW, back to back + +A cut built of pairs: a line from THEN and the opposite line from NOW. A panel +down the frame's left (the rail's region: a cut has the rail or the panel) +holds one pair while it plays. + +```jsonc +"render": { "transition": 0.12, "chrome": { …, "deck": { "footageScale": 0.78 }, "flips": { "pairs": [ + { "id": "vax", "topic": "Vaccines", // ≤ 32 characters + "then": { "entry": "c01", "when": "2019", "words": "…" }, // when ≤ 18, words ≤ 110: verbatim + "now": { "entry": "c02", "when": "2025", "words": "…" } } ] } } } +``` + +- **The motion.** The pair rises in with its THEN clip: its place (`03 / 11`), + the topic, the THEN card (tag, when, words) lit. As the NOW clip starts its + card slams in under it with a flash, the THEN card dims, and when both + `when`s carry a year the years between roll up on an odometer + ("+7 years later"). The pair lifts away as its NOW clip ends. +- **Checks.** `validateFlips()` (via `validateChrome()`) refuses a bad pair + and the rail beside it; `validateFlipEntries()` refuses a side naming no + timeline entry, a teaser, a THEN after its NOW and an entry in two pairs. + `schedule.json` gains `flips: { pairs, asides }`. `chrome-flips.mjs` is the + page; `compose-chrome.mjs --region flips` renders it. +- **Punch.** The panel is built for short clips — the line and nothing else — + and near-hard cuts (`transition` 0.12); a smaller `footageScale` gives it room. + ### The `image` entry type A still: the receipts a clip cannot say out loud — a post, a thread, a DM, a