
The liquid glass button
Buttons, WebGL, Hover, Physics
NewFree
The Upgrade to Pro button of a pricing page, on a black background: inside the pill a small glass prism opens a ray of white light into its spectrum, which runs across the pill and colours the words. It is real optics, worked out for sixteen wavelengths with Snell’s law, Cauchy’s index and Fresnel’s reflections, and drawn by a WebGL shader that adds the bands of colour together. The pointer turns the prism on a spring and the spectrum moves, opens and narrows; pressed, the prism spins, the spectrum sweeps the pill like a lighthouse and the words become Welcome to Pro.
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 prism button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/inter-tight@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the prism button: the Upgrade to Pro button of a pricing page. Inside the pill a small glass prism splits a ray
of white light into its spectrum, worked out with Snell's law for sixteen wavelengths, and the colours light the
words. The pointer turns the prism; pressed, it spins and the spectrum sweeps the whole pill -->
<div class="pro" data-pro>
<span class="pro__halo" aria-hidden="true" data-halo></span>
<div class="pro__pill" data-pill>
<canvas class="pro__canvas" aria-hidden="true" data-canvas></canvas>
<button class="pro__btn" type="button" data-btn data-autoclic>
<span class="pro__face" data-face="rest">Upgrade to Pro</span>
<span class="pro__face" data-face="busy" aria-hidden="true">Upgrading</span>
<span class="pro__face" data-face="done" aria-hidden="true">Welcome to Pro</span>
</button>
</div>
<p class="pro__note" data-rise><span data-note>$12 a month, billed yearly · cancel anytime</span></p>
<p class="sr" aria-live="polite" data-live></p>
</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.
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 prism button” from Animorio and fit it into my siteEvery frame in which the prism moves, the script follows sixteen rays, from violet at 409 nanometres to red at 691. For each one it finds the first face the ray meets, takes its normal and bends the ray with Snell’s law in vector form; inside the glass it finds the face it leaves by and bends it again. The index changes with the colour by Cauchy’s formula, n = INDEX + SPREAD / λ², higher for blue: that is why blue bends more and the colours separate. If a ray meets a face at a flatter angle than the critical one, the face acts as a mirror (total internal reflection) and the ray leaves by another.
At each face part of the light is reflected, by Fresnel’s equations for unpolarised light (the mean of the two polarisations): what gets through is the light left in the ray, and what the first face reflects becomes a white ray going back, stronger when the light comes in at a grazing angle. For each colour the shader gets the entry point, the point of any bounce, the exit point and the direction, with the light left written into the length of the direction (two vec4 per ray: few uniforms, enough for phones too).
The colour of each ray comes from the CIE 1931 colour matching functions written as sums of skewed gaussians (Wyman, Sloan and Shirley), then from XYZ to linear sRGB, clipping the negative parts the screen cannot show. The sixteen colours are scaled so that all of them together make white: where the bands overlap, near the prism, the light is white again, and further on the rainbow opens, as in a real prism.
For each pixel the shader adds up the light of every ray: a band with a sharp core and a wide glow, which widens along its path and grows fainter in proportion, so the energy stays the same. The letters are a texture painted once (the three labels in the red, green and blue channels) and they take the light more than the floor does, like print under a beam. The prism has a faint tint and polished edges, lighter on the faces turned upwards; at the end a soft curve that never reaches flat white, and the gamma correction.
At the start the script looks for the turn of minimum deviation, the classic position where the spectrum is tidiest, and the entry angle of the white ray that sends green through the middle of the words. The pointer adds up to TURN radians on a spring (STIFF and DAMP); pressed, the prism spins at SPIN turns a second for WAIT seconds and then the spring stops it on the next third of a turn, where a triangle looks just as before. The shader draws again only when something changes.
| Name | File | Default | What it changes |
|---|---|---|---|
INDEX | script.js | 1.48 | The glass’s refractive index (Cauchy’s A): more, the light bends more. |
SPREAD | script.js | 0.032 | How strongly the index changes with the colour (Cauchy’s B, in square micrometres): more, a wider rainbow. Real glass stays under 0.01: here it is exaggerated so it shows. |
TURN | script.js | 0.3 | How far the pointer can turn the prism, in radians each way. |
STIFF | script.js | 70 | How hard the spring turns the prism to where the pointer wants it. |
DAMP | script.js | 9 | How quickly the prism stops wobbling. |
SPIN | script.js | 1.4 | The turns per second of the prism while the upgrade goes through. |
WAIT | script.js | 1.6 | The seconds of the pretend upgrade. |
DONE | script.js | 3.4 | The seconds the button says Welcome to Pro before it comes back by itself. |
GAIN | script.js | 1 | How bright the light is. |
For the button that matters on a dark pricing page: Upgrade, Go Pro, Start free trial, Get early access. It works on its own, in the column of the recommended plan, or in the header of an app for creatives and developers; the prism says light and quality without any icon. Use it once a page: it is an effect that draws the eye.
The pill narrows to the width of the screen (at most 360 pixels) and the prism, the words and the spectrum are worked out again for its size. With no mouse a finger turns the prism while it touches and the spectrum follows; a tap presses the button. The canvas works at most at twice the screen’s density.
The prism keeps still in its rest position: no spring, no turning towards the pointer and no spin on the press. The spectrum stays where it is; pressed, the words change with a fade, the light grows stronger, the spectrum opens without moving and the halo appears.
GSAP 3.15.0, Inter Tight (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 11 KB; the libraries: GSAP 28 KB.
Tested on 5 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.