Why the export loop is driven by output frames
Ask what moment belongs in frame n, rather than asking what to do with the frame that just arrived. Cuts, mismatched frame rates and a camera that opened late all stop being special cases.
There are two ways to write an exporter. The obvious one reads frames from the inputs and decides what to do with each. The other asks, for every frame of the result, what moment of the recording belongs there and pulls the readers forward to it.
The second is slightly harder to picture and dramatically easier to keep correct. Prequel does the second.
The obvious version, and where it breaks
Input-driven means the loop is over what arrives. A screen frame shows up, so you write a screen frame. A camera frame shows up two thirds as often, because the camera is 30 fps and the screen is 60, so you write it every other time — except the camera also dropped four frames when the laptop got warm, and now "every other time" is wrong for the rest of the file.
Then there are cuts. The user removed 1.2 seconds from the middle. Input-driven, that means every frame after the cut needs its timestamp rewritten, and the two video streams need their rewrites to agree, and the audio needs the same treatment with a different sample rate. Each of those is a resampler you now own.
None of these are exotic. Mismatched frame rates, dropped frames, a camera that opened late and a cut in the middle are what an ordinary recording looks like.
Output-driven
The loop runs over the frames of the result:
for each frame n of the output:
t = n / output_fps // where we are in the finished video
source_t = timeline.locate(t) // where that is in the recording
screen = screen_reader.frame_at(source_t)
camera = camera_reader.frame_at(source_t)
composite and write
Cuts live entirely inside locate. It maps a moment in the export to a moment
in the take, and a removed span is just a discontinuity in that mapping. Nothing
downstream knows a cut happened.
Mismatched frame rates stop existing as a concept. Each reader is asked for the
frame covering source_t and answers with whatever it has; a 30 fps camera
against a 60 fps output naturally returns the same frame twice, which is exactly
right and required no branch.
A camera that opened late is one addition inside its reader — the manifest offset — and dropped frames are invisible, because nobody was counting frames in the first place.
The part that matters at the other end
The output is constant frame rate. Every frame is 1/fps after the last one,
because the loop generated it that way rather than inheriting whatever cadence
the inputs happened to have.
This is not a nicety. The editor's preview assumes constant frame rate — it computes the frame to show from elapsed time. If the export were variable, the preview and the file would land on different frames at the same timestamp, and every zoom keyframe you set against the preview would be a frame or two off in the result. The kind of wrong that survives review.
Animation folds into the same idea
Cursor motion, zoom curves and perspective quads are sampled into the render plan as keys before either rasteriser sees it. The preview and the exporter interpolate numbers; neither one knows what a zoom is.
Which means the answer to "does the zoom look the same in the export?" is not "we tested it". It is "there is only one implementation".