You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Speed regions are currently capped at 16× (MAX_PLAYBACK_SPEED = 16 in src/components/video-editor/types.ts). For long recordings this is limiting: condensing a 2-hour capture into a short timelapse segment needs far more than 16× (at 16× a 2 h 11 m recording still takes ~8 minutes). Desktop editors commonly allow much more: CapCut desktop goes to 100×, Premiere Pro's Speed/Duration dialog to 10,000 % (100×), Final Cut Pro accepts arbitrary custom rates.
I dug into why the cap exists, and it is not arbitrary — it is a hard Chromium engine limit, but one that only binds two of the three speed-handling paths:
Chromium hard-caps HTMLMediaElement.playbackRate to [0.0625, 16]. Verified on the exact engine Openscreen ships (Electron, Chromium 146):
v.playbackRate = 16 → ok
v.playbackRate = 16.1 → NotSupportedError: Failed to set the 'playbackRate' property on
'HTMLMediaElement': The provided playback rate (16.1) is not in
the supported playback range.
Two paths assign the region speed directly to playbackRate, so they inherit the cap:
Editor preview: videoEventHandlers.ts (video.playbackRate = activeSpeedRegion.speed), plus the webcam element and supplemental audio in VideoPlayback.tsx.
Export audio: audioEncoder.ts → renderPitchPreservedTimelineAudio() plays the timeline in real time through a hidden <audio> element (for preservesPitch) and captures it with MediaRecorder. Anything above 16× would throw.
The export video path is already unlimited.streamingDecoder.ts retimes frames offline (sourceTime = segmentStart + (frameIndex / fps) × speed), so 100× video export works today — it is only fenced off by the UI cap.
There is also a practical preview constraint noted in types.ts ("above 16× the decoder can't keep up and the playhead stalls"), which any solution needs to respect: real-time decode at 16× of a 60 fps recording is already ~960 fps.
Describe the solution you'd like
Raise the cap to 100× (the de-facto industry ceiling — ffmpeg's atempo audio filter, Premiere's audio time remapping, and CapCut all cap at 100) by taking the two playbackRate-bound paths off the real-time engine for fast segments:
Preview, segments > 16×: rAF-driven seek stepping. Instead of letting the media element play, advance the playhead by speed × Δt per animation frame and set video.currentTime to the target. Visually this is the fast-slideshow behaviour native NLEs show at extreme rates. The existing native-playback path stays untouched for ≤ 16× segments, so today's smooth preview is not affected.
Export audio, segments > 16×: drop real-time capture.
Phase 1 (pragmatic): render silence for > 16× segments. At those rates audio carries no usable information anyway, and this matches what users get from timelapse features elsewhere. Segments ≤ 16× keep the current pitch-preserved real-time path.
Phase 2 (optional follow-up): offline pitch-preserved time-stretch (WSOLA) in a worker fed by AudioDecoder, reusing the streaming infrastructure from fix: stream large local recordings so the editor and export don't exhaust memory #74. This would give real audio up to 100× and, as a bonus, could eventually replace the real-time capture path entirely (audio export would no longer take output-duration wall-clock time).
UI: raise MAX_PLAYBACK_SPEED to 100, keep the preset list as is, and let the custom-speed input accept up to 100. Optionally hint in the speed popover that > 16× segments preview as frame-stepping and export with silenced (Phase 1) audio.
Describe alternatives you've considered
Keep 16×: simplest, but condensing long recordings is a core screen-recording use case, and the video half of the work is already done.
A "timelapse" toggle instead of higher speeds: avoids the audio question entirely, but a unified speed control up to 100× is more discoverable and matches user expectations from other editors.
Additional context
Comparison of caps elsewhere:
Tool
Max speed
Approach
CapCut desktop
100×
offline retiming, offline audio stretch
Premiere Pro
10,000 % (time remapping 20,000 %)
offline; audio remap capped at 100×
Final Cut Pro
arbitrary custom
offline
ffmpeg
video unlimited (setpts); atempo 0.5–100
offline
Openscreen today
16×
real-time playbackRate
The pattern across tools: video retiming is effectively unlimited, ~100× is the recognised ceiling for meaningful audio, and every tool that exceeds 16× does so by not driving a real-time media element.
Search existing issues
Is your feature request related to a problem?
Speed regions are currently capped at 16× (
MAX_PLAYBACK_SPEED = 16insrc/components/video-editor/types.ts). For long recordings this is limiting: condensing a 2-hour capture into a short timelapse segment needs far more than 16× (at 16× a 2 h 11 m recording still takes ~8 minutes). Desktop editors commonly allow much more: CapCut desktop goes to 100×, Premiere Pro's Speed/Duration dialog to 10,000 % (100×), Final Cut Pro accepts arbitrary custom rates.I dug into why the cap exists, and it is not arbitrary — it is a hard Chromium engine limit, but one that only binds two of the three speed-handling paths:
Chromium hard-caps
HTMLMediaElement.playbackRateto[0.0625, 16]. Verified on the exact engine Openscreen ships (Electron, Chromium 146):Two paths assign the region speed directly to
playbackRate, so they inherit the cap:videoEventHandlers.ts(video.playbackRate = activeSpeedRegion.speed), plus the webcam element and supplemental audio inVideoPlayback.tsx.audioEncoder.ts→renderPitchPreservedTimelineAudio()plays the timeline in real time through a hidden<audio>element (forpreservesPitch) and captures it withMediaRecorder. Anything above 16× would throw.The export video path is already unlimited.
streamingDecoder.tsretimes frames offline (sourceTime = segmentStart + (frameIndex / fps) × speed), so 100× video export works today — it is only fenced off by the UI cap.There is also a practical preview constraint noted in
types.ts("above 16× the decoder can't keep up and the playhead stalls"), which any solution needs to respect: real-time decode at 16× of a 60 fps recording is already ~960 fps.Describe the solution you'd like
Raise the cap to 100× (the de-facto industry ceiling — ffmpeg's
atempoaudio filter, Premiere's audio time remapping, and CapCut all cap at 100) by taking the twoplaybackRate-bound paths off the real-time engine for fast segments:Preview, segments > 16×: rAF-driven seek stepping. Instead of letting the media element play, advance the playhead by
speed × Δtper animation frame and setvideo.currentTimeto the target. Visually this is the fast-slideshow behaviour native NLEs show at extreme rates. The existing native-playback path stays untouched for ≤ 16× segments, so today's smooth preview is not affected.Export audio, segments > 16×: drop real-time capture.
AudioDecoder, reusing the streaming infrastructure from fix: stream large local recordings so the editor and export don't exhaust memory #74. This would give real audio up to 100× and, as a bonus, could eventually replace the real-time capture path entirely (audio export would no longer take output-duration wall-clock time).UI: raise
MAX_PLAYBACK_SPEEDto 100, keep the preset list as is, and let the custom-speed input accept up to 100. Optionally hint in the speed popover that > 16× segments preview as frame-stepping and export with silenced (Phase 1) audio.Describe alternatives you've considered
AudioBufferSourceNode.playbackRate: no pitch preservation and requires decoding the full track into memory, which conflicts with the large-recording streaming work from fix: stream large local recordings so the editor and export don't exhaust memory #74.Additional context
Comparison of caps elsewhere:
setpts);atempo0.5–100playbackRateThe pattern across tools: video retiming is effectively unlimited, ~100× is the recognised ceiling for meaningful audio, and every tool that exceeds 16× does so by not driving a real-time media element.