
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
The new records of a record shop, each vinyl in its sleeve: when the row sets off the records are left behind, slide out of the open side and roll, their labels turning; when it stops they run back in and knock the back, and the sleeve gives a little jolt. The record in front stands half out, its name under it.
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 sliding records</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/syne@5.3.0/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/host-grotesk@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the records: a row of sleeves, each with its record inside. The row moves on a spring and the records feel
it: they slide out of the open side of their sleeves and roll when it sets off, knock the back of the sleeve
when it stops, and the record in front of you stands half out. The sleeves and the records are drawn by the
script -->
<section class="crate" role="region" aria-roledescription="carousel" aria-labelledby="crate-title" data-crate>
<header class="crate__head">
<h2 class="crate__title" id="crate-title">New in this week</h2>
<div class="crate__arrows">
<button class="arrow" type="button" aria-label="Previous record" data-prev>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path class="arrow__step" d="M14 6.5 8.5 12l5.5 5.5"/>
<path class="arrow__wrap" d="M8 9.5h6.5a4 4 0 0 1 0 8H10M10.5 6.5 7.5 9.5l3 3" transform="matrix(-1 0 0 1 24 0)"/>
</svg>
</button>
<button class="arrow" type="button" aria-label="Next record" data-next data-autoclic>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path class="arrow__step" d="M10 6.5 15.5 12 10 17.5"/>
<path class="arrow__wrap" d="M8 9.5h6.5a4 4 0 0 1 0 8H10M10.5 6.5 7.5 9.5l3 3"/>
</svg>
</button>
</div>
</header>
<div class="crate__view" tabindex="0" aria-describedby="crate-help" data-view>
<div class="crate__row" data-row></div>
</div>
<p class="sr" id="crate-help">Arrow keys to move along the records, Home and End for the first and the last.</p>
<div class="crate__foot">
<div class="caption" data-caption>
<p class="caption__title" data-cap-title></p>
<p class="caption__artist" data-cap-artist></p>
</div>
<div class="caption caption--end" data-caption-end>
<p class="caption__price" data-cap-price></p>
<p class="caption__meta" data-cap-meta></p>
</div>
</div>
<div class="rail" aria-hidden="true"><span class="rail__thumb" data-thumb></span></div>
<p class="sr" aria-live="polite" data-live></p>
</section>
</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.
53 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 sliding records” from Animorio and fit it into my siteThe row is a single number, p: the record in front as a fraction. A spring takes it to the chosen record, a = ω²·(goal − p) − 2ζω·v, with ω and ζ from GLIDE; the stiffness is divided by the square root of the distance, so a jump of six records starts with the same push as a single step and lasts only a little longer. Each sleeve stands at (i − p) times the step, in pixels.
That same a, times the step, is the row’s acceleration in pixels, already smooth because the spring works it out rather than the difference between two frames. Each record is a mass on a spring (SPRING) towards its place, OUT for the one in front and REST for the others, and the row accelerating pushes it the other way: by PUSH and by two thirds, what a disc rolling on its edge feels (its moment of inertia is half m r²).
Below zero is the back of the sleeve: the record bounces off it keeping KNOCK of its speed, and the sleeve takes 22 per cent of the knock, jolting on its own spring, a little sideways and a little turned. The other way, a record goes at most as far as the next sleeve, which it knocks the same way; the last one in the row as far as two thirds of its sleeve.
A rolling record turns by the way it has gone over its radius: the label, an SVG with the title and the side written round it with textPath, turns by u / R. The grooves are a repeating-radial-gradient with the gaps between the songs; the reflection is a conic-gradient on a layer that does not turn, as the lamp stays where it is.
With the mouse or a finger the row chases the pointer on a stiff spring, so the push is smooth there too, and past the ends on a rubber band. Let go, it takes the speed of the last 90 milliseconds, looks at where it would get in THROW seconds and is caught on the nearest record; touch-action pan-y leaves vertical page scrolling to the finger. Arrow keys, Home, End and the sideways wheel; at the ends the buttons turn into a curl that goes to the other end.
The step between sleeves is worked out by the script: the next sleeve starts --gap pixels after the record that stands out, so at rest the record covers nothing. The group of sleeve and record stands in the middle; when it does not fit, the sleeve lines up with the title and the record runs to the edge of the screen, where the row goes past the margins. When everything is still the loop switches off.
| Name | File | Default | What it changes |
|---|---|---|---|
OUT | script.js | 0.46 | How far the record in front stands out of its sleeve, as a part of the sleeve’s side. |
REST | script.js | 0.05 | How far the other records peek out of their sleeves when nothing moves. |
PUSH | script.js | 1.3 | How much the records feel the row moving: 0 not at all. |
SPRING | script.js | [110, 0.3] | The spring that takes a record back to its place: how stiff it is and how much it is held back. |
KNOCK | script.js | 0.35 | How much of its speed a record keeps when it knocks the back of its sleeve. |
GLIDE | script.js | [6.5, 0.8] | The row’s spring: how quickly it gets to a record and how much it is held back. |
THROW | script.js | 0.22 | The seconds a thrown row runs on before it is caught (how far a flick goes). |
RECORDS | script.js | [['Slow Orbit', 'Ines Varga', 'LP, 2026', '€28', 'orbit'], …] | The records: title, artist, format and year, price, cover (orbit, weather, swim, fig, hum, radio, stairs). |
--size | style.css | 300px | The side of a sleeve (260 on a phone). |
--gap | style.css | 24px | The space between the record out of its sleeve and the next sleeve. |
For the new arrivals of a record shop or a bookshop, an online shop’s featured products, a label’s albums, the podcasts or playlists of an app: wherever each thing has a square cover and is worth pulling a little out of the row.
The sleeves go down to 260 pixels and the row reaches the edges of the screen: the sleeve in front lines up with the title, 16 pixels from the edge, and its record comes out by 120 pixels to the right edge, faded a little. A finger drags and throws the row (up and down scrolls the page), the buttons are 42 pixels and a tap on a sleeve at the side goes there.
The row does not run: it fades out and back in already on the new record, with the records already in place (they change halfway through the fade); no sliding, bouncing or jolting sleeves, and the mouse over a sleeve pulls nothing out. The name changes with a fade and the component comes in with a fade only. Dragged, the row follows the hand, and let go it fades onto the nearest record.
GSAP 3.15.0, Syne (font variabile) 5.3.0, Host Grotesk (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 6 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.