UXS-005 — Video Editor
Status · Draft v0.1 · April 2026 · drafted from prototype mockup (OC-02 Fig 7) IA anchor · surfaces/video-editor · topbar-patterns/video-editor · shared-tokens Related PRD · PRD-005 Video Editor — the overlay list in this UXS is concrete; PRD-005 should be updated to enumerate the same overlays Related ADRs · ADR-004 Three-layer data store Related RFCs · RFC-006 Audio system · RFC-007 Key moment detection
Why this UXS exists
The Video Editor is the assembly studio — accumulated PNG renders become an MP4 with audio and overlays. PRD-005's sharpest threat (audio reads as decorative) is defeated specifically when the visual and audio events are demonstrably synchronised. This UXS specifies the visual contract that makes that synchronisation visible: the timeline ribbon under the preview shows key-moment markers; the Audio panel's "key moments detected" list shows the same moments by frame number; the Overlays panel's "Record flash" overlay fires at the same moment the audio swells. The UI has to make the connection visible — that's what this document specifies.
Principles
- Preview dominates; controls are dense. The preview takes ~75% of horizontal space. The right panel is dense and information-rich — this is a workshop surface, not a public face.
- Key moments are first-class. They appear in the preview (ribbon markers, NEW RECORD banner overlays), in the Audio panel (frame-number list), and in the Overlays panel (which overlays fire on which moment types). One detection algorithm (RFC-007), three points of visibility.
- Audio and overlays share a vocabulary. Both consume the per-frame intensity signal. The Overlays panel groups them visually: rendering overlays (counter, anomaly, label, flash) above editorial overlays (date, attribution, pull-quote).
- Export is the primary action.
export MP4lives in the topbar's right region inintent-info— present at all times, never buried in a menu.
Scope
In scope · Video Editor topbar with export MP4 action; preview area with rendered frame, sparkline, key-moment NEW RECORD banner, in-frame metadata overlay, and timeline ribbon; right-side control panel with Sequence, Audio, and Overlays sections; key-moments-detected list; overlay enable/disable list with status dots; citation footer.
Non-goals · The export-completion screen / share modal (deferred); the audio API authentication flow (Phase 2); behavioural rules (playback timing, key-moment detection algorithm — those are RFC territory).
Boundary note · Frame playback timing, audio crossfading mechanics (RFC-006), key-moment detection algorithm (RFC-007), and timeline ribbon scrubbing behaviour all belong in their respective RFCs. This UXS specifies the static appearance of every panel and overlay marker — not how they animate or compute.
Theme
Dark only.
Tokens
Inherited from IA
- Surface ·
canvas,surface,elevated,overlay,border,border-strong - Text ·
text,text-secondary,text-muted,text-disabled - Intent ·
intent-info(export action, audio section header, "frames" stat);intent-alert(record markers, NEW RECORD banner) - Typography ·
type-display,type-data,type-body,type-axis,type-label - Spacing · base unit 4px
Defined here — videoeditor-*
The Video Editor introduces tokens for the timeline ribbon's key-moment markers and the overlay status indicators.
| Token | Value | Usage |
|---|---|---|
videoeditor-marker-peak |
intent-alert |
Statistical peaks and record events on the timeline ribbon |
videoeditor-marker-cool |
intent-info |
Cooling / negative-anomaly events on the ribbon |
videoeditor-marker-record |
linear-gradient(135deg, #EF9F27, #F09595) |
Record events — amber-to-coral gradient marker |
videoeditor-playhead |
rgba(255,255,255,0.85) |
Current playback position indicator on the ribbon |
videoeditor-overlay-on |
intent-info |
Filled dot indicating an overlay is enabled |
videoeditor-overlay-off |
border |
Empty circle indicating an overlay is disabled |
videoeditor-banner |
rgba(239,159,39,0.18) |
Background fill for the in-preview "NEW RECORD" banner |
The marker colours intentionally match the source palette so that the timeline ribbon under an SST recipe uses warm tones and an ice recipe would use cool tones — the visual identity carries through.
Layout (Fig 7)
┌──────────────────────────────────────────────────────────────────────────────┐
│ OCEANCANVAS /timelapse editor / gulf_stream_thermal export MP4│ ← topbar (42px)
├─────────────────────────────────────────────────────────┬────────────────────┤
│ │ SEQUENCE │ ← right panel
│ ┌─────────────────┐ │ recipe gulf... │ ~340px wide
│ │ ╱╲╱─╲─╱╲╱╲╱──── │ ← sparkline (top-left, ~150x60) │ frames 365 │ `surface` bg
│ │ ● │ trace + current-position dot │ duration 30s·12fps│
│ └─────────────────┘ │ │
│ │ AUDIO │ ← intent-info hdr
│ ┌─────────────────────────────┐ │ via generative API│
│ │ ▢ NEW RECORD ▢ │ ← banner │ │
│ │ videoeditor-banner fill │ (centred, │ theme Ocean │
│ │ intent-alert text │ key moment)│ energy builds... │
│ └─────────────────────────────┘ │ sensitivity react.│
│ │ key mom. swell │
│ │ │
│ PREVIEW CANVAS │ key moments │
│ (rendered frame, e.g. SST thermal field) │ detected: │
│ full bleed of left area │ ●El Niño peak fr.54│
│ │ ●Record high fr.348│
│ 14 Mar 2026 │ ●Acceleration fr.378│
│ +1.8° (anomaly in domain-sst-accent) │ │
│ above baseline (sublabel in text-muted) │ OVERLAYS │
│ NOAA OISST · North Atlantic · OceanCanvas │ │
│ (in-frame attribution overlay, lower-left) │ ● Primary counter │
│ │ SST each frame │
│ │ ● Anomaly indicator│
│ ────●═══════════●══════════●══════════════════════► │ vs baseline │
│ peak cool record (timeline ribbon, key moment markers)│ ● Named event labels│
│ │ El Niño etc. │
│ │ ● Record flash │
│ │ at peaks │
│ │ ● Moving sparkline│
│ │ last 30 frames│
│ │ ● Timeline ribbon │
│ │ progress + ev.│
│ │ ● Date stamp │
│ │ editorial │
│ │ ● Source attrib. │
│ │ footer │
│ │ │
│ │ ○ Pull quote │
│ │ ○ Projection ghost│
├─────────────────────────────────────────────────────────┴────────────────────┤
│ OceanCanvas · Video editor · Audio + overlay enrichment · Key moments shared │ ← page footer
│ between tracks · Generative music API │
└──────────────────────────────────────────────────────────────────────────────┘
| Region | Position / size | Tokens | Notes |
|---|---|---|---|
| Topbar | Full width, 42px | surface background, wordmark on left, two-segment path in text-secondary, export MP4 in intent-info on right |
Per IA topbar-patterns/video-editor |
| Preview area | ~75% of viewport width, full height between topbar and footer | canvas background, render frame fills |
Updates as playback advances |
| Sparkline (in-preview, top-left) | Upper-left of preview, ~150×60px, padded ~24px from edges | surface 80% background, line in domain-sst-accent 1px, current-frame dot in text filled circle 4px |
Shows the data trend across the full sequence; current position dot moves with playback |
| NEW RECORD banner (in-preview) | Centred horizontally, ~30% of preview width, ~36px tall | videoeditor-banner background, intent-alert text, intent-alert 1px border |
Appears when a record key-moment fires; only visible during the moment, otherwise hidden. Animation timing in RFC-007 |
| Date stamp (in-preview) | Lower-left of preview area, padded ~24px | text type-data for date |
"14 Mar 2026" |
| Anomaly overlay (in-preview) | Below date | domain-sst-accent type-display for anomaly value, text-muted type-label for "above baseline" |
Source-coloured per the recipe's source — domain-sst-accent for SST recipes, would shift to domain-sealevel-accent for sea level recipes |
| In-frame attribution (lower-left footer of preview) | Bottom of preview area | text-muted type-axis |
"NOAA OISST · North Atlantic · OceanCanvas" — appears as part of the rendered frame because Source attribution overlay is enabled |
| Timeline ribbon | Bottom of preview area, full preview width, ~32px tall | border line as the track; key-moment markers as filled circles in marker-type colours; playhead as videoeditor-playhead filled circle 8px |
Per RFC-007: peak, cool, record, accel markers each have their colour |
| Right panel | ~340px wide, full height | surface background, border 1px left edge |
Three sections, type-label text-muted headers (or intent-info for AUDIO active section) |
| SEQUENCE section | Top of right panel | each row: label in text-muted type-data left, value in text right; "frames" value in intent-info to indicate it's a derived count |
recipe / frames / duration |
| AUDIO section | Below SEQUENCE | header intent-info (active section indicator); subtitle "via generative API" in text-muted; rows same pattern as SEQUENCE; values in intent-info for theme, text for others |
theme / energy arc / sensitivity / key moments |
| Key moments detected list | Sub-list within AUDIO | each row: status dot in videoeditor-marker-peak (or matching colour), event label in text, frame label in text-muted type-axis right-aligned |
"El Niño peak fr.54" / "Record high fr.348" / "Acceleration fr.378" |
| Channel mixer + EQ block | Below the waveform inside AUDIO | two-column grid: left = 4 channel rows (pad / pulse / accent / texture) with mute toggle + slim volume slider; right = 3 EQ bands (bass / mid / treble) with slim sliders and dB readout; mute strikes through the channel label and dims to text-disabled |
per ADR-027 mixer + EQ surface |
| Tension arc editor | Below the mixer + EQ inside AUDIO | small SVG curve preview (~280×50px) in surface 4% tint with border 1px, intent-teal curve at 85% opacity, draggable peak handle as intent-info filled circle with canvas 1.5px stroke; below the curve a row of 5 preset pills (none / classic / plateau / drift / invert) with active in intent-teal border + tint, inactive in text-muted border; below the pills, optional pin toggle row (accent-color: intent-teal) showing "pin peak to record moment (frame N)" in text-muted type-axis |
per ADR-028 — author-facing arc surface |
| Arc overlay (on waveform) | Painted over the waveform canvas | thin guide line at ~28% opacity tracing arc[t] across canvas height; live indicator dot at currentFrame in rgba(180, 220, 255, 0.9) 2.5px filled circle |
per ADR-028 — visualizer reads engine state, not parallel math |
| OVERLAYS section | Bottom of right panel | header text-muted type-label; rows: status dot + label + sublabel; enabled overlays use videoeditor-overlay-on; disabled use videoeditor-overlay-off |
8 enabled by default + 2 disabled |
| Citation footer | Bottom, full width | text-muted type-axis |
"OceanCanvas · Video editor · Audio + overlay enrichment · Key moments shared between tracks · Generative music API" |
The overlays — concrete list
The prototype defines the overlay set explicitly. PRD-005 should be revised to match this list.
| Overlay | Default | Description (sublabel in panel) |
|---|---|---|
| Primary counter | enabled | "SST each frame" — current-frame value over the render |
| Anomaly indicator | enabled | "vs baseline" — anomaly statistic over the render |
| Named event labels | enabled | "El Niño etc." — text labels for known events |
| Record flash | enabled | "at peaks" — visual flash on record key-moments |
| Moving sparkline | enabled | "last 30 frames" — small trend graphic in upper-left |
| Timeline ribbon | enabled | "progress + events" — the ribbon under the preview, exported with the video |
| Date stamp | enabled | "editorial" — the in-frame date in lower-left |
| Source attribution | enabled | "footer" — the in-frame attribution at very bottom |
| Pull quote | disabled | (Phase 2 — text quote inset on selected frames) |
| Projection ghost | disabled | (Phase 2 — overlay of past frames as ghosting) |
Component states
| Component | Default | Hover | Active | Focus | Disabled | Loading | Empty | Error |
|---|---|---|---|---|---|---|---|---|
| Export MP4 button | intent-info text in topbar |
brighter intent-info |
n/a (initiates export) | border-strong ring |
text-disabled (no frames) |
spinner replaces label | n/a | label flips to intent-alert "export failed" |
| Timeline ribbon track | border line |
crosshair appears at cursor x; preview frame jumps to that position | n/a | border-strong ring |
shimmer | n/a | n/a | n/a |
| Timeline ribbon marker | filled circle in marker-type colour | tooltip with event details + frame number in overlay |
n/a | border-strong ring |
n/a | n/a | n/a | hidden if data missing |
| Timeline ribbon playhead | videoeditor-playhead filled circle |
drags with cursor | n/a (always at current frame) | border-strong ring |
n/a | n/a | n/a | n/a |
| Audio section value | intent-info (theme, key moments) or text (others) |
underline on hover when changeable | tooltip when interactive | border-strong ring |
text-disabled |
shimmer | n/a | intent-alert |
| Overlay row | status dot + label + sublabel | row background surface 4% on hover |
enabled state: dot in videoeditor-overlay-on; disabled: videoeditor-overlay-off |
border-strong ring |
text-disabled |
n/a | n/a | dot flips intent-alert if overlay errors |
| Key-moment list row | dot + label + frame ref | row background surface 4% on hover |
clicking jumps preview to that frame | border-strong ring |
n/a | shimmer if not yet detected | "no key moments detected" centred at text-muted |
intent-alert if detection failed |
| NEW RECORD banner | hidden by default; shows during record key-moments only | n/a | videoeditor-banner fill + intent-alert text |
n/a | n/a | n/a | n/a | n/a |
Accessibility
- Contrast ·
intent-info(#5DCAA5) oversurfaceis 8:1+.intent-alert(#F09595) overvideoeditor-banner(low-opacity amber) is verified at 4.8:1 — meets WCAG AA. The status dots in the overlay list are colour-coded but always paired with text labels, so they remain distinguishable for users with colour-vision differences. - Focus · all interactive elements (export button, ribbon markers, ribbon playhead, audio section values, overlay rows, key-moment list rows) show a
border-strongfocus ring. - Keyboard · ribbon playhead accepts arrow keys for stepwise frame change; ribbon markers tab-reachable as a sub-group; overlay rows accept Space to toggle; export button accepts Enter. Tab order: topbar (wordmark → path → export) → preview controls → right panel sections (Sequence → Audio → Overlays) in document order.
- Reduced motion · NEW RECORD banner appearance, ribbon playhead movement, overlay enable/disable transitions, export-progress animation all respect
prefers-reduced-motion. - Screen readers · preview is
<region>witharia-labelcontaining the recipe id and current frame number. Timeline ribbon is a<slider>(oraria-valuenow-equipped element) witharia-valuemin/-max/-nowfor frame number. Markers arerole="button"with descriptions. Overlay rows are checkboxes witharia-checked. Key-moment list is<ul>with each row as<li>containing a button.
Acceptance criteria
- [ ] Topbar shows two-segment path (
/timelapse editor / {recipe-id}) andexport MP4action inintent-info - [ ] Preview area takes ~75% of horizontal space; right panel is ~340px wide
- [ ] In-preview sparkline appears top-left at ~150×60px with current-frame dot
- [ ] NEW RECORD banner appears in
videoeditor-bannerfill withintent-alerttext — only visible during record moments - [ ] In-preview metadata (date, anomaly, attribution) appears lower-left in source-appropriate colours
- [ ] Timeline ribbon is full preview width at the bottom of the preview area; markers colour-coded per type
- [ ] Right panel has three sections: SEQUENCE (
text-mutedheader), AUDIO (intent-infoheader — active section), OVERLAYS (text-mutedheader) - [ ] Audio section's "key moments detected" list shows colour-coded dots matching ribbon-marker colours
- [ ] Overlays section lists 10 overlays with status dots — 8 enabled by default (filled
intent-info), 2 disabled (borderempty circle) - [ ] Citation footer at bottom in
text-mutedtype-axis - [ ] All semantic tokens used; no one-off hex outside
videoeditor-*definitions - [ ] Focus visible on all interactive elements
- [ ] Keyboard reachability confirmed for ribbon, audio values, overlays, key-moment list
- [ ] Screen-reader labels in place on preview, ribbon, overlay rows, and key-moment list
Notes for related docs
PRD-005 should enumerate the overlays. This UXS contains the concrete list (10 overlays, 8 default-enabled). PRD-005 v0.2 should reference it explicitly so the product surface is documented at the impact level, not only at the visual-contract level.
RFC-006 audio system architecture stands. The prototype confirms the four-axis audio control surface (theme, energy arc, sensitivity, key moments). The "via generative API" subtitle indicates the stem-source choice (per RFC-006's Implementation B path) is in play here — the deeper API choice (Mubert vs. Beatoven) remains open.
RFC-007 key moment detection — the prototype shows three detected moments by name (El Niño peak, Record high, Acceleration). These map to the four detector types in RFC-007 (peaks, records, threshold, inflection); Acceleration corresponds to the inflection detector. Worth confirming in RFC-007's open questions whether the user-facing moment names are derived from detector type or set by the user / preset.