What you just scrolled through

Everything on this page is static files on a CDN — frames, one spritesheet, three hold loops and a pan schedule. There is no server, no database and no build step. That is deliberate: the library takes a list of URLs, and where they come from is your business.

Three-layer loading

A 2.8 MB spritesheet makes it scrollable in a second; full-resolution frames stream in behind it and cover as they land.

Hold loops

At frames 1, 61 and 150 the sequence pins and a short loop plays on top. Ping-pong, so there is no seam to hide.

Portrait pan

On a phone, a keyframe schedule moves the crop window so a 16:9 frame survives a 9:16 viewport. A few hundred bytes, no second asset set. Open this page on a phone — or narrow the window past 768 px — for a Fit / Fill / Follow switch that shows the three ways to resolve the crop.

Zero dependencies

~530 lines of JavaScript. No framework, no canvas, no build. Scroll never touches framework state.

npm install scroll-frame-sequence

The source, the Python tools that turn a video into these frames, and a page of the numbers we estimated wrong are all on GitHub.