From 52054c5d24f50abdb0fc99cebc43f0b25020cb54 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky <15040698+mmkal@users.noreply.github.com> Date: Wed, 26 Aug 2026 23:42:24 +0100 Subject: [PATCH] video-mode: snap a sliver of selector lead-in forward to the first highlight #40 clamped a selector trim start that landed AFTER a highlight. CI kept flaking on the mirror case: a start a sliver (36-92ms measured) BEFORE the first highlight. That sliver is raw footage from the recording's very first frames, and on a slow runner the screencast starts so late that those frames already show the action's result - the rendered video opened on the filled, expanded textarea one frame before the reveal's empty still (confirmed from the CI run's own raw/rendered artifacts: the 2.0s raw video has text at t=0.04s). A lead-in shorter than the fill stabilization window (max(0, timelineOffset) + 3 frames) is not worth keeping; open on the first highlight instead. Longer lead-ins are untouched. Co-Authored-By: Claude Fable 5 --- src/plugins/video-mode.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/plugins/video-mode.ts b/src/plugins/video-mode.ts index a7956b1..fc5dd3e 100644 --- a/src/plugins/video-mode.ts +++ b/src/plugins/video-mode.ts @@ -5612,6 +5612,26 @@ export const videoMode = (options: VideoModeOptions = {}): VideoModePlugin => { if (racedHighlightStarts.length > 0) { state.sourceRange.start = Math.min(...racedHighlightStarts); } + // The mirror case: a start a sliver BEFORE the first highlight. That + // sliver is raw footage from the recording's very first frames — + // exactly the frames a lagging screencast hasn't truthfully + // captured (on a slow runner the recorder's first frames can + // already show the action's result: a filled field before its + // reveal). A lead-in shorter than the fill stabilization window + // is not worth keeping; open on the first highlight instead. + const firstHighlightStart = Math.min( + ...highlights.map((candidate) => candidate.start), + ); + const leadInToleranceMs = + Math.max(0, timelineOffset) + + rawVideoInfo.frameDurationMs * VIDEO_MODE_FILL_PRE_ACTION_FRAME_PADDING; + if ( + Number.isFinite(firstHighlightStart) && + state.sourceRange.start < firstHighlightStart && + firstHighlightStart - state.sourceRange.start <= leadInToleranceMs + ) { + state.sourceRange.start = firstHighlightStart; + } } const annotationSourceRange = metadataFor(state).sourceRange; const sourceRange = translateSourceRange(annotationSourceRange, timelineOffset);