Skip to the content

Scroll image sequence

The product film that plays under the wheel.

Become a member to unlock the full effect today.

Join now

Already a member? Sign in

Documentation

  1. Copy to Webflow

    Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed.

  2. Add custom CSS

    Three things belong to the page rather than to the component: the section takes no height of its own, its height being one screen plus the scroll the sequence takes; no parent of the section may cut its overflow with overflow: hidden, which stops the block from pinning, so use overflow-x: clip where a parent has to cut; and the frames need an address that keeps their file names when they are given as a pattern, which the Assets panel of Webflow does not.
  3. Add custom JS

  4. Tune it

    Custom attributes
    Select the section on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.
    Custom attributeWhat it does
    data-scroll-sequence Marks the section the page scrolls through while the picture plays. It takes no value: leave the value field empty. That section is what the stylesheet makes taller by the scroll the sequence takes, and what carries the settings. Without it on any element of the page, the embed marks the block holding the screen.
    data-scroll-sequence-pin Marks the block that stays on screen, a child of the section: the canvas goes behind what it holds. It takes no value. Without it the engine takes the first block of the section. [ Optional ]
    data-scroll-sequence-frames Marks the box whose pictures are the frames, in the order of the page: swap them, add some, take some out. It takes no value and is never shown. Not needed when the section gives an address and a count with data-scroll-sequence-src and data-scroll-sequence-count; without either, there is no frame and the console says so. [ Optional ]
    data-scroll-sequence-beat="0.36 0.62" Marks a text that comes and goes: the share of the sequence where it comes, then the share where it leaves, 0 the first frame and 1 the last. A second number of 1 keeps it to the end. [ Optional ]
    data-scroll-sequence-loader Marks what shows while the frames come in: it is hidden once they are all in. It takes no value. [ Optional ]
    data-scroll-sequence-bar Marks a rule the load fills: it is scaled across by the share of frames that have arrived. It takes no value. [ Optional ]
    data-scroll-sequence-loaded Marks a text that receives the share of frames that have arrived, 37% for instance. It takes no value. [ Optional ]
    data-scroll-sequence-frame Marks a text that receives the number of the frame on screen. It takes no value. [ Optional ]
    data-scroll-sequence-total Marks a text that receives how many frames the sequence has. It takes no value. [ Optional ]
    data-scroll-sequence-track Marks a rule the scroll fills: it is scaled across by the place in the sequence. It takes no value. [ Optional ]
    data-scroll-sequence-alt="A ream of paper opening" On the section: the name assistive technology reads for the picture. Without it the canvas takes the alt of the first picture of the frames box, and is skipped as a decoration when there is none. [ Optional ]
    data-scroll-sequence-state Written by the engine on the section: idle until the section is near the window, loading while the frames come in, ready once they are all in, still under reduced motion. Never written by hand; it is what the stylesheet reads to pin the block and to hide the loader. [ Optional ]
    data-scroll-sequence-beat-state Written by the engine on each beat: before, on or after. Never written by hand; the stylesheet reads it to bring the beat in and out. [ Optional ]
    Settings
    Every setting is a custom attribute too, added the same way and on the same section. An attribute always wins over the defaults written in the code.
    AttributeDefaultWhat it is
    data-scroll-sequence-background #0e0b09 Colour of the block behind the frames: what shows before the first frame arrives, and around the picture when fit is contain. Options: any CSS colour. Give it the colour the frames have at their edges and the picture has no seam.
    data-scroll-sequence-src empty Address of the first frame, with its number in braces: https://your.host/shot-{001}.webp. The number in the braces is where the count starts and how many digits it is written with. Options: left empty, the frames are the pictures of the box marked data-scroll-sequence-frames, in the order of the page. {001} counts 001, 002, 003; {0} counts 0, 1, 2; {0100} starts at 0100.
    data-scroll-sequence-count 0 How many frames the address names. Only read with src.
    data-scroll-sequence-length clamp(1600px, 420vh, 5200px) Scroll the sequence takes, any CSS length: how long the block holds the screen.
    data-scroll-sequence-smooth 0.16 Time the picture takes to catch the scroll, in seconds.
    data-scroll-sequence-fit cover How a frame fills the screen: cover or contain. Options: cover fills the block and crops what does not fit, contain shows the whole frame and leaves background around it.
    data-scroll-sequence-focus-x 0.5 Point of the frame kept in view across, 0 its left edge and 1 its right, when cover crops the sides.
    data-scroll-sequence-focus-y 0.5 Point of the frame kept in view down, 0 its top and 1 its foot, when cover crops the top and the foot.
    data-scroll-sequence-blend on Cross-fade between two neighbouring frames while the picture moves: on or off. Options: on draws the two frames around the place in the scroll, one over the other, so few frames still make one move; off shows one frame at a time, for a sequence with hard cuts or fine line work that ghosts.
    data-scroll-sequence-density 2 Most canvas pixels per CSS pixel. The bitmap follows the screen up to this.
    data-scroll-sequence-poster 0 Frame shown under reduced motion, as a share of the sequence, 0 the first and 1 the last.

