Skip to content
animorio
IT
All components

The button under stress

Buttons, Physics, HoverCanvas, GSAPAdvancedCompressed weight: Demo 10 KBGSAP 28 KBFreeDownload the zip

The Run stress test button of a load testing tool, made of a slab of clear plastic seen between two crossed polarising filters, the way engineers look at the stress inside a model: wherever the plastic is under stress, fringes of colour appear. At rest only the rim glows, with the stress left in it by the mould. The pointer is a fingertip pressing on the top edge: a drop of coloured rings opens under it and follows it, and pressed, the rings multiply. Clicked, the test becomes a four point bending test whose load climbs in stages with the virtual users: the fringes pour in from the faces and curl round the pins, until the words say Passed at 5,000 users. The colours are not picked: they are worked out pixel by pixel from the stress and the light.

The code

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 button under stress</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/ibm-plex-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the button under stress: the Run stress test button of a load testing tool, a slab of clear plastic seen
         between two crossed polarising filters, so the stress inside it shows as bands of colour. The fringes are
         worked out on the canvas; the gloss, the edge and the words stay on top -->
    <div class="stress" data-stress>
      <button class="stress__btn" type="button" data-btn data-autoclic>
        <canvas class="stress__fringes" aria-hidden="true" data-fringes></canvas>
        <canvas class="stress__fringes stress__ghost" aria-hidden="true" data-ghost></canvas>
        <span class="stress__label" data-label>
          <span class="stress__icons" aria-hidden="true" data-icons>
            <svg class="stress__icon" viewBox="0 0 24 24" data-load>
              <path d="M3 13.5Q12 13.5 21 13.5" data-beam/>
              <path d="M6 14.6 4.1 18h3.8z M18 14.6 16.1 18h3.8z" data-supports/>
              <g data-arrow>
                <path d="M12 3.6v6.6"/>
                <path d="M9.5 7.9 12 10.4l2.5-2.5"/>
              </g>
            </svg>
            <svg class="stress__icon stress__icon--done" viewBox="0 0 24 24" data-check>
              <path d="M5 12.6l4.4 4.3L19.2 7.2" data-tick/>
            </svg>
          </span>
          <span class="stress__words" data-words>Run stress test</span>
        </span>
      </button>
      <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>

Playground

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.

26 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The button under stress” from Animorio and fit it into my site

What it does

On a black background there is a dark pill: a slab of clear plastic seen between two crossed polarising filters. Where the plastic is at rest no light gets through and the slab is black, with a breath of deep blue; only the rim glows, with the stress left in it by the mould: a thin white line and, outside it, a fringe of colours that changes a little along the way round. In the middle, in white, the icon of a beam on two supports with an arrow above it, and the words Run stress test. Bringing the mouse onto the slab, a drop of coloured rings opens on the top edge above the pointer, blue, yellow and orange, with a white glow falling under it; moving the mouse, the drop follows it on a spring. Pressed, the rings multiply and tighten, red, blue and green, and the slab sinks a touch. At the click the finger leaves and the test begins: two pins press from above, two supports hold the slab from below near its ends, and the load climbs in stages with the virtual users, 1,000, 2,500, 4,000 and 5,000, counted in the words. At every stage the fringes pour in from the faces: the slab goes from grey to white and yellow, then to bands of colour ever closer together that bend round the pins and the supports, while the little beam in the icon sags. At the top the load shivers a little, like real traffic. Then the load comes off, the slab rings for an instant and goes back to black with its rim; the words become Passed at 5,000 users with a green tick drawing itself, and after a few seconds Run stress test comes back.

How it works

Interference colours, in a table

