Skip to content
animorio
IT
All components

The Kundt's tube button

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

The Tune speakers button of an app for a pair of speakers, made as the Kundt's tube of physics classes: a glass tube with brass caps and, along its bottom, a bed of very fine golden powder. At a click the frequency climbs and stops on one resonance after another: the air in the tube becomes a standing wave, the powder dances where the air moves most and flows to heap up where the air is still, with fine ridges between one heap and the next. The last resonance leaves nine heaps in a row: Tuned to room.

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 Kundt's tube button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/saira@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the Kundt's tube button: the Tune speakers button of a speaker app, made as a glass tube with brass caps and a
         bed of fine golden powder along its bottom. The tuning sweeps the tube through its resonances: at each one the
         air stands in a wave, the powder dances where the air moves most and gathers in heaps where it is still, with
         fine ridges in between, until the last pattern stays: tuned -->
    <div class="kundt" data-kundt>
      <button class="kundt__btn" type="button" data-btn data-autoclic>
        <span class="kundt__haze" aria-hidden="true"></span>
        <canvas class="kundt__canvas" aria-hidden="true" data-canvas></canvas>
        <span class="kundt__glass" aria-hidden="true">
          <span class="kundt__glint" data-glint></span>
          <span class="kundt__glint" data-sweep></span>
          <span class="kundt__scale"></span>
        </span>
        <span class="kundt__cap kundt__cap--left" aria-hidden="true"></span>
        <span class="kundt__cap kundt__cap--right" aria-hidden="true"></span>
        <span class="kundt__print">
          <span class="kundt__label" data-label>
            <span class="kundt__icons" aria-hidden="true" data-icons>
              <svg class="kundt__icon" viewBox="0 0 24 24" data-fork>
                <path d="M8.6 2.6v7.6a3.4 3.4 0 0 0 6.8 0V2.6" data-prongs/>
                <path d="M12 13.6v7.8"/>
              </svg>
              <svg class="kundt__icon kundt__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="kundt__words" data-words>Tune speakers</span>
            <span class="kundt__hz" aria-hidden="true" data-hz></span>
          </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.

28 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 Kundt's tube button” from Animorio and fit it into my site

What it does

On a black background a pill 60 pixels tall made as a Kundt's tube, the glass tube physics classes use to show sound: dark glass with the lamp's reflection along its top edge, two caps of turned brass at the ends, with three grooves each, and along the bottom of the glass a bed of very fine golden powder, a little higher against the caps; under the powder a scale printed on the glass, a tick every 5 pixels. At the top, printed on the glass, Tune speakers with a tuning fork. With the mouse over it, a reflection slides along the glass to the pointer and the pointer makes the glass sing like a wet finger on the rim of a wine glass: under it the powder fizzes, swells a little and raises fine ridges that sink again behind it. Pressing, the glass gets a little knock: the whole bed of powder hops and the pill sinks. At a click the tuning starts: the words turn to Tuning with the frequency climbing, 686 Hz, 1,029 Hz, 1,715 Hz, 2,744 Hz, and the prongs of the tuning fork shiver. On each resonance the frequency holds and the air in the tube becomes a standing wave: the powder dances where the air moves most, puffs of dust rise into the light, smeared by the air going back and forth, and the powder flows towards the nodes, where the air is still, and heaps up there; where the air moves most Kundt's ridges stand up, thin and close together. Between one resonance and the next the powder calms down, and where the frequency runs over a resonance without stopping it fizzes for a moment. The last resonance plays louder and gathers all the powder: nine cone-shaped heaps, half a heap against each cap, half a wavelength apart, with the ridges between them. The words turn to Tuned to room with a tick that draws itself, and a reflection runs along the glass. After a moment the tube gets a knock and shivers, the powder turns fluid and runs level again, and the words go back to Tune speakers. On a phone a finger drawn along the glass makes it sing and a tap starts the tuning. With the keyboard the focus shows a golden ring and the reflection in the middle of the glass; Enter or Space tunes.

How it works

The resonances of the tube

A tube closed at both ends resonates at n times c / 2L, with c = 343 m/s and L the length of the tube (TUBE): with 50 centimetres, 343 Hz for every n. In resonance n the speed of the air along the tube goes as sin(nπx/L), still at both caps. Every resonance answers the frequency with its own bell, 1/√(1 + Q²(f/fn − fn/f)²) with Q = 13. What matters to the powder is the speed squared, on average: the resonances add up in it each on its own (their phases go their separate ways), so every pattern comes out symmetric, and when the frequency runs over a resonance it does not stop on, the powder fizzes for a moment.

The powder flows to the nodes

The force of the standing wave pushes the powder down the slope of the speed squared: for a single resonance −sin(2kx), towards the nodes, where the air is still. The top layer, as deep as the shaking (MOBILE), flows with that push; the packed bottom stays where it is (PACK). It is an upwind flux between columns half a pixel wide, in steps short enough that no column gives more than half its moving layer, and nothing piles up past the tallest a heap may be, below the words.

The sandpile

After every step of the flow, a pass of the sandpile: a column steeper than the angle of repose (REPOSE) gives half its excess to its neighbour. Shaken, the powder holds much lower slopes, like a liquid: heaps left by an earlier resonance, where the air now moves, melt away; at the nodes, where the air is still, the powder keeps its angle and the heaps stand as cones. The tuning plays softly on the first resonances and loudly on the last: the flow goes as the fourth power of the loudness, so every stop shows its pattern but only the last gathers all the powder, in heaps that are nearly all the same.

Grains, dust and ridges

