Skip to the content

Velocity marquee

A ribbon of content runs on without end, and the page scroll drives it: it cruises on its own when nothing is happening, gains speed as the reader scrolls down, runs back the other way when the reader scrolls up, and leans a little while it is being pulled, standing upright again the moment it settles.

Create a free account to unlock it.

Sign up free

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

    The space between two items belongs to the items, as a padding or a margin on each of them, so the rhythm holds where two copies join. A row that spaces its items with a flex gap has no space at that join: give --velocity-marquee-gap the same length, or move the space onto the items.
  3. Add custom JS

  4. Use it on your own elements

    Custom attributes
    Select the element 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-velocity-marquee Marks the box the ribbon runs behind. It takes no value: leave the value field empty. That box is what clips the content, what the effect is mounted on and what carries the settings. Without it nothing is mounted anywhere, and the embed says so in the console.
    data-velocity-marquee-track Marks the row that holds the content, inside that box, written once. It takes no value, and it decides what the ribbon is made of: the engine repeats this row as many times as the width needs. Without it the engine wraps everything inside the box in a row of its own and the ribbon still runs, but the whole content of the box becomes the ribbon, padding and headings included. [ Optional ]
    data-velocity-marquee-strip Written by the engine on the box it builds around the row, and taken off again by destroy(). Never written by hand: it is in this table because it shows in the Navigator and because the stylesheet styles it. [ Optional ]
    data-velocity-marquee-clone Written by the engine on every copy of the row. A copy is hidden from screen readers and taken out of the tab order, and it is made again whenever the width or the content changes. Never written by hand. [ Optional ]
    data-velocity-marquee-state Written by the engine on the box: running, paused while it is off screen, still under reduced motion or when there is nothing to repeat. Never written by hand, and a page can style on it. [ Optional ]
    Settings
    Every setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.
    AttributeDefaultWhat it is
    data-velocity-marquee-cruise 46 How fast the ribbon runs on its own, in pixels a second, when the page is not moving.
    data-velocity-marquee-direction left Which way the ribbon runs when nothing is happening. Options: left, right.
    data-velocity-marquee-boost 1.5 How much of the scroll speed is handed to the ribbon, as a factor.
    data-velocity-marquee-max-speed 2400 The ceiling, in pixels a second, whatever the scroll does.
    data-velocity-marquee-ease 0.12 How quickly the ribbon takes up a new speed, 0 to 1.
    data-velocity-marquee-skew 7 The strongest lean, in degrees, reached at top speed.
    data-velocity-marquee-reverse true Whether scrolling up sends the ribbon back the other way. Options: false (the page only ever pushes it forward), true.
    data-velocity-marquee-reduced-speed 0 The speed kept when the reader asks for reduced motion, in pixels a second. Options: 0 stands the ribbon still and makes no copy, any speed keeps it crawling with no lean.
    data-velocity-marquee-debug false Whether the ribbon writes its live state in data-velocity-marquee-debug-* attributes. Options: false, true (speed, lean, period, copies and offset, six times a second).

What it does

Velocity marquee is a scroll animation for Webflow and vanilla JavaScript, built on GSAP 3. Also called scroll velocity marquee, marquee speed on scroll or marquee scroll direction.

A ribbon of content runs on without end, and the page scroll drives it: it cruises on its own when nothing is happening, gains speed as the reader scrolls down, runs back the other way when the reader scrolls up, and leans a little while it is being pulled, standing upright again the moment it settles. The repeat is seamless at any window width and with any content: the row is written once, the engine repeats it as many times as the width needs, reads the distance between two copies from the page itself and wraps a single transform on that distance, so there is no jump at the join and no drift after any number of turns. It is real text the whole time, selectable and searchable, read once by a screen reader and once only, and nothing runs at all while the ribbon is off screen or when the reader asks for reduced motion. Pattern type velocity marquee, scrolling ticker, infinite scroller, speed reactive text band.

Updated

Questions

Add the custom attribute data-velocity-marquee, with an empty value, to the box that clips the ribbon, and data-velocity-marquee-track to the row inside it that holds the content, written once. The engine copies that row as many times as the width needs. Settings are more attributes on the same box, such as data-velocity-marquee-cruise="90".

No ScrollTrigger. It uses the GSAP 3.12.5 core only, from the CDN, for its ticker and quickSetter, and reads window.scrollY itself once a frame. That is also why Webflow.destroy() cannot take the effect down.

data-velocity-marquee-cruise is the speed when the page stands still, 46 pixels a second by default, and data-velocity-marquee-boost, 1.5 by default, is the share of the scroll speed handed to the ribbon: lower and the scroll barely shows, higher and a flick of the wheel throws the ribbon across. data-velocity-marquee-max-speed is the ceiling, 2400 pixels a second by default.

Yes, and it does by default: reverse is true, so scrolling up runs the ribbon backwards. Set data-velocity-marquee-reverse="false" and the page only ever pushes it forward. data-velocity-marquee-direction, left or right, sets which way it runs at rest.

A flex gap on the row does not repeat at the join: there is no gap between the last item of one copy and the first of the next. Put the space on the items as padding or margin, or give --velocity-marquee-gap the same length as the gap.