diff --git a/components/sections/PuntosInflexion.tsx b/components/sections/PuntosInflexion.tsx index 4ff8e39..3d4d36c 100644 --- a/components/sections/PuntosInflexion.tsx +++ b/components/sections/PuntosInflexion.tsx @@ -80,6 +80,17 @@ function Escenificado() { // frame is a dozen lines, needs no measurement pass from the library, and can // be verified in the browser, which the black box could not. const bruto = useMotionValue(0); + + // Whether the stage is close enough to be worth paying for its photographs. + // Measured on the static export: the six of them are 1,24 MB and every one + // was downloading before the reader had scrolled a pixel — `loading="lazy"` + // did not save us, because Chrome's distance threshold is generous enough to + // swallow a section that starts under 2.000px down. Two megabytes before the + // first gesture, on a page that gets opened from a WhatsApp link on mobile + // data. + const [cerca, setCerca] = useState(false); + const yaCerca = useRef(false); + useEffect(() => { let pendiente = 0; const medir = () => { @@ -89,6 +100,12 @@ function Escenificado() { const { top, height } = el.getBoundingClientRect(); const recorrido = height - window.innerHeight; bruto.set(recorrido > 0 ? Math.min(1, Math.max(0, -top / recorrido)) : 0); + // Latch, never unset: the images are cached by then, and flipping it back + // would tear down the stage every time the reader scrolled past. + if (!yaCerca.current && top < window.innerHeight * 1.25) { + yaCerca.current = true; + setCerca(true); + } }; const alScroll = () => { if (!pendiente) pendiente = requestAnimationFrame(medir); @@ -138,8 +155,11 @@ function Escenificado() {
{/* The photograph of whichever point is on screen, crossfading with - the beat. Only the active one is opaque; the rest sit at zero, so - the browser still holds them decoded and the swap costs nothing. */} + the beat. Only the neighbours of the active scene are mounted: + the next one is in the document a whole scene before it is needed, + which is time enough to arrive, and the far ones cost nothing. + Mounting all six was 1,24 MB spent up front for five pictures the + reader might never reach. */} {items.map((item, i) => ( - - - + {cerca && Math.abs(i - activo) <= 1 && ( + + + + )} ))}