Skip to content
animorio
IT
Back to the library

The rearing ribbon

Scroll, 3D, WebGL, ImagesWebGL, Canvas, GSAPAdvancedCompressed weight: Demo 12 KBGSAP 28 KBFreeDownload the zip

Scroll inside the preview

Eight cards on a ribbon curved in depth: scroll the page and the ribbon runs sideways, and the faster it goes the more its left side rears towards you while the two ends wring. At the start three loader bars become the cards.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The rearing ribbon</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a tall page: scrolling down moves the ribbon sideways; the script sets the height from the ribbon's length -->
  <main class="hall" data-hall>
    <div class="stage" data-stage>
      <!-- the ribbon and the floor are drawn here -->
      <canvas class="stage__canvas" data-canvas aria-hidden="true"></canvas>

      <header class="bar">
        <p class="brand">The Museum of Small Things</p>
        <a class="bar__link" href="#">Plan a visit</a>
      </header>

      <!-- the rooms: the script paints these names on the cards, and they stay here for whoever cannot see them -->
      <ul class="rooms" data-rooms>
        <li><h2>Buttons</h2><p>Four holes, mostly</p></li>
        <li><h2>Keys</h2><p>To doors that are gone</p></li>
        <li><h2>Marbles</h2><p>Won and lost in playgrounds</p></li>
        <li><h2>Matchboxes</h2><p>From cafés that closed</p></li>
        <li><h2>Tickets</h2><p>Trams, ferries, one funicular</p></li>
        <li><h2>Stamps</h2><p>Steamed off old letters</p></li>
        <li><h2>Spoons</h2><p>None of them matching</p></li>
        <li><h2>Combs</h2><p>Pocket size, tortoiseshell</p></li>
      </ul>

      <footer class="foot">
        <p>Autumn rooms</p>
        <p data-hint>Scroll</p>
      </footer>
    </div>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

109 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The rearing ribbon” from Animorio and fit it into my site

What it does

The rooms of an invented museum of small things, one card per room: buttons, keys, marbles, matchboxes, tickets, stamps, spoons, combs. The cards sit in a row on a ribbon seen by a real camera: on the left it comes near, on the right it goes far, in one long S, and it leans into its own slope like a banked track. Under it there is a floor of squares. Scrolling the page moves the ribbon sideways, a little behind the scroll: slowly, it stays composed; with a flick the left side lifts and comes forward, the two ends wring opposite ways and the S deepens, then everything settles. The card under the pointer sinks in the middle like a pressed cushion, and a click brings it to the middle of the page. On arrival there are only three white bars filling up: then each one flies, grows and becomes one of the three cards in view, while the others come in from the sides.

How it works

The curve is a place

Every card is the same sheet of 32 by 8 squares, put where the flat card would be. The curve does not belong to the cards: it is a function of x on the page, the same for all of them. For every vertex q = x / half the page × SPAN + SHIFT, and the depth is DEPTH × sin(π q) × e^(−q²): near on the left, far on the right, and flat again off the page with no need for a cut-off. A card crossing a bend takes the bend, vertex by vertex, and the cards in a row make one ribbon.

The lean, read off the slope

The ribbon rolls about its centre line by BANK times the derivative of that same curve: where it climbs hardest it leans hardest, where it levels out it sits square, and the two can never disagree because one is read off the other. On top of that the whole ribbon is turned like a door, on a ramp 1.5 s − 0.5 s³ that arrives flat at the edges, and runs slightly uphill to the right (TILT).

Speed

The ribbon chases the scroll, covering a tenth of the distance every sixtieth of a second. How far behind it is, in pixels, divided by RUSH, passed through tanh and then squared, is the speed from 0 to 1: squaring keeps slow scrolling calm. With speed the left side lifts by 0.1 and comes forward by 0.2 (in half page widths), behind a mask that fades out towards the middle; the ends wring by up to 1.8 radians, one each way; the S deepens by SURGE.

