
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
A design app’s palette generated from a moodboard as a kaleidoscope: every colour it reads falls into the chamber as a chip of glass, tumbles over the others while the drum turns, and two mirrors multiply it into eight slices. The fuller the chamber, the richer the pattern; at the end the drum stops and the five chosen colours come out of the eyepiece as swatches.
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, viewport-fit=cover">
<title>The palette kaleidoscope</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the palette generator of a design app: every colour read from the moodboard drops into a kaleidoscope as a
chip of glass, tumbles in the turning chamber and is mirrored into eight slices. When the chamber is full the
drum stops and the five colours it settled on come out as swatches below. The glass is simulated and painted
on the canvas by script.js; the words, the swatches and the button are HTML -->
<section class="pal" aria-labelledby="pal-title" data-pal>
<div class="pal__top">
<div class="pal__scope" role="progressbar" aria-labelledby="pal-title" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-valuetext="Palette not generated yet" data-scope>
<div class="pal__knurl" aria-hidden="true" data-knurl></div>
<div class="pal__well">
<canvas class="pal__glass" aria-hidden="true" data-glass></canvas>
<span class="pal__lens" aria-hidden="true"></span>
</div>
</div>
<div class="pal__words">
<h2 class="pal__title" id="pal-title">Moodboard · Coastal Dusk</h2>
<p class="pal__big" aria-hidden="true"><span class="pal__swap" data-big>24 images</span></p>
<p class="pal__status">
<span class="pal__swap" data-status>No palette yet</span>
<svg class="pal__tick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.6 10.4l3.5 3.5 7.4-8" pathLength="1"/></svg>
</p>
<p class="pal__sub"><span class="pal__swap" data-sub>Edited 2 h ago</span></p>
<button class="pal__btn" type="button" data-action data-autoclic><span class="pal__label" data-label>Generate palette</span></button>
</div>
</div>
<ul class="pal__swatches" aria-label="Generated palette" data-swatches>
<li class="pal__slot"><span class="pal__chip" data-chip></span><span class="pal__hex" data-hex></span></li>
<li class="pal__slot"><span class="pal__chip" data-chip></span><span class="pal__hex" data-hex></span></li>
<li class="pal__slot"><span class="pal__chip" data-chip></span><span class="pal__hex" data-hex></span></li>
<li class="pal__slot"><span class="pal__chip" data-chip></span><span class="pal__hex" data-hex></span></li>
<li class="pal__slot"><span class="pal__chip" data-chip></span><span class="pal__hex" data-hex></span></li>
</ul>
<p class="sr" role="status" 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.
35 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 palette kaleidoscope” from Animorio and fit it into my siteEvery chip is an irregular convex polygon (a three sided shard, a quad, a pentagon or a long sliver) centred on its centroid. For the physics it carries a few circles that fill it: one at the centroid and others towards the corners, each as big as its distance to the nearest edge. Mass and moment of inertia come from the area. So collisions between chips become collisions between circles, simple and stable, yet a knock on a corner spins the chip as a real polygon would.
Three physics steps per frame (at most 1/30 of a second in all). Every step gathers the contacts between circles of different chips and between circles and the round wall; then ten rounds of sequential impulses: an impulse along the normal that never pulls (accumulated and kept above zero), with a little bounce when the hit is hard and a small push that undoes overlaps, and friction along the contact that never exceeds FRICTION times the normal impulse. Speeds are capped and no chip can leave through the wall.
The chamber’s wall does not stand still: at the point of contact it moves at the drum’s speed, ω × r, and friction passes it on to the glass. That is why the heap climbs the wall until the slope beats the friction and it slides back, just as in a real kaleidoscope’s tube. The drum’s speed is a GSAP tween: it starts on a soft curve, stops with a jolt when something goes wrong and slows down gently when the palette is ready. The knurling on the drum turns by the same angle while the light on it stays put.
Every frame the chamber is painted once on a canvas of its own. Every chip is filled with its colour in screen mode, so where two chips overlap their light adds up and the colour brightens; on top, a gradient along the direction of the light gives the thickness (bright where the light comes in, dark where it leaves), a lighter band just inside the outline makes thick cut glass, and every edge lights up or darkens by how much it faces the light.
The mirrors meet a little below the middle of the chamber and look down, where the glass gathers. The eyepiece draws the chamber’s canvas SLICES times: every slice is a wedge clip of angle 2π/SLICES, turned into place, and every other slice is flipped, so the edges meet as they do between two real mirrors. On top go the faint seams of the mirrors, the grey veil of the error (saturation mode) and the final glint.
The eyepiece is a role=progressbar with aria-valuenow and an aria-valuetext that says how many images have been read, the card has aria-busy while it works and an aria-live line says when the palette starts, stops and which colours it chose. The swatches are a list with their codes written out. The button changes its word (Generate palette, Generating…, Retry, Regenerate) and takes the new width with a little bounce; while it works it is aria-disabled.
| Name | File | Default | What it changes |
|---|---|---|---|
IMAGES | script.js | 24 | How many images the moodboard has. |
SECONDS | script.js | 6 | How long a palette takes in the demo, in seconds (a real one follows the generator). |
PIECES | script.js | 34 | How many chips of coloured glass fill the chamber. |
SLICES | script.js | 8 | How many mirrored slices the eyepiece shows (an even number). |
DRUM | script.js | 0.8 | How fast the drum turns while it works, in radians a second. |
GRAVITY | script.js | 1100 | How hard the glass falls, in pixels a second squared. |
FRICTION | script.js | 0.35 | How much the glass grips the wall and the other chips: higher, the heap climbs further before it slides. |
BOUNCE | script.js | 0.18 | How much a chip bounces when it lands: 0 not at all, 0.6 a lot. |
CHIP | script.js | 1 | How big the chips are: 0.7 small, 1.3 large. |
FAIL_EVERY | script.js | 2 | In the demo, one palette in how many cannot read the moodboard (0 never). |
FAIL_AT | script.js | 0.55 | How far the palette that stops gets, from 0 to 1. |
SHEEN | script.js | 0.8 | The glint that crosses the eyepiece when the palette is ready: 0 none, 1.5 bright. |
For a wait of a few seconds while a program picks colours: a palette from a moodboard or a photo, a generated theme for an app, a brand’s colours pulled from a website. The kaleidoscope says at once that the work is about colour, and the pattern growing richer makes the result feel as if it is taking shape; for any loading that is not about colour the metaphor is out of place.
The card takes the screen’s width less 32 pixels (358 on a 390 screen) and stays 266 tall; the eyepiece drops from 184 to 164 pixels, the big words to 27, and the five swatches close up with gaps of 6. The chamber resizes with the eyepiece and the glass keeps its place. The canvas paints at the screen’s real density, up to twice. The button is a pill 36 tall: under a finger it squashes and springs back, and its words widen on the width axis only under the mouse.
The drum does not turn and the glass does not fall: every new chip fades in already in its place in the heap (the physics settles it out of sight before it is shown), without flashes. No jolt or jump on the error (the grey veil stays), no glint at the end; the swatches fade in at their places and the coloured glass fades out on Regenerate. The pattern still grows richer, because it is what says how far along things are.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 15 KB; the libraries: GSAP 28 KB.
Tested on 8 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.