fix(recording): preserve frame timing#33
Merged
Merged
Conversation
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
Preserve
ImageFrame.atMstiming when exporting constant-rate MP4 recordings, while reducing capture and filesystem work for dense or unchanged terminal output.Before / After
Before: FFmpeg received
-ras an input option over one concat entry per source frame. Irregular frames at 0 ms, 1000 ms, and 1200 ms encoded as three 5 FPS frames lasting 0.6 seconds, discarding the supplied timing. Replay also captured the complete terminal grid after every event, and equal snapshots with different object identities rendered separately.After: Drive samples source timestamps onto the requested CFR grid before invoking FFmpeg. The same input becomes seven 5 FPS frames lasting 1.4 seconds, with the final frame preserved. Replay captures lazily at sample boundaries, and structurally equal snapshots share one render key.
How
src/recording/encode.tsselects frames fromatMs, references unique PNGs directly from the concat manifest, and removes per-sample hardlinks.src/recording/replay.tscaptures terminal state only when a requested sample needs it.src/recording/export.tscaches a structural digest once per snapshot object so equal states deduplicate across identities.src/recording/frame-rate.tscentralizes the 60 FPS default and positive-finite validation.Scope
This keeps 60 FPS as the default and retains the existing custom
fpsquality/performance control. It does not change timeline capture, terminal rendering, or the public result shape.Testing
bun run test:effect test/recording/export.test.ts test/recording/replay.test.ts test/recording/export-dedupe.test.ts(23 passed)bun run test:effect(147 passed)bun run test:cli(51 passed)bun run lintbun run typecheckbun pm pack --dry-runFlow