fix(engine): hold last frame when a clip's media is shorter than its slot (#1726)

Renders showed the page background (a one-frame black flash) right before a cut
when a video clip's source media was a hair shorter than its data-duration slot
— the common case, since `ffmpeg -t 1.45` emits 43 frames = 1.433s at 30fps.
The frame lookup only held the last frame at the exact clip end, so the
sub-frame remainder rendered blank.

- Hold the last extracted frame for the rest of the slot once the source is
  exhausted, within a tolerance floored at the compiler's 0.05s clamp epsilon so
  the seam is covered at any fps (2 frames alone is < 0.05s above 40fps). Clips
  deliberately much shorter than their slot still blank for the tail (unchanged).
- Warn when the compiler clamps a video's data-duration down to its media length
  (slot longer than source by more than the clamp epsilon): a render-time
  `[compile]` warning in the producer, plus a matching `validate` warning that
  reads each <video>'s live duration in headless Chrome (static HTML lint can't
  see media durations). A shared `analyzeClipMediaFit` keeps both on one
  threshold.

Adds engine unit tests for the hold behavior and the analyzer.
This commit is contained in:
Miguel Ángel
2026-06-25 19:16:27 -04:00
committed by GitHub
parent 764aa02a3a
commit 92385711dc
8 changed files with 195 additions and 11 deletions
+4 -2
View File
@@ -48,8 +48,10 @@ export interface CompilationResult {
unresolved: UnresolvedElement[];
}
// ffprobe precision can differ slightly across local and CI media stacks.
const MEDIA_DURATION_CLAMP_EPSILON_SECONDS = 0.05;
// ffprobe precision can differ slightly across local and CI media stacks. Also
// the floor for the engine's hold-last-frame tolerance (a slot left unclamped is
// short by at most this), so they must move together.
export const MEDIA_DURATION_CLAMP_EPSILON_SECONDS = 0.05;
export function shouldClampMediaDuration(declaredDuration: number, maxDuration: number): boolean {
return declaredDuration > maxDuration + MEDIA_DURATION_CLAMP_EPSILON_SECONDS;
+1
View File
@@ -135,6 +135,7 @@ export {
extractResolvedMedia,
clampDurations,
shouldClampMediaDuration,
MEDIA_DURATION_CLAMP_EPSILON_SECONDS,
} from "./compiler/timingCompiler";
// Lint