Grains leave the columns shaken past a threshold, as many as the shaking says, with a push towards the node; one in eight jumps higher, and motes of fine dust rise into the light and float. When they land they bring their powder to the column they fall on: no powder is ever lost (tested over thirty seconds of clicks, one every 2.8 seconds). They are drawn as streaks as long as the air's back and forth at that spot. Kundt's ridges are a layer of their own, a ridge every STRIAE pixels with the same volume of powder taken from beside it: they grow where the air moves most, sink while the frequency runs on, and stay when the sound stops.

The bed painted pixel by pixel

The bed is an ImageData at two pixels per CSS pixel, made again on every frame in which something moves. For every column the slope says how much light it takes from the lamp, above and a little to the left: the surface by its own slope, the face of a heap by the slope of the heap; under the surface the powder is darker the lower it lies, the valleys are darker, and a fixed grain, anchored to the bottom of the glass, runs through it all. The colours come from a table of 256 tints made from the three powder variables. Shaken, the surface glitters and swells a little.

The singing glass and the way back to rest

A pointer drawn along the glass shakes it in a bell 15 pixels wide, the more the faster it goes: the powder fizzes, swells and raises ridges that sink again in half a second. A press is a little knock on the whole bed. To go back to rest the tube shivers (GSAP keyframes) and the bed turns fluid: a diffusion solved implicitly with the Thomas algorithm, which can be as fast as it likes without ever overshooting, plus a pull towards the shape of the bed at rest, scaled on every frame to the powder lying on the bottom, so nothing is lost. When nothing moves the canvas is not drawn again.

Values to change

NameFileDefaultWhat it changes
BUSYscript.jsTuningThe words while the frequency climbs, before the frequency.
DONEscript.jsTuned to roomThe words once the powder has settled.
MODESscript.js[2, 3, 5, 8]The resonances the tuning stops on, in order: the last one is the pattern that stays (with 8, nine heaps). With high resonances the heaps are many and small.
SWEEPscript.js3.6The seconds of the tuning, from the first note to the last.
TUBEscript.js50The length of the tube, in centimetres: it sets the frequencies on the label (with 50 centimetres, 343 Hz for every resonance).
POWDERscript.js7How deep the powder lies at rest, in pixels.
REPOSEscript.js46The steepest slope the powder holds, in degrees: higher, taller and narrower heaps.
DRIFTscript.js1How hard the standing wave pushes the powder to its nodes: 0, the powder dances but stays where it is.
STRIAEscript.js3.2The spacing of the fine ridges where the air moves most, in pixels: 0, no ridges.
DUSTscript.js1How much fine dust rises and floats in the light: 0, none.
HUMscript.js1How much a pointer drawn along the glass makes the powder tremble: 0, not at all.
HOLDscript.js2.4The seconds the button says Tuned to room before it goes back to rest.

Try them in the Playground

When to use it

For the action that measures or adjusts something with sound and takes a few seconds: tuning speakers to the room, the sound check before a live stream, calibrating a microphone or a pair of headphones, analysing a track. It belongs in music, audio and smart home apps and on science and instrument sites; the black background makes the powder glow. It is a button to show off, one to a page, not one for a toolbar.

On phones

The pill is 60 pixels tall and 340 wide, or the screen less 32; the caps stay 30 pixels long (26 below 360) and the powder fills the glass that is left, at the same scale, so with the same patterns. A finger drawn along the glass makes it sing like the mouse (touch-action: pan-y, so up and down the page still scrolls); a tap gives the knock and starts the tuning. The reflection that follows the mouse is not there on a phone.

With reduced motion

No hopping, no flow, no dust in the air, no moving reflections and no shiver. At a click the frequency goes through the resonances as before, and on each one the bed fades into that resonance's pattern, worked out at once: heaps on the nodes with rounded tops and the ridges between them, the first patterns only in part and the last one in full. The words change in a fade, the tick is already drawn, and the way back to rest is a fade to the level bed. The pill pressed darkens a little instead of shrinking.

Pitfalls

  • Adding up the resonances with their signs, while the frequency ran between an even and an odd resonance the two added up on one half of the tube and cancelled on the other: the powder all ran to the left cap, into a huge heap. Adding up their squares, as the average over time does when the phases go their separate ways, every pattern comes out symmetric.
  • With only hopping grains the powder was too slow: a heap took more than three seconds to form, and a resonance lasts half a second. Now most of it is carried by the flow of the top layer, and the grains in the air are what can be seen.
  • In a single frame the flow poured up to 6 pixels of powder into the same column, at the edge of a heap, and the sandpile passed once at the end could not keep up: heaps came out with straight walls. Now every step of the flow is followed by a pass of the sandpile.
  • The heaps of the first resonance would not go away any more (no powder is lost), and in the end two heaps were three times the others. Now shaken powder holds low slopes, like a liquid, and the tuning plays softly on the first resonances: the flow goes as the fourth power of the loudness, and only the last resonance gathers all the powder.
  • The pull towards the shape of the bed at rest started from the powder on the bottom at that moment, but the powder still in the air landed later: on every round the tube gained a little, 3% every forty seconds of clicks. Now the shape is scaled on every frame to the powder lying on the bottom, and the total does not change by a thousandth.
  • With the pointer over it the grains hopped a pixel high, against the lit edge of a bed of the same colour: nothing showed. Now the shaken powder swells a little and fine ridges rise under the pointer and sink after it; and the pointer's speed counts from 260 pixels a second, the pace of a calm hand.
  • The frequency went from 686 to 1,029 Hz and the centred words moved sideways with every extra figure: the frequency keeps the room of its widest figures, aligned left.

Libraries

GSAP 3.15.0, Saira (font variabile, con l'asse della larghezza) 5.3.0.

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

Testing

Tested on 6 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