Skip to content
animorio
IT
All components

The marbled button

Buttons, Hover, PhysicsCanvas, GSAPAdvancedCompressed weight: Demo 12 KBGSAP 28 KBFreeDownload the zip

The Shuffle palette button of a colour palette tool, covered in marbled paper like the endpapers of an old book, with a paper label pasted on it. The pointer goes through the bath like a stylus and the ink follows it in swirls. At a click the new palette falls in a shower of drops from the point clicked: each drop pushes the old colours aside into thin rims, then a comb waves them.

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 marbled button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/eb-garamond@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the marbled button: the Shuffle palette button of a colour palette tool, a board covered in marbled paper with
         a paper label pasted on it. The pointer drags through the inks like a stylus; a click lets the new palette fall
         one drop per colour, each drop pushing the old pattern aside, and a comb draws them into feathers -->
    <div class="marble" data-marble>
      <button class="marble__btn" type="button" data-btn data-autoclic>
        <canvas class="marble__sheet" aria-hidden="true" data-sheet></canvas>
        <canvas class="marble__sheet marble__ghost" aria-hidden="true" data-ghost></canvas>
        <span class="marble__sheen" aria-hidden="true" data-sheen></span>
        <span class="marble__label" data-label>
          <span class="marble__icons" aria-hidden="true" data-icons>
            <svg class="marble__icon" viewBox="0 0 24 24" data-shuffle>
              <path d="M3 7h2.6c2.4 0 3.9 1.1 5.1 3.1l1.6 2.8c1.2 2 2.7 3.1 5.1 3.1H21"/>
              <path d="M18.4 13.4 21 16l-2.6 2.6"/>
              <path d="M3 16h2.6c1.5 0 2.6-.4 3.5-1.2"/>
              <path d="M13.9 8.2c1-.8 2.1-1.2 3.5-1.2H21"/>
              <path d="M18.4 4.4 21 7l-2.6 2.6"/>
            </svg>
            <svg class="marble__icon marble__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="marble__words" data-words>Shuffle palette</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.

50 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 marbled button” from Animorio and fit it into my site

What it does

On a white background a rectangular board with slightly rounded corners, covered in stone marbled paper like Turkish paper: drops of blue, brick red, ochre, petrol green and bone, each with smaller drops of another colour inside, crowded until they become stones, with thin pale veins between them; under the board the dark edge of the card. A paper label is pasted in the middle, ivory with a double rule, with the two crossed arrows of shuffle and Shuffle palette in Garamond. With the mouse over it, the paper takes a soft gloss that follows the pointer, and the pointer itself goes through the bath like a stylus: the ink round it follows it and curls into swirls that stay. Clicking, the words turn to Mixing inks and the new palette falls in a shower, one drop after another from the point clicked: each drop spreads and pushes the old colours aside, which squeeze into thin rims round the new stones; into half the stones falls a second, smaller drop of another colour. Then a comb goes across and waves the stones a little. The words turn to New palette with a tick that draws itself, and after a moment back to Shuffle palette. Every click moves on to the next palette. On a phone a finger dragged across combs the ink, a tap shuffles.

How it works

Every ink is a polygon

Every drop is a polygon of points floating on the bath, drawn on the canvas from the oldest to the newest. Every gesture (a drop, the comb, the stylus) moves all the points of all the inks the way the liquid would move them. The maths is Aubrey Jaffer's maths of marbling: the moves are continuous and never fold over themselves, so the polygons never cross and the shapes stay true marbled paper.

The drop that pushes

A drop of radius r falling at C moves each point P away from C so that its squared distance grows by r²: P' = C + (P − C) · √(1 + r² / |P − C|²). So the area of every ink stays the same and the old colours squeeze into thin rims round the new one. While the drop spreads, each frame applies only the growth of r² since the frame before: drops applied one after another at the same point add up.

The comb and the stylus

The comb has TINES teeth along the board: each point slides across by a bell (SHARPNESS wide) of its distance from the nearest tooth, so the waves come out round. The stylus is the pointer: its path, taken with getCoalescedEvents, is walked in short steps, and at each step the points nearby move with it along a gaussian TRAIL wide. In short steps the move never gets steep enough to fold the liquid over itself.