What it does

Scroll image sequence is a scroll animation for Webflow and vanilla JavaScript, with no library. Also called image sequence on scroll, scroll scrubbed video or canvas image sequence.

The product film that plays under the wheel. A section holds the screen while the page scrolls through it, and its picture is a sequence of frames: the scroll decides which one is shown, forwards and back, eased towards the wheel instead of snapped to it. The frames are drawn on a canvas laid out like object-fit cover, with a focal point to keep in view when a phone crops the sides, and a bitmap that follows the pixel density of the screen. Two neighbouring frames are cross-faded while the picture moves, so a short sequence still reads as one move, and the picture always comes to rest on a whole, sharp frame. The frames load in passes, the one on screen first, then one in sixteen, in eight, in four, so the whole move is there, coarse, long before the last file; a loader says how many are in, counted, not guessed. Texts marked as beats come and go at given points of the sequence. The frames are given either as an address pattern and a count, or as the pictures of a box of the page, which is how a Webflow site keeps them in its own assets. No library: the hold is sticky positioning, the position is read from the layout, so it follows the browser's own scroll and a smooth scroll library alike. Under reduced motion there is no pin and no sequence: one frame, the only one downloaded, and every text on the page. Pattern type image sequence, scroll scrubbed video, product reveal.

Updated

Questions

Mark a section data-scroll-sequence and the block that stays on screen inside it data-scroll-sequence-pin. Keep the frames as Images in a box marked data-scroll-sequence-frames, in the order of the page: Webflow renames every asset it stores, so an address pattern cannot point at them. The box is never shown, and the engine asks for the files itself.

No. The hold is CSS sticky positioning and the place in the sequence is read from the layout, so it follows the browser's own scroll and a smooth scroll library alike, with no library loaded. The picture is numbered stills drawn on one canvas, not a video: the preview plays 96 WebP frames of 1600 by 1200, 2.3 MB in all.

100 to 150 frames is the usual range; under 40 the cross-fade between two frames starts to show as a ghost on a fast move. data-scroll-sequence-length is the scroll the sequence takes, and around 30 to 50 pixels of scroll per frame reads well. The whole set is downloaded, nothing is streamed, so weigh the folder before raising the count.

Give any block inside the section data-scroll-sequence-beat="0.36 0.62", the share of the sequence where it comes and the share where it leaves. The engine writes data-scroll-sequence-beat-state on it, before, on or after, and the stylesheet does the move. A beat whose second number is 1 stays to the end.

An ancestor with overflow: hidden becomes the scroll container of the sticky block, and a container that does not scroll has nowhere to pin. Use overflow-x: clip where a parent has to cut; the engine says so in the console when it finds one. Give the section no height of its own either: its height is one screen plus the length of the sequence.