Between two crossed polarising filters, a stressed plastic lets the light through by sin²(π δ / λ), where δ is the delay between the two polarisations and λ the wavelength: in white light every delay has its own colour, the Michel-Lévy scale (black, grey, white, yellow, red, blue, green and round again, paler every time). At the start the script works it out once, in 2048 steps up to 6000 nanometres: it adds the formula up over a hundred wavelengths with the light of a black body at 6500 kelvin and the CIE 1931 colour matching functions (in Wyman, Sloan and Shirley's gaussians), goes from XYZ to sRGB and pulls the colours the screen cannot show towards the grey of the same brightness. A photographer's curve (power 1.5) sinks the faint light into the black, and a breath of blue recalls that real filters never close completely.

The stress left in the rim

A moulded slab cools from the outside first: the skin stays squeezed along the edge and the core pulls a little. For every pixel the script finds the nearest point of the pill's edge, the tangent there and the distance, and writes a stress tensor along the tangent: RIM nanometres of delay at the edge, falling off like a Gauss bell, with a small change along the way round. It is worked out once for every size, in three Float32Arrays, and at rest it is the only thing that shows.

Flamant under the finger and the pins

A load P on an edge pushes the plastic straight out from itself with a stress 2P cos θ / π r (Flamant's solution for the half plane): the rings of colour are circles touching the edge at the load. The finger is such a load on the top edge, CONTACT pixels wide so the stress does not go to infinity at the point; below, the table pushes back over a wide patch. TOUCH and PRESS say how many fringes lie under the finger: under a contact c wide the stress peaks at 0.2067 P / c, and from that the script finds P.

The beam of the four point test

During the test two pins press from above and two supports hold from below. Besides Flamant under each of them, the slab bends like a beam: σ = M y / I, growing towards the faces and nothing on the neutral axis, where the words are, plus the shear τ = V (h²/4 − y²) / 2I. In beam theory the moment changes all at once at the pins and the supports; in a real slab the change spreads over about its height (Saint-Venant), so the moment is smoothed with a bell and the shear is its slope. The load is scaled so that PEAK fringes lie on the faces between the pins.

Springs, stages and no idle work

The finger's load, its position and the test's load are three springs (STIFF and DAMP), moved on in two half steps a frame with the step held under 1/30 of a second: a load that changes rings for a moment before it settles, and the fringes come and go. The stages of the test are the USERS, one every STAGE seconds, and at the top the load shivers with the traffic. For every pixel the tensors are added up, the difference of the principal stresses √((σx − σy)² + 4τ²) gives the delay and the table the colour, written into a Uint32Array and laid down with putImageData. The canvas works at SHARP times the screen's density (about a millisecond and a half a frame on a computer) and draws again only when a load changes.

Values to change

NameFileDefaultWhat it changes
TOUCHscript.js1.3The fringes the pointer's touch opens under it, in orders (one order is one round of colours).
PRESSscript.js3The fringes under the finger while the button is held down, in orders.
PEAKscript.js3.6The fringes on the slab's faces when the test is at its peak, in orders: more, closer and paler bands.
USERSscript.js[1000, 2500, 4000, 5000]The virtual users of every stage of the test: the load follows them, and the highest is the one the words give at the end.
STAGEscript.js0.5The seconds of every stage.
HOLDscript.js0.85The seconds the test holds the highest load.
RIMscript.js950The stress left in the rim, in nanometres of delay: 280 is white, 450 orange, 550 purple, 700 blue.
CONTACTscript.js3How wide the fingertip and the test's pins are, in pixels: less, tighter rings.
STIFFscript.js160How stiff the slab is: more, it takes a new load sooner.
DAMPscript.js10How quickly the slab stops ringing after a change of load.
LIGHTscript.js1How bright the light behind the slab is.
SHARPscript.js0.7How fine the fringes are drawn against the screen: more, sharper and costlier.
RUNscript.jsusersThe word after the number while the test runs.
DONEscript.jsPassed at {users} usersThe words once the test has passed: {users} becomes the highest number.
BACKscript.js2.4The seconds before the button says Run stress test again.

Try them in the Playground

When to use it

For the action that matters in a tool for developers or engineers on a dark background: running a load test, a benchmark, a simulation, a check that puts the system to the test. It belongs on sites about materials, engineering, physics and optics, where polarised light says something by itself. It is a button to show off, one to a page, not one for a toolbar.

On phones

The slab is 60 pixels tall like the other buttons and 300 wide, or the screen minus 48; the stresses are worked out again for the real size. With no mouse a finger resting on it opens the rings under itself and, dragged across, takes them along (touch-action: pan-y, so up and down the page still scrolls). A tap starts the test; a finger that has been dragged lifts without starting it, as on any button. The canvas works at 0.7 times the screen's density, at most 1.4 pixels per pixel.

With reduced motion

No rings following the pointer and no springs. At the click the image of the test at its highest load, worked out once at the start, fades in on the slab and fades away at the end; the words change in a fade, with no slide and no blur, and pressed the slab darkens a little instead of shrinking.

Pitfalls

  • The finger made as three point bending lit the whole slab white even with a light touch: first order white covers a wide range of delay, from 150 to 350 nanometres. Now the finger is a local contact (Flamant, with the table pushing back under it) and bending only comes in the test, when the whole slab has to light up.
  • In beam theory the shear jumps at the supports and the pins, and sharp vertical lines showed across the slab: the moment smoothed with a bell about a third of the height wide, with the shear taken as its slope, removed them.
  • The 5 per cent of light far from the finger became a 25 per cent grey after sRGB encoding, and pressing fogged the whole slab: a photographer's curve before the encoding brings the black back, and the light the filters let through, a breath of blue, keeps the slab visible on the black page.
  • The stress in the rim falling off like an exponential made a wide white band, like a neon tube: with a Gauss bell the colours stay at the edge and the white is a thin line.
  • The change along the rim depended on which half, top or bottom, the pixel was in: on the round ends it made a cut at half height. Now it is a continuous function of the position.
  • With a high PEAK the table ended at 3600 nanometres and the middle of the slab went flat: now it runs to 6000, where the colours are already the pale pinks and greens of the high orders.
  • With the pointer already over the button when the page opens, no pointerenter arrives: the first pointermove counts as the entry.

Libraries

GSAP 3.15.0, IBM Plex Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 10 KB; the libraries: GSAP 28 KB.

Testing

Tested on 12 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All components