diff --git a/static/js/app.js b/static/js/app.js index 70e91a9..f103073 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -302,10 +302,17 @@ function hideSlideshow() { function loadSlide(slot, url) { const img = document.getElementById(`slide-${slot}`); - img.src = url; if (slot === activeSlot) { - // Slight delay lets the browser decode before fading in - requestAnimationFrame(() => requestAnimationFrame(() => img.classList.add('active'))); + // Only fade in once the image is fully decoded — no blank-then-flash + img.onload = () => { img.onload = null; img.classList.add('active'); }; + img.src = url; + // Handle cached images that won't fire onload + if (img.complete && img.naturalWidth > 0) { + img.onload = null; + img.classList.add('active'); + } + } else { + img.src = url; // preload only } } @@ -314,13 +321,20 @@ function advanceSlide() { const current = document.getElementById(`slide-${activeSlot}`); const next = document.getElementById(`slide-${nextSlot}`); - // Fade in the preloaded next image, fade out current - next.classList.add('active'); - current.classList.remove('active'); - activeSlot = nextSlot; + const doSwap = () => { + next.onload = null; + next.classList.add('active'); + current.classList.remove('active'); + activeSlot = nextSlot; + // Preload the upcoming photo into the now-hidden slot + slideIndex = (slideIndex + 1) % photos.length; + current.src = photos[(slideIndex + 1) % photos.length]; + }; - // Preload the one after next into the now-hidden slot - slideIndex = (slideIndex + 1) % photos.length; - const upcoming = photos[(slideIndex + 1) % photos.length]; - current.src = upcoming; + // If the preloaded image is ready, swap immediately; otherwise wait for it + if (next.complete && next.naturalWidth > 0) { + doSwap(); + } else { + next.onload = doSwap; + } }