The light and the dent

The surface’s normal comes from the same formulas, not from the mesh: under a tight sheen (exponent 48) every edge of the mesh would turn into a line. The light comes from the upper left; and the far end of the S is darker (SHADE). Under the pointer the card sinks by a tenth of its height with a dome (1 − x²)(1 − y²), which is zero along every edge: the outline never moves, however deep the middle goes.

The bars were the cards

The three cards nearest the middle start as bars of 48 by 5 pixels, white, clipped to the fill: bar k is full for clamp(p × 3 − k, 0, 1). When loading ends each one flies: the rectangle goes from the bar’s to the card’s in 1.5 seconds of expo.inOut, 0.05 apart; the white leaves a touch before landing and the ribbon’s curve comes in on the same progress. The other cards arrive from the sides in 1.25 seconds.

Values to change

NameFileDefaultWhat it changes
FOLLOW, RUSHscript.js0.1, 140How much of its lag behind the scroll the ribbon makes up every sixtieth of a second, and how many pixels behind it must be to count as full speed.
FIELDscript.js53.4The camera’s field of view, in degrees: wider means more perspective.
DEPTH, SURGEscript.js0.2, 1.1How deep the S goes (in half page widths) and how much deeper at full speed.
SPAN, SHIFTscript.js1.15, -0.2How much of the S fits in the page and how far it is slid along: negative brings the near bulge in from the left.
BANK, DOOR, TILTscript.js-0.16, -0.12, 0.03The lean into the slope (radians), the door-like turn of the whole ribbon and the rise to the right.
REAR, WRINGscript.js0.1, 0.2, 1.8At full speed: how far the left side lifts and comes forward, and how many radians the ends wring.
DENT, HOVERscript.js0.1, 0.5How far the card under the pointer sinks (share of its height) and in how many seconds.
SHADE, GLOSSscript.js0.5, 0.35How dark the far end of the S is and how bright the sheen.
CARDscript.js0.46, 10, 20The cards: height (share of the page), gap and corner radius in pixels.
FLOORscript.js0.15, 0.11The floor: how bright its lines are and how wide a square is, in page widths.
INTRO, BARscript.js1.4, 1.5, 0.05, 1.25 / 48, 5, 8The seconds of the entrance (loading, flight, gap between flights, arrival of the other cards) and the bars’ sizes in pixels.
ROOMSscript.js8The eight cards: things, proportions and colours. To use photos, pass images to texImage2D instead of the canvases.

Try them in the Playground

When to use it

For a row of projects, products or chapters that has to be the main scene: a portfolio’s home, a collection, a programme. It wants landscape cards full of colour, six to a dozen of them; with narrow cards the wring turns them edge-on before they can be read.

On phones

The cards are smaller and the S becomes a bowl, with no door: on a narrow screen a wave has no room to be read. Scrolling with a finger moves the ribbon and makes it rear in the same way. No dent: that needs a pointer.

With reduced motion

The ribbon is flat and follows the scroll with no lag: no curve, no rearing, no dent, and the cards are there from the start, without the bars.

Pitfalls

  • Bending first and rolling afterwards winds the bend instead of the ribbon. The order is: roll about the centre line, then depth, then rise and rear-up. The roll leaves x untouched, and the curve reads x.
  • A normal taken from the mesh hands back its flat faces, and a tight sheen turns every edge into a line. The normal is worked out from the curve’s exact derivative.
  • Past about two radians of wring a card goes edge-on and for a moment a picture becomes a line. To see more at ordinary speeds lower RUSH rather than raise WRING.
  • When the ribbon wrings the cards overlap: it takes a depth test, and they must be drawn from the furthest to the nearest, or the soft edge of a near card leaves a dark thread on the one behind.
  • The hit area stays that of the flat card: perspective moves the drawing, not the target. With DEPTH and TILT high the pointer ends up picking the wrong card.

Libraries

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.

Testing

Tested on 30 September 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All animations