
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
A project budget in a studio’s contact form, chosen on a comb of thin teeth: the vermilion knob stands among them, the teeth ahead bend under its push and grow, then slip behind it and ring like a plucked comb, with a wave that runs along the row and dies out. The big figure above grows wider with the budget. 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 comb slider</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the budget field of a studio's contact form, on a comb: a row of hairline teeth on a spine. The knob stands
among the teeth; as it passes they lean out of its way and grow, each on a spring of its own and tied to its
neighbours, so they straighten behind it in a wave that dies out. The teeth and the knob are drawn by the
script on the canvas; the real range input underneath carries the value, the keys and the screen reader -->
<div class="budget" data-budget>
<div class="budget__head">
<label class="budget__label" for="budget-range">Project budget</label>
<span class="budget__note" aria-hidden="true"><span class="budget__note-text" data-note>A full website</span></span>
</div>
<p class="budget__value" aria-hidden="true"><span class="budget__cur">€</span><span class="budget__num" data-num>40k</span></p>
<div class="budget__comb" data-comb data-autoclic>
<canvas class="budget__canvas" aria-hidden="true" data-canvas></canvas>
<input class="budget__range" type="range" id="budget-range" name="budget" min="5000" max="100000" step="5000" value="40000" data-range>
</div>
<div class="budget__scale" aria-hidden="true">
<span data-lo>€5k</span>
<span data-hi>€100k+</span>
</div>
</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>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.
37 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 comb slider” from Animorio and fit it into my siteEvery tooth is a weight on a spring (TOOTH_SPRING) that wants it straight, and two springs tie it to its neighbours (COUPLING): the difference between a tooth and the two beside it pulls it. It is the discrete string of the physics books, so a bend that is not shared does not stay put but runs along the row as a wave, and the damping puts it out in a second and a half. The springs are worked out on GSAP’s ticker in steps of 1/240 of a second, with the frame step capped at 1/30.
The tip of each tooth stays CLEAR pixels from the middle of the knob, on the side the tooth is on: a very stiff contact spring keeps it out. So the running knob pushes the tips ahead of it and bends those teeth; once one is bent by SLIP of its length it changes side, the contact spring snaps it across and it rings. The slower the knob, the sooner the teeth let it through; a tooth whose root is right behind a still knob stands straight, hidden by it.
Every frame the canvas redraws the teeth as quadratic Bézier curves that leave the root straight and bend at the tip, like a real blade; a bending tooth also gets a little lower. Four strokes in all: tall and short teeth, black before the knob and grey after it. The teeth near the knob grow by LIFT (more while it runs, when it is touched or held), and the run drags them a little with it (DRAG). When everything is still, the ticker is removed.
While it is held the knob follows the hand on a very stiff spring, just behind; past the two ends it only gives a little. Let go, the value comes from where the hand was, and the KNOB_SPRING spring takes it to the nearest step with one pixel too many. Its head has a spring of its own that makes it lag during the run and swing once on arrival.
The figure follows the knob, not the written value: its width axis (Roboto Flex’s font-stretch, 25 to 151) goes from WIDTH[0] to WIDTH[1] along the comb, so it grows while you drag, and its weight drops to 360 with the speed and comes back to 620 when it settles. The grey line above changes by sliding in its mask, up when the budget rises and down when it falls.
Under the canvas there is a real, invisible range input that holds the value, the label, the keys (arrows, Page Up and Down, Home, End) and the screen reader, with an aria-valuetext like €40,000; the focus ring is drawn only when it is reached with the keys. A click from a script (detail 0, the preview’s) is a pretend hand: it takes the budget to 90k, then down to 15k and back where it was.
| Name | File | Default | What it changes |
|---|---|---|---|
MIN | script.js | 5000 | The smallest budget. |
MAX | script.js | 100000 | The largest budget, written with a plus: that much or more. |
STEP | script.js | 5000 | How much the budget moves by: one tall tooth for every step. |
START_AT | script.js | 40000 | The budget when the page opens. |
CURRENCY | script.js | '€' | The sign in front of the figures. |
TEETH | script.js | 3 | How many teeth there are from one step to the next (fewer on a narrow screen, if they would crowd). |
CLEAR | script.js | 5.5 | How close a tooth’s tip may come to the middle of the knob, in pixels. |
SLIP | script.js | 0.4 | How far a tooth bends before the knob, as a share of its length, before it slips behind. |
LIFT | script.js | 18 | How much the teeth near the knob grow, in pixels. |
REACH | script.js | 44 | How far from the knob the teeth still feel it, in pixels. |
DRAG | script.js | 0.006 | How much the running knob drags the nearby teeth with it. |
TOOTH_SPRING | script.js | [300, 0.22] | Each tooth’s spring: how stiff, and how much it is held back (less means it rings longer). |
COUPLING | script.js | 700 | How hard each tooth pulls its neighbours: the higher, the faster and farther the wave runs. |
KNOB_SPRING | script.js | [320, 0.78] | The knob’s spring when nobody holds it: how stiff, and how much it is held back. |
WIDTH | script.js | [32, 148] | The figure’s width axis at the smallest and at the largest budget (25 to 151). |
NOTES | script.js | [[15000, 'A landing page'], [40000, 'A full website'], [70000, 'A brand and a website'], [100000, 'A digital product']] | What a budget usually buys: up to that much, those words. |
For the budget in a studio’s or an agency’s contact form, the figure of a quote, the text size in a reading app, or any stepped slider where the gesture should be felt in the fingers without adding anything to the page.
The slider takes the width of the screen minus a margin and the figure gets a little smaller; if the teeth would stand less than 5 pixels apart, there are fewer between two steps. A finger drags it sideways while the page still scrolls up and down (touch-action: pan-y), and a tap on the comb brings the knob there through the teeth. Springs and waves are the same.
No springs, no waves, no entrance: the knob is at once where it is taken, the nearby teeth are already at their height and bent out of its way, and the figure and the grey line change with a fade. The figure’s width still follows the budget.
GSAP 3.15.0, Roboto Flex (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 10 KB; the libraries: GSAP 28 KB.
Tested on 16 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.