Version 3.7.0
In-Place Take Cleanup, Streamlined Recorder UI
Recorder review adds in-place take cleanup, denoise, silence trim, a saved-take player, and a cleaner recording surface.
Major recorder release: takes can now be denoised and silence-trimmed in-place during review (before committing), the review surface reuses the actual silence-remover components instead of a parallel implementation, and the recorder UI is simplified by removing the top navbar in non-idle states.
Features
- In-place take cleanup — during review, toggle Background Noise Removal
and/or Silence Trim in the new TakeCleanupPanel (right sidebar). When you
click Keep, the Rust
apply_take_cleanuppipeline runs plan → denoise → cut → validate → commit, replacing the take’s source files on disk with cleaned versions. Validate-then-replace safety: originals are never deleted until all 7 checks pass on the new files. Orphan.cleaning.tmpfiles are swept on the next project load. - Review surface reuses silence-remover components — the review state now
mounts the real
SilencePlayerSlot,SilenceBottomPanel,WaveformTrack,SilenceOverlay, andDenoiseProgressDialogfrom the silence-remover feature. No parallel implementation — the take is projected onto a synthesized single-clip project viauseTakeAsSilenceProjectso the components find the data shape they expect. - Separate player surface for saved takes — clicking a committed take in
the filmstrip now opens
TakePlayerSurface, a lightweight native<video>+ Web Audio player with the custom PlaybackControls (waveform seek bar, reset, mute). No Remotion Player, no silence-remover stores, no DenoiseProgressDialog leaking into the saved-take view. - Streamlined recorder UI — the top navbar (
RecorderTopBar) now renders only in the idle slot. In recording, review, replay, and sequence states the bar is removed, reclaiming 56 px of vertical space for the canvas. The Help button and recording controls (Pause / Stop / Resume / Cancel) are relocated to theCanvasIdentityStrip. The DeviceStrip no longer appears during recording, preventing mid-take device changes (a known bug source). - Caption max width control — new per-phrase and project-level Max Width %
slider (30–100%) caps how far captions span horizontally before wrapping.
Available in the Phrase Inspector, Project Defaults Inspector, and per-overlay
Style Controls. The renderer’s
useTextLayouthonours the value viastyle.maxWidth. - “Focus” text style preset — new built-in preset: Inter 900, 42 px, 70% max width, black rectangle background, cumulative highlight mode.
Bug Fixes
- End-of-playback desync — Remotion’s
moveToBeginningWhenEndeddefaults totrue, causing an auto-rewind to frame 0 before firingended. The MediaPool saw frame 0 + stale PLAYING state → played all media for a full extra loop. Fixed with one prop:moveToBeginningWhenEnded={false}onSilencePlayer’s<Player>. Applies to both the silence-remover route and the recorder review surface. - Cleanup commits to the wrong file when denoise is on — the orchestrator
mutated
plan.mic.sourceto the denoised WAV path for the cut step.commit_planthen used that mutated path as the rename destination → cleaned m4a landed at.cleaning.tmp.denoised.wav→ orphan sweep deleted it → original mic.m4a untouched. Fixed by using a siblingmic_cut_inputvariable without mutating the plan. - FFmpeg cut filter failures — rewrote
cut_filefromaselect/select+between()predicates toatrim/trim+concat, which is robust to the edge cases that caused the old filter to occasionally pass through the full input. - Saved-take duration stale after cleanup —
gatedKeepnow patchespendingTake.duration_secswith the cleaned duration fromapply_take_cleanupbefore callingaddTake, preventing frozen-frame tails when the cleaned file is shorter than the original. - Autosave toast during review — the synthesized in-memory project for the
review bridge triggered the persistence layer’s autosave, which failed (no
on-disk folder) and surfaced the “Your changes are still in memory” toast.
Fixed by adding
inMemoryOnly: trueto the project metadata and early- returning insaveProjectData. - Spacebar only paused preview, not playhead — two shortcut handlers (RECORDER_SHORTCUTS + SILENCE_SHORTCUTS) both bound Space, racing each other. Fixed by dropping RECORDER_SHORTCUTS play/seek wiring entirely in the review surface — the silence-remover’s handler is the canonical one.
- Denoise never completes —
denoise.tspassedclip.file_path(screen video, no audio track) instead ofaudioSourceFor(clip)(mic.m4a) todenoise_for_analysis. FFmpeg hung on-vnof a video-only file. Fixed by centralizing audio/video source resolution intoaudioSourceFor()/videoSourceFor()insrc/lib/clip-source-resolver.ts. - Waveform all-red when silence toggle OFF — setting
clipSegments[clipId]to[]meant “no keep segments = everything is silence.” Fixed by setting a full-span keep segment[{start:0, end:duration}]when silence is disabled.
Refactoring
- Silence-remover PiP composition and renderers extracted into shared
src/lib/composition/— screen/webcam toggle removed,CanvasComposershared between silence-remover and recorder. DenoiseModePickerandSilenceControlsadapter extracted for reuse by the review cleanup panel.- Dead
Positionstruct removed fromsrc-tauri/src/assets/types.rs. - Centralized clip source resolution (
audioSourceFor/videoSourceFor) insrc/lib/clip-source-resolver.tswith 6 tests.
Tests
- 4 new tests for
cut_filetrim+concat filter shapes (single/multi × audio/video). - 6 tests for
audioSourceFor/videoSourceForfallback chains. - Existing
plan_tests,validate_tests,commit_tests,orphan_sweep_testscover the full cleanup pipeline.
