diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index d3c5f37..dc9ad40 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,7 +2,7 @@ import { onMount } from 'svelte'; import { env } from '$env/dynamic/public'; - // Svelte 5 Runes for Reactivity + // Svelte 5 Runes for Core Reactivity let photos = $state([]); let nextToken = $state(null); let loading = $state(false); @@ -10,18 +10,20 @@ let activePhoto = $state(null); let observerTarget; - // Lightbox Pan & Zoom Matrix State + // Lightbox Control Flags let isZoomed = $state(false); let lightboxContainer = $state(null); - let isDragging = $state(false); + let imageMatrixWrapper = $state(null); // Explicit ref to bypass reactive state lag + let isDragging = false; // Internal mutable flag (not a reactive rune) - // Coordinate state vectors for custom 2D transform panning - let panX = $state(0); - let panY = $state(0); + // Coordinate Vector Matrix (using raw numbers to bypass Svelte state loops on fast cycles) + let currentX = 0; + let currentY = 0; let startX = 0; let startY = 0; + let ticking = false; - // Touch tracking coordinates for mobile swipes + // Touch tracking coordinates for layout pagination swipes let touchStartX = 0; let touchEndX = 0; @@ -75,8 +77,11 @@ function resetZoom() { isZoomed = false; isDragging = false; - panX = 0; - panY = 0; + currentX = 0; + currentY = 0; + if (imageMatrixWrapper) { + imageMatrixWrapper.style.transform = `translate3d(0px, 0px, 0px)`; + } } function nextPhoto() { @@ -100,11 +105,11 @@ activePhoto = null; } if (e.key === 'ArrowRight' && !isZoomed) { - e.preventDefault(); // 👈 Stops the underlying grid buttons from changing focus + e.preventDefault(); nextPhoto(); } if (e.key === 'ArrowLeft' && !isZoomed) { - e.preventDefault(); // 👈 Stops the underlying grid buttons from changing focus + e.preventDefault(); prevPhoto(); } } @@ -118,34 +123,46 @@ } } - // Dynamic Pointer Interface Input Routing (Desktop Mouse & Mobile Touch Dragging) + // HIGH PERFORMANCE NATIVE INTERFACE PIPELINE (60FPS Engine) function pointerDown(clientX, clientY, target) { if (!isZoomed) return; if (target.tagName === 'BUTTON' || target.closest('button')) return; isDragging = true; - startX = clientX - panX; - startY = clientY - panY; + startX = clientX - currentX; + startY = clientY - currentY; } - function pointerMove(clientX, clientY, preventDefaultFunc) { + function pointerMove(clientX, clientY) { if (!isDragging) return; - if (typeof preventDefaultFunc === 'function') preventDefaultFunc(); - panX = clientX - startX; - panY = clientY - startY; + currentX = clientX - startX; + currentY = clientY - startY; + + // requestAnimationFrame schedules updates with the browser screen refresh cycle + if (!ticking) { + window.requestAnimationFrame(() => { + if (imageMatrixWrapper) { + imageMatrixWrapper.style.transform = `translate3d(${currentX}px, ${currentY}px, 0px)`; + } + ticking = false; + }); + ticking = true; + } } function pointerUp() { isDragging = false; } - // Desktop Mouse Adapters + // Desktop Mouse Interface Subscriptions function handleMouseDown(e) { pointerDown(e.clientX, e.clientY, e.target); } - function handleMouseMove(e) { pointerMove(e.clientX, e.clientY, () => e.preventDefault()); } + function handleMouseMove(e) { + if(isDragging) e.preventDefault(); + pointerMove(e.clientX, e.clientY); + } - // Mobile Touch Panning Adapters - // Mobile Touch Panning Adapters + // Mobile Touch Interface Subscriptions function handleTouchStart(e) { if (isZoomed) { const touch = e.touches[0]; @@ -156,9 +173,10 @@ } function handleTouchMove(e) { - if (isZoomed && e.touches.length === 1) { // 👈 Ensures single finger panning behaves correctly + if (isZoomed && e.touches.length === 1) { + e.preventDefault(); // Kill native momentum bouncing const touch = e.touches[0]; - pointerMove(touch.clientX, touch.clientY, () => e.preventDefault()); + pointerMove(touch.clientX, touch.clientY); } } @@ -218,7 +236,7 @@ onclick={(e) => { if (e.target === e.currentTarget) activePhoto = null; }} onkeydown={handleKeyDown} ontouchstart={handleTouchStart} - ontouchmove={handleTouchMove} + ontouchmove={handleTouchMove} ontouchend={handleTouchEnd} >
@@ -315,16 +333,17 @@ {/if}
Gallery Content Visual
+ class="max-h-[70vh] max-w-full rounded shadow-2xl select-none pointer-events-none transition-transform duration-200 ease-out will-change-transform" + style="transform: scale({isZoomed ? 3.8 : 1});" + /> +