Skip to content
animorio
IT
All components

The colour picker

Pickers, SVG, TransitionsGSAPMediumCompressed weight: Demo 4.9 KBGSAP 28 KBFreeDownload the zip

A mug with six colours under it: choosing one, the new paint rises inside the mug from the bottom with a rolling wave, the handle takes it when the wave gets there, the mug sways and a ring slides onto the swatch chosen; all the while steam rises from the cup.

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 colour picker</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/outfit@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the picker: a mug and six colours under it, over six real radio buttons. Choosing a colour, the new paint
         rises inside the mug from the bottom with a rolling wave, the handle takes it when the wave gets there, the
         mug sways, and a ring slides to the swatch chosen. Steam keeps rising from the cup -->
    <form class="pick" data-pick onsubmit="return false">
      <svg class="pick__mug" viewBox="0 0 260 240" aria-hidden="true" data-mug>
        <defs>
          <clipPath id="mug-body"><path d="M60 62 L68 188 Q70 205 87 205 L163 205 Q180 205 182 188 L190 62 Z"/></clipPath>
          <linearGradient id="mug-gloss" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" stop-color="#fff" stop-opacity="0"/>
            <stop offset="0.5" stop-color="#fff" stop-opacity="0.34"/>
            <stop offset="1" stop-color="#fff" stop-opacity="0"/>
          </linearGradient>
          <linearGradient id="mug-shade" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0.55" stop-color="#000" stop-opacity="0"/>
            <stop offset="1" stop-color="#000" stop-opacity="0.18"/>
          </linearGradient>
          <filter id="mug-soft" x="-20%" y="-50%" width="140%" height="200%"><feGaussianBlur stdDeviation="4"/></filter>
        </defs>
        <ellipse class="pick__shadow" cx="126" cy="214" rx="80" ry="9" filter="url(#mug-soft)"/>
        <g class="pick__steam" data-steam>
          <path d="M108 50c-7-9 7-15 0-24s7-15 0-22"/>
          <path d="M126 46c-7-9 7-15 0-24s7-15 0-22"/>
          <path d="M144 50c-7-9 7-15 0-24s7-15 0-22"/>
        </g>
        <path class="pick__handle" d="M186 88 C238 84 244 172 184 168 L182 148 C218 152 218 102 186 108 Z" data-handle/>
        <g clip-path="url(#mug-body)">
          <rect x="50" y="50" width="150" height="170" data-body/>
          <path data-paint/>
          <rect x="50" y="50" width="150" height="170" fill="url(#mug-shade)"/>
          <rect x="74" y="66" width="18" height="128" rx="9" fill="url(#mug-gloss)"/>
        </g>
        <ellipse cx="125" cy="62" rx="65" ry="13" data-rim/>
        <ellipse cx="125" cy="64" rx="56" ry="9.5" class="pick__coffee"/>
        <ellipse cx="125" cy="62" rx="64" ry="12.4" class="pick__lip"/>
      </svg>
      <fieldset class="pick__swatches" data-swatches data-autoclic>
        <legend class="pick__legend">Colour</legend>
        <span class="pick__ring" aria-hidden="true" data-ring></span>
      </fieldset>
      <p class="pick__name" aria-hidden="true"><span data-name></span></p>
      <p class="pick__note" data-note></p>
    </form>
  </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 colour picker” from Animorio and fit it into my site

What it does

On a white background a sage green ceramic mug full of coffee, with a shadow under it and three wisps of steam rising, drawing themselves and fading one after the other; below, six square swatches with rounded corners (Sage, Terracotta, Ink, Butter, Sky and Plum), the one chosen smaller inside a black ring, and below that the colour’s name and a line describing it. Choosing another colour the ring slides onto the new swatch, which shrinks with a bounce, and inside the mug the new paint rises from the bottom: its edge is a wave, still at first, rolling halfway and flattening at the end; the handle takes the colour when the wave gets there, the rim last, and the mug sways a little. The name rolls away upwards and the new one arrives from below, and the line underneath changes.

How it works

A mug in SVG

The mug is hand-drawn in SVG: the body, cut by a clipPath of its own shape, the handle, the rim, the coffee and a pale light on one side. The body’s colour is a plain rectangle inside the cut; over it, inside the same cut, the new paint rises.

The paint rising

The paint is a path from the bottom up to a wavy edge: the script redraws it on every frame with height = level + WAVE[0] · sin(x · WAVE[1] + phase). The level rises in FILL seconds with power2.inOut, the phase runs and the wave’s height follows sin(π · progress), so it is still at the start and flat at the end; then the body takes the colour and the paint goes.

Handle, rim and sway

In the same timeline the handle changes colour when the wave reaches its height (42 per cent of the way up), the rim at the end in the shaded colour, and the mug sways by SWAY degrees round its foot and settles with elastic.out.

Real swatches

Under the swatches there are six real radio buttons: arrows, screen readers and forms work by themselves. A single ring slides onto the swatch chosen with back.out, and the swatch shrinks to 0.74 inside it with a bounce; the name rolls over and the line underneath changes with a fade.

The steam and the preview

Three wisps of steam have a dash half as long as their line that runs along with stroke-dashoffset while they rise and fade, in an endless loop staggered between them. A click from a script on the swatches (the library’s preview) chooses the next colour.

Values to change

NameFileDefaultWhat it changes
COLOURSscript.js[['Sage', '#9bb38f', 'A soft green, like olive leaves.'], …]The colours: name, colour and a line about it.
STARTscript.js0The colour chosen when the page opens.
FILLscript.js1.1The seconds the new colour takes to rise.
WAVEscript.js[7, 0.075]The wave on top of the paint: how high, in pixels, and how close its crests are.
SWAYscript.js3How far the mug sways as it fills, in degrees.

Try them in the Playground

When to use it

For a product page with several colours (mugs, bags, shoes, chairs), for picking the colour of a theme or a label: wherever the colour chosen must show on the object straight away.

On phones

The mug shrinks with the screen and the swatches stay big enough for a finger; two quick taps on a swatch do not zoom the page.

With reduced motion

The mug changes colour at once, without the wave or the sway, the steam stands still, the ring and the name change without sliding.

Pitfalls

  • A colour chosen while the last one is still rising: the rise in progress finishes at once (progress(1)), so the new one always starts from a whole colour and not from half a mug.
  • A wave with the same height all the way up starts and ends crooked: its height follows sin(π · progress), still at the bottom and flat at the top.
  • The paint sits in the same clipPath as the body, under the light and the side shade: that way the new colour gets the same light as the ceramic straight away.

Libraries

GSAP 3.15.0, Outfit (font variabile) 5.3.0.

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

Testing

Tested on 3 October 2026

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

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