diff --git a/frontend/src/components/preview/PreviewView.tsx b/frontend/src/components/preview/PreviewView.tsx index 1a09dbe..dcf5937 100644 --- a/frontend/src/components/preview/PreviewView.tsx +++ b/frontend/src/components/preview/PreviewView.tsx @@ -138,13 +138,17 @@ export function PreviewView() { useHotkeys('right', goNext, { preventDefault: true }) useHotkeys('i', () => setInfoPanelOpen((v) => !v), { preventDefault: true }) - // Preload the immediate neighbors so arrow nav feels instant. Skip videos - // (browsers can't preload them via Image()) and skip when at the edges. + // Preload the ±5 neighbor thumbnails so arrow nav feels instant. Cheap + // because getPreviewImageSrc returns the 1280px thumb; the current photo's + // full-res /proxy upgrade is handled separately inside PreviewImage. Skip + // videos (browsers can't preload them via Image()) and clamp to bounds. useEffect(() => { - const neighbors: Photo[] = [] - if (safeIndex > 0) neighbors.push(photos[safeIndex - 1]) - if (safeIndex < photos.length - 1) neighbors.push(photos[safeIndex + 1]) - for (const p of neighbors) { + const PRELOAD_RADIUS = 5 + const start = Math.max(0, safeIndex - PRELOAD_RADIUS) + const end = Math.min(photos.length - 1, safeIndex + PRELOAD_RADIUS) + for (let i = start; i <= end; i++) { + if (i === safeIndex) continue + const p = photos[i] if (isVideo(p)) continue const img = new Image() img.src = getPreviewImageSrc(p)