From 43bd3d07c28b849bf6ea3cbd71309100eceb3691 Mon Sep 17 00:00:00 2001 From: you Date: Thu, 19 Mar 2026 07:01:01 +0000 Subject: [PATCH] Fix VCR scrubber: pause after replay ends, hold playhead position Two root causes fixed: 1. startReplay() was calling vcrResumeLive() when buffer exhausted, snapping back to LIVE mode. Now pauses instead. 2. updateTimelinePlayhead() recalculated position from timestamps relative to now (which shifts). Now holds at dragPct position when paused after a scrub. --- public/live.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/public/live.js b/public/live.js index d3a4c86a..1739af34 100644 --- a/public/live.js +++ b/public/live.js @@ -162,8 +162,8 @@ function tick() { if (VCR.mode !== 'REPLAY') return; if (VCR.playhead >= VCR.buffer.length) { - // Caught up — go live - vcrResumeLive(); + // Caught up — pause instead of auto-resuming live + vcrSetMode('PAUSED'); return; } const entry = VCR.buffer[VCR.playhead]; @@ -342,17 +342,18 @@ // Redraw sparkline (cheap, avoids double-buffer complexity) // Just draw playhead line on top — clear only the line area - let playTs; + let x; if (VCR.mode === 'LIVE' || VCR.playhead < 0) { - playTs = now; - } else if (VCR.playhead < VCR.buffer.length) { - playTs = VCR.buffer[VCR.playhead].ts; + x = cw; // rightmost = now + } else if (VCR.playhead >= 0 && VCR.playhead < VCR.buffer.length) { + const playTs = VCR.buffer[VCR.playhead].ts; + x = ((playTs - startTs) / scopeMs) * cw; + } else if (VCR.mode === 'PAUSED' && VCR.dragPct != null) { + // After scrub, hold at last drag position + x = VCR.dragPct * cw; } else { - playTs = now; + x = cw; } - - const x = ((playTs - startTs) / scopeMs) * cw; - // We overlay a playhead marker — use a separate tiny canvas or just draw const playheadEl = document.getElementById('vcrPlayhead'); if (playheadEl) { playheadEl.style.left = Math.max(0, Math.min(cw - 2, x)) + 'px';