Recorder, Captions Architecture & Take Health
A platform release with a redesigned recorder shell, consolidated captions architecture, take health checks, transcript editing, and a v2 storage layout.
A platform release. Two large engineering pushes — a ground-up redesign of the recorder shell and a five-phase consolidation of the captions architecture — landed alongside a new take-health system, a redesigned transcript editor, and a v2 storage layout.
Recorder
- RecorderShell redesign — single phase-aware shell replaces the legacy workspace.
Static recording surface, unified top bar across idle/recording/review/player phases,
horizontal filmstrip of scenes and takes, contextual scene insertion via flanking ”+”
buttons, and a global TakesDrawer toggled by
e. - SceneTile + TakeThumbCard — compact text-focused scene navigation, inline active-state controls, webcam PiP on take thumbnails, aspect-preserving formats with automatic migration of legacy square thumbnails.
- DeviceStrip + DevicePicker — hot-plug auto-detection via Swift
AVCaptureDeviceobservers and Tauri events. Empty-array canonical state replaces the per-sourceenabledflag. Device watchdog auto-stops a recording when hardware disconnects. - Long-lived SCStream architecture —
ScreenSessionFFI keeps the screen-capture pipeline warm across takes. Priming window persists to maintain the XPC connection; forced re-prime on every take fixes the black-screen regression. - Broken-take detection — new Rust
probe_take_healthTauri command (split across five submodules) uses the bundledffmpegsidecar to validate each take’s required streams. Broken takes render with a red ring + disabled star;selectTakerefuses them; “Send to …” is gated when any scene has no usable take; the silence-bridge re-probes at handoff and surfacesBundleHasUnhealthyTakesErrorwith a toast. - Audio feedback — procedural cues at 432 Hz for countdown, recording state changes, and transitions.
- Recording project list — status, progress, size, and rename. Project lineage tracking persists recording → silence and silence → captions handoffs.
- Per-scene export — export model emits per-scene folders, persists export directories for quick access, includes timestamps in folder names, opens in Finder with stale-path recovery, and surfaces a rich success summary.
- Post-ready error recovery — non-terminal stream failures after
recording-readyno longer discard the recording.
Captions Architecture Consolidation (Phases 0–5)
A targeted refactor that took the captions feature from 11 stores to 6, removed two parallel rendering paths, and replaced reactive playhead subscriptions with a single RAF-driven loop.
- Phase 0 — Zod schemas as the source of truth for captions types, a fixture
library with round-trip tests, and a
/dev/gallerypage for fixture-based visual review. - Phase 1 — Single render path. Removed the shadow renderer; all visible
captions/overlay output now flows through
<MainComposition>driven by Remotion’s<Player>(live editor) or render worker (export).<CaptionsPlayerOverlay>survives as a transparent interaction layer that ghost-renders content for correct drag/resize/rotate handle dimensions. - Phase 2 — Store consolidation. Merged
style-store,export-store,timeline-display-store, andpreview-guide-storeinto existing stores; splitsegments-store/index.ts(645 → 44 LoC) andoverlays-store.ts(565 → 54 LoC) into focused slices. Extracted a sharedbuildSegmentEntityMaphelper. - Phase 3 — Imperative playhead. New
PlayheadStore+PlayheadProvider+useFrameValue<T>(selector)hook backed by a single shared RAF loop. Components now only re-render when the selected value actually changes, not on every clock tick. MigratedCropMode,CaptionsPlayerOverlay,TimeDisplay,CutButton, anduseOverlayActionsoffuseTimelineStore((s) => s.currentTime). - Phase 4a — Retired MediaPool from the captions feature.
- Phase 5 — Docs. CLAUDE.md §6 (shadow renderer) and §9 (store map) rewritten;
new performance rule 18 in
docs/perf/REACT_PERF_RULES.mdforuseFrameValue. - Segments as source of truth — per-phrase data migrated from overlays into caption segments; translation feature removed; new transcript editor components replace the old transcription panel.
Transcript Editor
- Transcript drawer — side-panel editor with toolbar, search/find-and-replace,
filter chips, persistent review cursor (
R/Shift+R/Cmd+Enter), atomic per-segment review marking, phrase grouping, confidence heatmap with smooth auto-mark fade, and phrase-level context menus. - Centralized shortcut catalog at
src/features/captions/shortcuts.ts; project- wide migration to theisEditableTargetguard. - Search-and-replace — whole-word toggle fixes a data-loss bug; navigation + replace UI with batch select-all.
- Phrase inspector — per-phrase rotation and
maxFontSizeoverrides, individual segment editing, select-all phrases for batch editing. - Heatmap canonical for the reviewed signal, JSON preview tab, deduped download UI; orphan-aware cursor advance.
Editor & Inspector
- Tabbed cockpit (Content / Style / Transform / Animation) with selection-summary header and bulk Tighten/Delete/Clear actions. “Mixed” indicators across all multi-edit fields. Cockpit thumbnail anchor in the inspector header.
- Crop overhaul — improved aspect-ratio presets, keyboard shortcuts, crop inspector section, transcript controls relocated to a new drawer toolbar.
- Animation presets system — UI controls with detection logic; collapsible
AnimationPickerpanels replaced with persistentPhaseCardcomponents. - Whisper engine presets with advanced settings + customization tracking.
- Multi-selection — Shift+click range, Cmd+click toggle, Cmd+A select all; multi-overlay transcription cockpit; primary anchoring on shift+click.
- Per-phrase rotation in editor and renderer; capitalize support in text formatting; broader sidebar resize range.
- Drag-and-drop video import to the Captions dashboard via a pre-filled
CaptionsCreationDialog. - Crop and text styling — shadow and stroke separated into independent rendering
layers (font-relative
emfractions for cross-platform consistency); padding and background sizing unified onto em-fractions of font height. - FCP-style filmstrip thumbnails on timeline video clips.
- Bridge templates (Minimal + Screen Studio) for send-to-captions.
Silence Remover
- Dual-sidebar layout with specialized clips and settings panels. Drag-to-reorder clips, batch deletion, custom shortcuts, segment navigation, adjustable waveform.
- Per-clip overrides + denoise modes; manual-edit ledger survives slider/preset changes.
- Orientation-aware player canvas; auto-rewind on playback completion.
- Atomic multi-file project creation; live import + denoise progress; cancellation.
Storage & Persistence
- v2 layout — internal state in
app_data_root;Exports/split into{Recordings,SilenceRemoval,Captions}/subfolders; all three stages auto-save with reveal-in-Finder toast. Centralized naming utilities atcrate::storage::naming; paths viacrate::storage::paths. Project-type isolation; simplified path resolution. - Captions persistence actor with a generation-counter invariant — wired into the save/load lifecycle; prevents reset-time data corruption; surfaces load errors in the warm-up overlay with retry.
- Project-level legacy fields removed (
duration,width,height); dynamic clip-based calculation. Incremental project-metadata backfill forpreviewVideoPathand missing counts. - Debounced auto-save with flush on window close.
Theme
- Theme provider with curated OKLCH presets, runtime swap via CSS custom props, 220 ms cross-fade, zero-flash boot.
- Project-wide migration to shadcn theme tokens — replaced raw Tailwind colour
scales (
bg-zinc-950,text-white/85,border-white/10, …) with theme tokens (bg-background,text-foreground,border-border, …). CLAUDE.md §4c documents the mapping.
Performance
- Proxy encoder low-latency —
-g 6 -keyint_min 6 -tune zerolatency(keyframe every 0.2 s);TARGET_PREMOUNT_S1.5 → 0.5 — minimizes clip-boundary lag and audio-context strain. - Captions overlay audio via pooled
<Audio>tags withnumberOfSharedAudioTags={6}— fixes the clip-3 audio death caused by WebKit’s per-element user-activation model. - MediaPool optimizations — park-once logic for inactive slots; preserve
srcon recycle so same-clip handoffs stay warm. TranscriptionPanelre-renders eliminated viauseFrameValuemigration.- Increased video playhead drift tolerance to prevent decoder freezing.
Bug Fixes
- Compositional duration off-by-one fixed alongside the always-visible
PhraseLengthInlineSlider. - Manual text overlays no longer auto-assign to caption-bearing tracks.
- Filmstrip layout shift during scene transitions scoped via animations; take row height pinned.
- Word-merge synchronization bug —
mergeWordsnow callssyncToOverlaybeforereGroupSegmentsto prevent stale per-overlay rawWords from overwriting the primary track. Merge shortcut remapped tomod+shift+m. - Caption regeneration wipes all prior text overlays for the source clip (pass-specific cleanup treats undefined as ‘original’).
- New tracks insert at top of section, not bottom.
- Race-condition media playback —
ensurePausedutility chains pause commands to pending play promises. - Multi-import in silence remover — black clip 3 + height fluctuation fixes.
- Self-healing router for stale
lastPageredirects. - Bridge FFmpeg failures now surface stderr in silence → captions errors.
- Infinite reset loop introduced by Phase 2 style merge resolved.
Refactoring
SettingsTab.tsx509 → 309 LoC (main);useFontLoader.ts434 → 83 LoC (orchestration);TimelineItem.tsxsplit into focused hooks.- Tracks persist as full objects instead of IDs; sacred-track logic replaced with manual naming support.
- Timeline clip colours migrated from static hex to CSS variables with a legacy migration; removed style-card badges; pruned text-style presets.
- Caption templates consolidated into a single default layout.
