commit f1fc799bdeb45dbdeef8c8e3958a3f78761e42a2
parent dc34b4e4305f5edd6bf64fe05a0ae77327929426
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sat, 26 Sep 2026 02:05:54 -0400
plans: brand S4 approved — Archilyzer Media: M2 Signal mark, "flush · caps matched" lockup (MEDIA at 1.035x, measured), YouTube assets CLI, an opt-in umtool report-to-video preset with vendored OFL fonts; not part of the site rollout
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
1 file changed, 91 insertions(+), 56 deletions(-)
diff --git a/plans/brand-and-themes.md b/plans/brand-and-themes.md
@@ -1256,59 +1256,94 @@ also writes the rollout scripts to `scripts/`); the release record is
and the homepage (`pnpm --filter yt-dlp-transcript-common exec tsx bin/archilyzer.ts build
homepage`, then `… deploy homepage`). `pnpm ops` needs `WORKER_TOKEN` from `editor/.env`.
-## Proposed — Archilyzer Media, the YouTube channel (awaiting the operator's picks)
-
-Asked 2026-09-25: branding for **Archilyzer Media**, the operator's YouTube channel for the
-videos. It is a new row on the canvas, "Archilyzer Media · the YouTube channel" (canvas
-version 10), with three boards: *Media · mark + lockup*, *Media · the channel* and *Media · in
-the video*. The generators are `gen.py` and `gen_media.py` beside the staging dir
-(`node_modules/.brand-canvas/`); `gen_media.py` takes the live `canvas.json` it read as its
-argument.
-
-**Open choices** (recommendation first):
-- **Mark.**
- - **M2 · Signal:** the parent mark, graphite and dim, with the found line and play head lit in
- Signal `#5fa8a0`.
- - **M1 · Bone:** the parent mark unchanged.
-
- At 40 px in a subscription list, bone on graphite reads as a blank grey avatar. Signal is
- Archilyzer's own accent, so the channel speaks as the project rather than as any one site,
- and it does not fight YouTube's red.
-- **Lockup.**
- - **Imprint:** the `Archi|lyzer` wordmark over a `MEDIA` tag (Plex Mono 500, tracked
- 0.24em, in the accent).
- - **Inline:** `Archi|lyzer Media`, with "Media" in the suffix weight.
-
-**The channel assets.** YouTube's specs were checked 2026-09-25.
-
-| Asset | Size | Design |
-|---|---|---|
-| Profile picture | 800×800 PNG, rendered as a 98 px circle | `markSvg` maskable (scale 0.8 keeps the farthest corner at 69% of the circle's radius) |
-| Banner | 2560×1440 PNG ≤ 6 MB. Every device shows only the centre 1546×423; desktop shows 2560×423, tablet 1855×423 | A field of dim transcript lines wrapping around a clear safe area, the lockup centred in it, and one lit found line in the desktop strip |
-| Watermark (Studio) | 150×150 PNG | `markSvg` any |
-| Thumbnail template | 1280×720 | The still on the left; the headline (Archivo 118%, 800) and a found line on the right; the mark top-left; the bottom-right kept clear for YouTube's duration badge |
-
-**In the video** (`umtool/report-to-video`).
-- **Today:**
- - The cards are drawn with ImageMagick + Pango (`render-cards.mjs`), and the clip header
- with ffmpeg `drawtext` (`build-video.mjs`).
- - Colours come from the manifest's `render.palette`; fonts come from `render.fontRegular` /
- `render.fontBold`.
- - "Fira Sans" is the hardcoded default in `span()`.
- - Nothing is burned in.
-- **Proposed:**
- - A `brand` preset: ground `#151b20`, fg `#e7edf1`, muted `#8496a2`, accent Signal.
- - The mark leads the existing `Channel · title · date @ time` header. It is burned in, so
- reposts keep it.
- - A title card and an end card that carry the lockup, the end card with slots for the
- end-screen elements.
-- **Fonts:** this needs Archivo and IBM Plex installed as system fonts; neither is on this
- machine. `ttf-ibm-plex` is in Arch's extra repo. Archivo's variable TTF comes from Google
- Fonts, into `~/.local/share/fonts`. Pango takes `@wdth=118` variations.
-
-**Slice S4, after S1** (it reuses `markSvg` and S1's PNG renderer):
-- `common/bin/brand-icons.ts --youtube <dir>` writes the profile picture, banner and watermark.
- The banner's text needs Archivo at exactly 118%: a static instance (fontTools `instancer`)
- for satori, or installed fonts for `rsvg-convert`.
-- The umtool preset.
-- The operator claims the handle and uploads the assets.
+## S4 — Archilyzer Media, the YouTube channel (approved 2026-09-26)
+
+On 2026-09-25 the operator asked for branding for **Archilyzer Media**, their YouTube channel for
+the videos, and approved the design on 2026-09-26. It is on the canvas (version 14):
+https://claude.ai/artifact/UsUxwgRkP5a3m4jZXucAvG, in the row "Archilyzer Media · the YouTube
+channel". The generators are `node_modules/.brand-canvas/{gen,gen_media}.py` in the primary checkout.
+
+S4 ships after release 10's cut and is **not part of the site rollout**: it touches only a CLI in
+`common/bin` and umtool.
+
+### Decisions (operator, 2026-09-26)
+
+- **Mark M2 · Signal.** The parent mark's geometry, lit in Signal: ground `#151b20`, dim `#3f4c56`,
+ lit `#5fa8a0`. The avatar uses the maskable variant (scale 0.8 on full-bleed ground).
+- **Lockup "flush · caps matched".** The `Archi|lyzer` wordmark sits over `MEDIA`:
+ - Both are Archivo at wdth 118. The wordmark is 720 / 380 at -0.01em; MEDIA is 700, in Signal.
+ - MEDIA's size is **1.035×** the wordmark's, and it is letter-spaced to exactly the wordmark's
+ width.
+ - Measured with fontTools on `Archivo[wdth,wght]`: "Archilyzer" is 5.334 em and "MEDIA" is
+ 3.953 em. So MEDIA's capitals match the wordmark's cap height (0.686 em), with 0.30 em between
+ letters.
+ - The mark's height equals the text block's (wordmark cap top to MEDIA baseline), about 1.70× the
+ wordmark size, with a 0.46× gap.
+ - On the banner at 2560 px: wordmark 124 px, MEDIA 128 px, text width 661, mark 210. The block
+ is centred on the safe area.
+- **Unchanged from the proposal:** the banner (a field of dim transcript lines wrapping around a
+ clear gutter round the safe area, the lockup centred in it, one lit found line with a play head in
+ the desktop strip right of the safe area); the Studio watermark (`any` variant); the burned-in mark
+ leading the clip header; the title card, end card and thumbnail layouts of the *in the video*
+ board.
+
+### What S4 delivers
+
+1. **`common/lib/brandMedia.ts` (pure).**
+ - `MEDIA_PALETTE`, `MEDIA_RATIO = 1.035`.
+ - `mediaLockupSvg({px, palette})`: a standalone SVG with **the text as outlined paths**, so
+ rendering the lockup needs no font (rsvg-convert, satori `<img>`, ImageMagick).
+ - The outlines come from a checked-in, generated `common/lib/brandMediaGlyphs.ts` (do-not-edit
+ header): glyph paths and advances at wdth 118 for `Archi` 720, `lyzer` 380 and `MEDIA` 700,
+ plus kerning pairs if the font has them.
+ - The generator is `common/bin/gen-media-glyphs.py` (fontTools instancer; the repo already has
+ Python tools). It downloads `Archivo[wdth,wght].ttf` from google/fonts; the font is not
+ committed.
+2. **The YouTube channel assets:** `common/bin/brand-media.ts --out <dir>`. The default dir is
+ `~/reports/archilyzer-media/brand/`. It writes, each with its SVG source:
+ - `avatar-800.png`;
+ - `watermark-150.png`, with transparent corners;
+ - `banner-2560x1440.png`, ≤ 6 MB;
+ - `banner-safe-1546x423.png`, the part every device shows.
+
+ It also writes `INDEX.html` (operator rule: handoffs are HTML), with a preview of each asset,
+ its size, and the YouTube Studio upload steps: Customization → Branding → Picture / Banner
+ image / Video watermark.
+3. **The umtool report-to-video brand preset: opt-in, and nothing else moves.**
+ - **How it's enabled:** a manifest opts in (e.g. `render.brand: "archilyzer-media"`). The preset
+ sets `render.palette` (bg `#151b20`, fg `#e7edf1`, muted `#8496a2`, accent `#5fa8a0`, amber
+ `#e3b15c`) and the fonts: Archivo at wdth 118 for display, Plex Sans for body, Plex Mono for
+ the header and meta lines.
+ - **Title card:** the lockup top-left; the title in Archivo 118% 720; the found line (play head
+ + lit bar) under it; a Plex Mono meta line.
+ - **Clip header:** the mark leads the existing `Channel · title · date @ time` header, burned in.
+ - **End card:** new, and only with the preset. The lockup and `archilyzer.pages.dev` on the
+ left; the right half kept clear for YouTube's end-screen elements (nothing drawn there). The
+ duration is configurable, default 20 s.
+ - **Thumbnail step:** 1280×720 from a clip still plus a headline, per the board. The mark is
+ top-left, and the bottom-right is kept clear for the duration badge.
+ - **Fonts are vendored (OFL), not system-installed.** Archivo variable, IBM Plex Sans and IBM
+ Plex Mono go under `umtool/report-to-video/fonts/` with `OFL.txt` and a `fonts.conf`.
+ - The preset points `FONTCONFIG_FILE` at that conf for its `magick`/`rsvg-convert` children.
+ - Pango takes `@wght=…,wdth=118` variations (Pango 1.58 here).
+ - ffmpeg `drawtext` takes `fontfile=` paths, and needs static fonts only.
+ - Fallback: `fonts/install-user-fonts.sh` into `~/.local/share/fonts`, which needs no sudo.
+ - **Surface:** if umtool has a render/project settings surface, the preset is a choice there
+ (operator rule: umtool evolves with the video); otherwise it is manifest-only, and the report
+ says so.
+ - **Hard rule: byte-identical when not opted in.** The live umtool (:3050) spawns
+ report-to-video scripts from disk, so a manifest that does not opt in must render
+ **byte-identical** cards before and after. Prove it on an existing manifest's cards.
+
+### Gates
+
+- tsc.
+- Unit tests: common, editor, `test:scripts`, mcp, and the report-to-video tests.
+- **The lockup's geometry:** the MEDIA advance equals the wordmark advance within 0.5%, and the
+ block sits inside the banner's safe area.
+- **The PNGs:** the IHDR sizes are right, and the banner is ≤ 6 MB.
+- **The before/after card diff** for a manifest that does not opt in.
+- **A rendered sample:** title card, a clip header frame, end card and thumbnail for a small
+ fixture manifest. Look at each one.
+- umtool e2e if umtool's code is touched (`SONG_DIR=~/reports/quartering-uh-song/data pnpm
+ --filter umtool run e2e`, queued).