feat(editor): add playback speed multiplier for time-lapse export - #19
Open
adisagar2003 wants to merge 3 commits into
Open
adisagar2003 wants to merge 3 commits into
adisagar2003 wants to merge 3 commits into
Conversation
Pure output-frame to source-time mapping used by the exporters, plus the repo's first test target (host-less, Swift Testing) and a make test target. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a 1x-16x speed setting to the editor's Video tab. Export keeps reading every source sample but emits fewer frames: writer PTS stays frameIndex/fps while the reader cursor and renderer clock advance at outputTime * speed, so cursor, zoom, captions and all regions keep being sampled in source time and need no remapping. Speed above 1x forces the compositor path and drops audio (system, mic, noise reduction and click sounds), since sped-up audio is unusable and time-scaling it was removed in v0.14.6. Preview applies the same multiplier to the player rate. The timeline stays in source seconds; the panel shows the resulting export length. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…k sounds - clamp(-.infinity) returned 16x instead of 1x - speed panel reported the untrimmed asset length as the export length; it now uses the same source span the exporter does (trim, or video regions) - click sound generation guards on speed itself instead of being passed a nil cursor snapshot, matching how mic noise reduction opts out - needsCompositor compares the clamped speed, so an out-of-range value in project.json no longer forces a pointless re-encode - footnote no longer claims audio was removed from silent recordings - test target gets runpath search paths; added a direct clamp test Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
adisagar2003
marked this pull request as ready for review
September 11, 2026 20:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a time-lapse speed multiplier (1x–16x) to the editor's Video tab. The exported video is
shortened by that factor:
duration_out = duration_in / speed.There's currently no way to speed a recording up, so a long build-along or refactor session can
only be exported at 1x.
How
The three exporters are hand-rolled
AVAssetReader → FrameRenderer → AVAssetWriterloops whereoutput time, composition time and source time are the same value. This change decouples the
writer clock from the source clock and nothing else:
FrameRendererkeeps receiving source-domain composition time, so cursor metadata, zoomkeyframes, captions, camera/video/spotlight regions and transition durations all keep working
untouched — no changes in
RegionRemapping,CompositionInstructionorFrameRenderer. That'swhy this seam was chosen over
composition.scaleTimeRange(...), which would desync thosedomains.
reader.timeRangestill covers the full trim, so every source sample is still read.Speed above 1x:
checkNeedsCompositor) — passthrough can't resample;usable and time-scaling it was deliberately removed in v0.14.6 (22dc93c), so it isn't
reintroduced here.
Preview applies the same multiplier to the player rate (multiplied onto the existing drift
ratios, not assigned over them) and mutes audio above 1x. The timeline stays in source seconds —
only the export gets shorter — and the panel shows the resulting length.
Tests
TimeLapseholds all the arithmetic and is covered by unit tests, including the two cases thatwould otherwise bite: degenerate speeds (0 / negative / NaN → division by zero) and the last
frame never reading past the source duration.
ReframedTests, host-less so it doesn't launch theapp, Swift Testing) plus
make test. Happy to split that into its own PR, or drop it, if you'drather keep the project test-free.
Verification status
Not compiled by me: I don't have Xcode on this machine, only the Command Line Tools, so
make build/make testnever ran here. Flagging that up front rather than burying it. Whatwas verified:
TimeLapselogic: unit tests run green through a standalone SPM harness, and mutation-checked(flipping
ceil→floorand dropping the speed factor both make them fail).swiftc -parse, andswift formatis clean.Still needs a real build + an export check:
ffprobe), with cursor/zoom/captionsstill landing on the same on-screen events
AVPlayercan refuse rates above 2 for items that don't support fastforward, which would silently stall playback rather than error
Not included