ScrollMarquee

A strip of content running sideways for ever, leaning with the scroll and reversing when it does.

scroll the page

Paste into Claude Code, Cursor or any agent. Pinned to a tag, so it will not change under you.

Options

period 24

4 to 120 s

Seconds for the strip to travel exactly one copy of its content, which is also the loop. Longer content at the same period runs faster, because the distance is longer: this is a pace rather than a speed.

direction 1

-1 to 1

Which way it runs when the page is still. 1 is leftwards, which is the direction text is read away from and the one that feels like it is going somewhere.

drag 0.35

0 to 2

How far the scroll drags it, in copies of the content per full scroll of the element through the viewport. This is what makes it reverse when you scroll back up. At 0 it runs at a constant pace and ignores the page.

skew 7

0 to 25 deg

Degrees of lean at full scroll speed. This is the whole character of the effect: it is what makes the strip feel like it has mass and is being dragged rather than playing beside the page. Past about 15 it reads as a glitch.

stretch 0.12

0 to 0.5

How much it stretches along its travel at full scroll speed. Small: it is the squash-and-stretch of the thing, and at anything over about 0.2 the type distorts enough to notice as distortion.

reference 1.2

0.2 to 6

The scroll speed that counts as full, in screens per second. 1.2 is about a brisk flick, so an ordinary scroll leans the strip a few degrees and a hard one leans it fully. Too low and a single wheel click pins it at maximum, which loses the difference between a nudge and a flick.

gap 48

0 to 240 px

Space between the end of one copy of the content and the start of the next. It is applied inside the copy, so it is part of the width the wrap is measured against: a gap added between the copies instead would make the loop a fraction longer than the thing it is wrapping, and the strip would stutter once per cycle.

What it needs

Category
Type, an effect
Dependencies
None at all
Browser
No WebGL
Frame budget
~0.05 ms · 0 context
Pinned to
v0.12.0
  • No canvas and no WebGL. The strip is the author's own markup, moved into a track and transformed, so links keep working and images that have loaded stay loaded
  • Pure in t, which is the part that takes care. A marquee written the obvious way accumulates an offset every frame, and an effect that integrates against its own last frame cannot be recorded, cannot be seeked and drifts on a dropped frame. The position here is a function of the clock and the scroll position and nothing else
  • The content is duplicated once so the wrap is seamless, and the clone is aria-hidden with every focusable inside it given tabindex -1. A duplicate of the content is a duplicate to a screen reader too
  • The lean is scroll velocity, normalised and clipped. A trackpad reports an order of magnitude more than a wheel, and without a ceiling the strip lies flat on its side the first time somebody flicks the page
  • One transform on one element per frame, which is a composited property, so this does no layout work at all
  • One transform write per frame on a single element. Both properties are composited, so there is no layout and no paint
  • The content width is measured on mount and on resize rather than per frame