New points, old points

After every move, an edge stretched past 3.4 pixels gets new points along it, and two points too close become one. Only near the board, though: farther out, where nobody looks and neither the comb nor the stylus can bring anything back in, edges stay long. At the end of a shuffle every ink is painted on a hidden canvas in a colour of its own, at half size: those that show nowhere (buried under the new ones) are let go, and the others are cut to a margin round the board.

The shower of the new palette

There are as many drops as it takes to cover the board COVER times over, on a slightly shaken honeycomb, and they fall from the point clicked outwards, STAGGER seconds apart, each spreading in SPREAD seconds with expo.out. Into half the stones a second, smaller drop of another colour falls. The comb goes one way and the other way on alternate shuffles, so the ink does not drift off to one side.

Paper, veins, label

The pale veins round every ink are the same shape filled three times in the bath's colour, nudged a hair three ways, under the ink: it costs a third of stroking the outline. Over everything lies a paper grain with a few fibres, blended in overlay. The label is HTML: it keeps the width of its longest words, and when the words change the icon slides to its new place while the words swap with a blur.

Values to change

NameFileDefaultWhat it changes
COVERscript.js1.1How much of the board the new palette covers: 1 about all of it, less leaves more of the old.
SIZEscript.js11How wide a drop spreads, in pixels: the size of the stones.
STAGGERscript.js0.015The seconds between one drop and the next.
SPREADscript.js0.55The seconds a drop takes to spread.
COMBscript.js8How far the comb drags the ink after the drops, in pixels (0, no comb).
TINESscript.js3The teeth of the comb, across the height of the board.
SHARPNESSscript.js5How far from a tooth the ink still follows it, in pixels.
TRAILscript.js13How wide the pointer's trail through the ink is, in pixels.
DRAGscript.js0.8How much of the pointer's movement the ink follows: 0 none, 1 all of it.
VEINSscript.js0.55The pale veins round every ink: 0 none, 1 strong.
BUSYscript.jsMixing inksThe words while the drops spread.
DONEscript.jsNew paletteThe words once the new palette is in.
SEEDscript.js11The first sheet: another number, another pattern.
PALETTESscript.js[['#1d3557', '#a63d40', '#e9b44c', '#2f6f68', '#f3e6c8'], …]The palettes the button goes through in turn, one ink for each colour (the first is the first sheet's).

Try them in the Playground

When to use it

For the button that reshuffles or makes something at random in a creative tool: colour palettes, covers, patterns, themes, names. It belongs where paper, bookbinding and handwork belong: publishers, stationers, bookbinders, book and design sites. It is a button to show off, one to a page, not one for a toolbar.

On phones

The board is 60 pixels tall like the other buttons and 320 wide, or the screen minus 48; the sheet is drawn again at the real size. A finger dragged across combs the ink like the pointer (touch-action: pan-y, so up and down the page still scrolls); a tap shuffles, and the shower starts from where the finger touched.

With reduced motion

No stylus and no gloss following the pointer. At a click the new sheet is worked out all at once and the old one fades away on top of it; the words change in a fade, with no slide and no blur, and the board pressed darkens a little instead of shrinking.

Pitfalls

  • The comb with an exponential falloff from the tooth (the one in Jaffer's text) made sharp points, more flame stitch than marbled paper: with a gaussian bell the waves come out round.
  • After twenty shuffles the points had grown past a hundred and forty thousand, nearly all of them off the board: the edges of the old inks, pushed far out by every drop. Now off the board edges get no new points, the buried inks are found with a canvas of code colours and let go, and the others are cut to a margin (Sutherland and Hodgman): they stay under sixty thousand.
  • The veins as a stroke round every ink cost three times the fill, with so many thousands of points: three fills nudged a hair under the ink make the same vein for a third.
  • The comb always going the same way made the ink drift to one side, and the empty bath came in from the other edge: it goes one way and the other on alternate shuffles, and the first sheet is drawn past the edges too.
  • The drops of the shower in a random order looked like noise: from the point clicked outwards the shower reads as an answer to the click.
  • Words changing length made the label jump: the label keeps the width of its longest words, and the icon slides to its new place instead of jumping.

Libraries

GSAP 3.15.0, EB Garamond (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 12 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