From a27925e8cbe97b3219437608b40432e886782316 Mon Sep 17 00:00:00 2001 From: skal Date: Thu, 12 Feb 2026 13:26:22 +0100 Subject: Timeline editor: fix seek position when zoomed Use helper functions (beatsToTime, timeToBeats) consistently in click handlers. Fixes red cursor jumping to wrong position during seek. Co-Authored-By: Claude Sonnet 4.5 --- tools/timeline_editor/index.html | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/timeline_editor/index.html b/tools/timeline_editor/index.html index 2c66ddd..402c580 100644 --- a/tools/timeline_editor/index.html +++ b/tools/timeline_editor/index.html @@ -852,15 +852,15 @@ if (!state.audioBuffer) return; const rect = dom.waveformContainer.getBoundingClientRect(); const clickX = e.clientX - rect.left + dom.timelineContent.scrollLeft; - const clickTime = (clickX / state.pixelsPerSecond) * 60.0 / state.bpm; + const clickBeats = clickX / state.pixelsPerSecond; + const clickTime = beatsToTime(clickBeats); const wasPlaying = state.isPlaying; if (wasPlaying) stopPlayback(false); state.playbackOffset = Math.max(0, Math.min(clickTime, state.audioDuration)); - const clickBeats = state.playbackOffset * state.bpm / 60.0; - dom.playbackTime.textContent = `${state.playbackOffset.toFixed(2)}s (${clickBeats.toFixed(2)}b)`; - const indicatorX = clickBeats * state.pixelsPerSecond; - dom.playbackIndicator.style.left = `${indicatorX}px`; - dom.waveformPlaybackIndicator.style.left = `${indicatorX}px`; + const pausedBeats = timeToBeats(state.playbackOffset); + dom.playbackTime.textContent = `${state.playbackOffset.toFixed(2)}s (${pausedBeats.toFixed(2)}b)`; + const indicatorX = pausedBeats * state.pixelsPerSecond; + dom.playbackIndicator.style.left = dom.waveformPlaybackIndicator.style.left = `${indicatorX}px`; if (wasPlaying) await startPlayback(); }); @@ -917,15 +917,16 @@ if (e.target !== dom.timeline) return; const timelineRect = dom.timeline.getBoundingClientRect(); const clickX = e.clientX - timelineRect.left + dom.timelineContent.scrollLeft; - const clickBeats = clickX / state.pixelsPerSecond, clickTime = clickBeats * 60.0 / state.bpm; + const clickBeats = clickX / state.pixelsPerSecond; + const clickTime = beatsToTime(clickBeats); if (state.audioBuffer) { const wasPlaying = state.isPlaying; if (wasPlaying) stopPlayback(false); state.playbackOffset = Math.max(0, Math.min(clickTime, state.audioDuration)); - const pausedBeats = state.playbackOffset * state.bpm / 60.0; + const pausedBeats = timeToBeats(state.playbackOffset); dom.playbackTime.textContent = `${state.playbackOffset.toFixed(2)}s (${pausedBeats.toFixed(2)}b)`; const indicatorX = pausedBeats * state.pixelsPerSecond; - dom.playbackIndicator.style.left = `${indicatorX}px`; dom.waveformPlaybackIndicator.style.left = `${indicatorX}px`; + dom.playbackIndicator.style.left = dom.waveformPlaybackIndicator.style.left = `${indicatorX}px`; if (wasPlaying) await startPlayback(); showMessage(`Seek to ${clickTime.toFixed(2)}s (${clickBeats.toFixed(2)}b)`, 'success'); } -- cgit v1.2.3