
Marquee that speeds up with scroll
Scroll, Text, Hover
Free
The winter timetable of a small ferry in thin tabular figures: under the pointer two vermilion hairlines stretch like rubber bands to the edges, one along the row and one down the column, the time where they cross takes weight and width, and the headers of the port and the boat snap. Minimal style.
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 ferry timetable</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage" data-stage>
<header class="top">
<span class="top__name"><span>Larkspit</span></span>
<span class="top__note"><span>Winter timetable, every day</span></span>
</header>
<!-- the timetable: a port on every row, a boat on every column, a departure time in every cell. Under the pointer
two hairlines stretch like rubber bands to the edges, one along the row and one down the column; the time
where they cross takes weight and width, and the two headers snap -->
<div class="board" data-board>
<svg class="cross" data-cross aria-hidden="true">
<path class="cross__line" data-line-row d="" />
<path class="cross__line" data-line-col d="" />
</svg>
<div class="table" role="table" aria-label="Larkspit ferry, winter departures" tabindex="0" data-table></div>
<i class="rule rule--head" data-rule aria-hidden="true"></i>
<i class="rule rule--foot" data-rule aria-hidden="true"></i>
</div>
<footer class="foot">
<span class="hint" data-hint>Point at a sailing</span>
<span class="sr" aria-live="polite" data-say></span>
</footer>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>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.
20 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The ferry timetable” from Animorio and fit it into my siteThe table is a CSS grid with role=table: the first column for the ports, then a 1fr column for each boat, the rows with display: contents. The times are worked out from the boat's departure plus the port's minutes. Every text is a span with three CSS variables, --w (font-weight), --s (font-stretch) and --k (how much black is in the color-mix with the grey): GSAP animates only those, and Archivo's figures with tabular-nums never make the columns dance.
The two lines are two paths in an SVG that sits behind the grid. Every text has a background the colour of the paper with a little padding: the line runs under it and disappears behind the figures, so it shows only between the cells. No masks and no maths: the order of the layers is enough.
Each line is a path of two cubic curves: from the left end to the held point (where the pointer is along the line) and from there to the right end, with a flat tangent at the held point. The held point chases the middle of the row on a stiff spring (GRAB_SPRING), the ends on a softer one (ENDS_SPRING): changing row the line bends and straightens. PULL moves the held point towards the pointer inside the cell. The springs are integrated by hand on GSAP's ticker with the step capped at 1/30 of a second.
A third number, reach, goes from 0 to 1 on a spring that is almost fully damped (it goes a pixel or two past): the ends stand at that fraction of the way between the pointer and the edges. When the cross goes out, reach goes back to 0 on a harder spring and the lines go back into the pointer. A new cross is born already on its row, with no bend.
Changing cell, every text that changes state gets one tween only (the old one is stopped first, so a late one never undoes the new one): the crossing goes to WEIGHT[1] and WIDTH[1] with back.out, the row and the column to black, the others to grey with a delay that grows with the distance. The four neighbours make a push of NUDGE pixels and come back with elastic.out; the port and the boat snap 5 pixels towards the table and come back on a spring, taking weight.
| Name | File | Default | What it changes |
|---|---|---|---|
GRAB_SPRING | script.js | [420, 30] | The spring of the point where the pointer holds each line: how stiff, and how much it is held back. |
ENDS_SPRING | script.js | [150, 17] | The spring of the two ends of each line, which follow the held point a moment later (softer, more bend). |
PULL | script.js | 0.22 | How much the pointer pulls the line off the middle of its row (0 = not at all). |
WEIGHT | script.js | [230, 680] | The weight of the times at rest and of the time at the crossing (100 to 900). |
WIDTH | script.js | [88, 114] | The width of the times at rest and of the time at the crossing (62 to 125). |
NUDGE | script.js | 2 | How many pixels the cells next to the crossing move away. |
WANDER | script.js | true | The cross walks by itself when nobody points. |
For every two-way table where you look for a crossing: ferry, train and bus timetables, the programme of a festival (stages and hours), the sizes of a shop, the prices of a hotel by season and room. It works while the table fits a screen, up to eight rows and eight columns; bigger than that, it is better filtered first.
The same animations with the sizes adapted: the figures are smaller and the rows taller, so the table fills the screen and the cells are easy to touch. The cross goes where you touch and follows the finger while it slides; when the finger lifts it stays there, and after a few seconds it starts walking by itself again. The page still scrolls up and down.
No springs, no bends and no snaps: the lines appear already stretched on the row and the column, the crossing, the row and the headers change weight and colour with a short fade, the neighbours do not move and the cross does not walk by itself. When the page opens everything fades in already in place.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.2 KB; the libraries: GSAP 28 KB.
Tested on 15 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.