diff --git a/components/timeline/TimeScale.tsx b/components/timeline/TimeScale.tsx index 366ad1a..7051140 100644 --- a/components/timeline/TimeScale.tsx +++ b/components/timeline/TimeScale.tsx @@ -42,10 +42,16 @@ export function TimeScale({ // Calculate total timeline width (match waveform calculation) // Uses 5 pixels per second as base scale, multiplied by zoom + // Always ensure minimum width is at least viewport width for full coverage const PIXELS_PER_SECOND_BASE = 5; const totalWidth = React.useMemo(() => { - return duration * zoom * PIXELS_PER_SECOND_BASE; - }, [duration, zoom]); + if (zoom >= 1) { + const calculatedWidth = duration * zoom * PIXELS_PER_SECOND_BASE; + // Ensure it's at least viewport width so timeline always fills + return Math.max(calculatedWidth, viewportWidth); + } + return viewportWidth; + }, [duration, zoom, viewportWidth]); // Update viewport width on resize React.useEffect(() => { diff --git a/components/tracks/Track.tsx b/components/tracks/Track.tsx index 2453737..4075b13 100644 --- a/components/tracks/Track.tsx +++ b/components/tracks/Track.tsx @@ -329,7 +329,17 @@ export function Track({ const buffer = track.audioBuffer; const channelData = buffer.getChannelData(0); - const samplesPerPixel = Math.floor(buffer.length / (width * zoom)); + // Calculate samples per pixel based on the total width + // Must match the timeline calculation exactly + const PIXELS_PER_SECOND_BASE = 5; + let totalWidth; + if (zoom >= 1) { + const calculatedWidth = duration * zoom * PIXELS_PER_SECOND_BASE; + totalWidth = Math.max(calculatedWidth, width); + } else { + totalWidth = width; + } + const samplesPerPixel = buffer.length / totalWidth; // Draw waveform ctx.fillStyle = track.color; diff --git a/components/tracks/TrackList.tsx b/components/tracks/TrackList.tsx index c447ccf..4a3f407 100644 --- a/components/tracks/TrackList.tsx +++ b/components/tracks/TrackList.tsx @@ -170,12 +170,7 @@ export function TrackList({ }); setSyncingScroll(false); - - // Also call the external callback if provided - if (onTimeScaleScroll) { - onTimeScaleScroll(); - } - }, [syncingScroll, onTimeScaleScroll]); + }, [syncingScroll]); // Expose the scroll handler via ref so AudioEditor can call it React.useEffect(() => {