From 47d41b4a617c59644d01c5023b3dbffdeb54571c Mon Sep 17 00:00:00 2001 From: Ludwig Mey Date: Wed, 26 Aug 2026 13:09:00 +1200 Subject: [PATCH] =?UTF-8?q?Fix=20slideshow=20stalling=20=E2=80=94=20replac?= =?UTF-8?q?e=20transitionend=20with=20setTimeout=20for=20preload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit transitionend is unreliable: if the Pi's display sleeps or a transition is interrupted, the event never fires and the next slot's src is never set. advanceSlide then waits forever on an onload that can't fire. Replace with a 1600ms setTimeout (just past the 1.5s CSS transition) which always fires. Also add a guard to kick-start the src if it's blank when advanceSlide runs. Co-Authored-By: Claude Sonnet 4.6 --- static/js/app.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/static/js/app.js b/static/js/app.js index 538a353..fa7cd80 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -328,15 +328,21 @@ function advanceSlide() { activeSlot = nextSlot; slideIndex = (slideIndex + 1) % photos.length; const preloadSrc = photos[(slideIndex + 1) % photos.length]; - // Only change src after the fade-out completes — changing it mid-transition - // causes the new image to appear at partial opacity (the flash the user sees) - current.addEventListener('transitionend', () => { current.src = preloadSrc; }, { once: true }); + // Wait for the fade-out transition to finish before preloading the next src. + // transitionend is unreliable (can be skipped if display sleeps), so use + // a plain timeout just past the 1.5s CSS transition as the trigger. + setTimeout(() => { current.src = preloadSrc; }, 1600); }; - // If the preloaded image is ready, swap immediately; otherwise wait for it + // If the preloaded image is ready, swap immediately; otherwise wait for it. + // Guard against a stuck onload by also setting src explicitly if needed. if (next.complete && next.naturalWidth > 0) { doSwap(); } else { + if (!next.src || next.src === window.location.href) { + // src was never set (stalled state) — kick it off now + next.src = photos[(slideIndex + 1) % photos.length]; + } next.onload = doSwap; } }