Storyboard & reel timing¶
A storyboard is the creative seed of a reel: an ordered list of cards,
each a short on-screen line with its narration, palette roles, and (for overlay
cards) a media panel. It is the main human input — hand-authored or AI-drafted,
then human-edited — so keryx validates it loudly and renders deterministically
from it. The model and maths are a faithful port of the blog gen-reel.py
(spec §3.1).
Card schema¶
storyboard.json is a JSON array of cards:
| Field | Meaning |
|---|---|
text |
the on-screen line (a tight distillation; \n forces a break). *word* marks accent words. |
vo |
the narration — distinct from text: may be fuller and carry provider control tags (SSML <break>, phonetic spellings). |
bg / fg / accent |
palette roles. Mode-dependent: block uses all three; overlay ignores bg. |
dur |
fallback on-screen seconds, used only when no VO drives timing. |
cover / mono |
bookend cover art / monospace URL closer. |
mode |
block (default) or overlay (full-bleed media + scrim + line). |
scene |
overlay illustration prompt (required for a generated overlay card). |
media |
resolved panel {kind: image\|video, source: generated\|uploaded, path}. |
voice |
per-card voice override — any of speaker (a registered voice from the catalog, for multi-author reels), stability, similarity, style, speed, model (a TTS model for this line), pronounce (a respelling used as this line's narration, any model), ipa (a phonetic rendering used on a phoneme-capable model, ignored on multilingual_v2). Steady a wobbly line (stability), slow a fast one (speed), switch speaker, or fix a mangled word (pronounce/ipa), without touching the rest of the reel. Defaults come from the reel theme's voice. |
The on-screen text and the vo narration are kept as separate fields — the
batch proved they want different phrasing.
A per-line --stability/--similarity/--style/--speed passed to
voice gen --line N is persisted into that card's voice block, so a later
reel build reproduces the tuned read.
Validation¶
Loaded storyboards are validated; the same findings back the CLI exit 2, the
API 422, and the studio inline checks:
- MUST non-empty
text(R-WS-9); overlay cards have asceneor supplied media (R-WS-10); balanced*markers (R-WS-11); palette roles reference defined keys, mode-aware (R-WS-12). - SHOULD the last card is the mono URL closer (
R-WS-13);bgon an overlay card warns (inert). Cover-card art availability is checked at render time (R-WS-14).
VO-driven timing¶
Narration drives pacing. Each card's on-screen duration is its VO clip length +
a lead (≈0.5s) + tail (≈0.7s); cards crossfade (xfade ≈0.4s). For card
i:
start_i = Σ dur[:i] − i·xfade
vo_delay_i = (start_i + lead) # the VO is placed here
total = Σ dur − (n−1)·xfade
The music bed is requested at this computed total by default, so it covers
the whole reel — both music gen --takes and reel make size the bed to the
VO-driven total once the VO clips are promoted (music gen --length <d> overrides
it explicitly; with no VO promoted yet the bed falls back to a default length).
The maths is pure and unit-tested (internal/reel); the VO-driven total is
computed once in reelcmd.ReelTimingFromVO and shared by reel build,
music gen --takes, and reel make, with the renderer supplying real durations
(from ffprobe) and font metrics.
Text rendering¶
- Orphan control: wrapping never leaves a lone trailing word — it pulls one word down from the line above (a flagged defect in the first batch).
- Accents:
*word*tokens render in the accent colour; markers are stripped before measurement. (Parity quirk: in a multi-word*no one safer*only the first/last tokens are accented.)
Status: the deterministic core (schema, validation, timing, wrapping, accents) lands in Phase 1d. Card PNG rendering and the ffmpeg xfade/audio-mux assembly (the
Rendereradapter +keryx reel build) follow in the next phase.