gallery animation : reveal only once all images are loaded. related to #55
All checks were successful
Deploy / Deploy to Production (push) Successful in 21s

Preload unique image URLs via new Image(). Container stays at opacity:0
until all are ready, then reveals at once. Cached images show instantly
(no fade transition). Fixes broken progressive reveal in scrolling gallery.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-04-03 12:28:31 +02:00
parent 9d7fca4d91
commit cc61a83139

View file

@ -7,8 +7,35 @@
* @prop {number} secondsPerImage — durée par image (défaut: 8s)
* @prop {'vertical'|'horizontal'} mode — direction du défilement
*/
import { onMount } from 'svelte'
let { images = [], secondsPerImage = 8, backgroundColor = null, backgroundImage = null, mode = 'vertical' } = $props()
let containerEl = $state(null)
let allLoaded = $state(false)
let needsFade = $state(false)
// Wait for all unique source images to load before revealing
onMount(() => {
const uniqueSrcs = new Set(images.map(img => img.src).filter(Boolean))
if (uniqueSrcs.size === 0) { allLoaded = true; return }
let remaining = uniqueSrcs.size
const done = () => { if (--remaining <= 0) allLoaded = true }
for (const src of uniqueSrcs) {
const img = new Image()
img.src = src
if (img.complete) {
done()
} else {
needsFade = true
img.onload = done
img.onerror = done
}
}
})
const columns = $derived.by(() => {
const count = images.length
const duration = count * secondsPerImage
@ -40,6 +67,8 @@
<div
class="gallery-animation gallery-animation--{mode}"
class:gallery-animation--ready={allLoaded}
class:gallery-animation--fade={needsFade}
style="--gallery-duration: {columns[0]?.duration ?? 24}s{backgroundColor ? `; --background-color: ${backgroundColor}` : ''}{backgroundImage ? `; --gallery-background-image: url(${backgroundImage})` : ''}"
>
<div class="gallery-animation__overlay"></div>
@ -80,9 +109,17 @@
overflow: hidden;
background-color: var(--background-color, transparent);
background-image: var(--gallery-background-image);
opacity: 0;
}
.gallery-animation--ready {
opacity: .8;
}
.gallery-animation--fade.gallery-animation--ready {
transition: opacity 0.4s ease;
}
.gallery-animation__overlay {
position: absolute;
inset: 0;