Skip to content

0036 — Studio theme editor (rgba palette + full type-scoped theme controls)

Status: IN PROGRESS — from Matt's 2026-07-23 studio driving notes (0029 §9). D1 + D2 resolved with Matt 2026-07-23: canonical form #RRGGBBAA, alpha everywhere the renderer composites (gg's SetHexColor natively parses hex8; an all-opaque palette renders identically). D3 resolved 2026-07-23: fonts are a picker (datalist, free-text escape) over GET /fonts — the system DejaVu family (bare names) + project fonts in assets/fonts/*.ttf|otf (project-relative paths, which the renderer's resolveFont passes through verbatim — "brand fonts" work today by dropping files there). Follow-up (Matt): a studio upload manager to load fonts INTO the project (persisted with it), so brand fonts don't require filesystem access. D4 (script-definition editability) still open. Date: 2026-07-23 Relates: 0006 (avatar theme — the theme model this edits), 0034 (project settings — the ThemesManager this replaces/extends), 0035 (config writes — themes persist via Store.Apply), 0001 §6 (themes are config-driven).


1. Problem

The 0034 ThemesManager exposes only the palette, edited as HTML hex strings behind a browser-default colour input — "an incomplete and confusing UI" (Matt). A theme is much more than a palette (the blog's reel/blueprint: card.{font_bold,font_mono,mode,scrim, style} · music.{gain,prompt} · palette · voice.{id,stability,similarity}), and the editable surface should scope to what the theme's type actually uses.

2. Goals

  1. A proper colour picker — a real wheel/area picker (HSV area + hue slider), not the native swatch; palette entries displayed as named swatches.
  2. rgba, not hex — the palette gains an alpha channel. Intent (Matt, confirmed): transparency is a designed axis, most immediately for scrims/overlays (e.g. card.scrim.color + from today approximates what an rgba scrim colour expresses directly). Storage moves from #RRGGBB to rgba-capable form.
  3. Full theme controls, type-scoped — beyond palette: fonts (card.font_bold/mono), style prompt (card.style), script definition (mode/scrim/accent conventions), music (prompt · gain), voice (id · stability · similarity), each shown only for the theme types that carry them (reel = all; article/portrait = prompt+palette…).

3. Design sketch

  • Colour model. Palette values accept #RRGGBB (back-compat) and #RRGGBBAA / rgba(r,g,b,a). Canonical storage: #RRGGBBAA (compact, YAML-friendly, sorts stably); alpha FF may serialise as #RRGGBB for parity with existing themes.
  • Renderer impact. internal/gen/reel (fogleman/gg + ffmpeg pipeline) must parse the extended form and honour alpha where compositing supports it (text fills, scrims, blocks). Parity guard: an all-opaque palette renders identically to today.
  • Editor layout. Per-theme accordion of sections (Palette · Fonts · Style prompt · Script · Music · Voice), each section present iff the type schema includes it. Raw-JSON "Advanced" per theme stays (0034 Q1) as the escape hatch.
  • Persistence. Through the existing themes CRUD → project Store.Apply (0035); targeted per-theme writes remain the deferred nicety.

4. Open questions (for review)

  • D1: #RRGGBBAA vs rgba() string as the canonical stored form? (Rec: #RRGGBBAA.)
  • D2: does alpha extend to every palette use (text/bg fills) or only compositing surfaces (scrim, overlay tints) in v1? (Rec: everywhere the renderer composites; the parity guard keeps opaque behaviour unchanged.)
  • D3: font control = free-text font name, or a picker over fonts discovered in the assets/embedded set?
  • D4: is "script definition" (mode/scrim conventions) editable v1 or read-only surfaced?

5. Non-goals

  • New theme types; theme inheritance; per-card palette overrides (0038 territory).