Skip to content
animorio
IT
Back to the library

The washing machine

SVGGSAP, CSS onlyAdvancedCompressed weight: Demo 12 KBGSAP 28 KBFreeDownload the zip

A washing machine seen from the front: the clothes jump from the line into the door, the water rises with foam and bubbles, then rinse and spin, with the machine shaking and walking across the floor. At the end the door opens and the clothes fly back to the line to dry. The display counts down the minutes; a click changes the program.

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>La lavatrice</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="banco" data-banco>
    <header class="testo">
      <p class="marchio">Spinwell Launderette</p>
      <h1 class="titolo">In by nine,<br>dry by noon.</h1>
      <p class="frase">Drop your bag on Tannery Street: we wash it, rinse it, spin it and peg it out in the yard to dry in the sun.</p>
      <button class="programma" type="button" data-programma>
        <span class="programma__fondo" aria-hidden="true"></span>
        <svg class="programma__manopola" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.2" fill="none" stroke="currentColor" stroke-width="1.8" /><path d="M12 12V5.6" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" /></svg>
        <span class="programma__scritta">Next program</span>
      </button>
      <p class="ora" aria-live="polite"><span class="ora__etichetta">Now running</span> <span class="ora__nome" data-ora>Cotton 40°, 1200 rpm</span></p>
    </header>

    <div class="palco" data-palco>
      <svg class="scena" data-scena viewBox="30 110 960 575" preserveAspectRatio="xMidYMid meet" role="img" aria-label="A washing machine seen from the front: the clothes tumble behind the round door, the water rises with foam and bubbles, the drum spins and the machine shakes, then the door opens and the clothes fly out to dry on a line. Click to change the program.">
        <defs>
          <radialGradient id="g-cestello" cx="0.5" cy="0.45" r="0.6">
            <stop offset="0" style="stop-color: var(--cestello-chiaro)" />
            <stop offset="1" style="stop-color: var(--cestello)" />
          </radialGradient>
          <linearGradient id="g-corpo" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" style="stop-color: var(--bianco)" />
            <stop offset="0.82" style="stop-color: var(--bianco)" />
            <stop offset="1" style="stop-color: var(--bianco-ombra)" />
          </linearGradient>
          <linearGradient id="g-cromo" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0" style="stop-color: var(--cromo-chiaro)" />
            <stop offset="0.5" style="stop-color: var(--cromo)" />
            <stop offset="1" style="stop-color: var(--cromo-chiaro)" />
          </linearGradient>
          <clipPath id="c-oblo"><circle cx="260" cy="445" r="96" /></clipPath>
          <filter id="f-scia" x="-20%" y="-20%" width="140%" height="140%"><feGaussianBlur stdDeviation="4" /></filter>
        </defs>

        <!-- il pavimento della lavanderia -->
        <rect class="pavimento" x="40" y="640" width="940" height="30" rx="6" />
        <path class="piastrelle" d="M160 640V670M300 640V670M440 640V670M580 640V670M720 640V670M860 640V670" />

        <!-- il filo per stendere, coi suoi due pali e le mollette -->
        <g data-stendino>
          <rect class="palo" x="512" y="150" width="10" height="492" rx="4" />
          <rect class="palo" x="968" y="150" width="10" height="492" rx="4" />
          <rect class="palo-testa" x="504" y="146" width="26" height="10" rx="4" />
          <rect class="palo-testa" x="960" y="146" width="26" height="10" rx="4" />
          <path class="filo" data-filo d="M520 170Q745 222 970 170" />
        </g>

        <ellipse class="ombra" data-ombra cx="260" cy="641" rx="176" ry="9" />

        <!-- la lavatrice: il gruppo mosso dal disegno (deriva e tremore), il figlio per GSAP (il sobbalzo) -->
        <g data-macchina>
          <g data-sbuffi></g>
          <g data-corpo>
            <rect class="piede" x="122" y="626" width="34" height="14" rx="3" />
            <rect class="piede" x="364" y="626" width="34" height="14" rx="3" />
            <rect fill="url(#g-corpo)" class="corpo" x="100" y="210" width="320" height="420" rx="18" />
            <path class="linea" d="M100 292H420" />
            <path class="linea" d="M112 598H408" />
            <text class="targa" x="260" y="619">SPINWELL</text>
            <!-- il cassetto del detersivo -->
            <rect class="cassetto" x="118" y="228" width="88" height="44" rx="6" />
            <rect class="cassetto-presa" x="140" y="258" width="44" height="6" rx="3" />
            <!-- il display -->
            <rect class="display" x="218" y="226" width="132" height="50" rx="7" />
            <g class="display__testo" data-display>
              <text class="display__programma" data-d-programma x="228" y="243">COTTON 40°</text>
              <text class="display__tempo" data-d-tempo x="228" y="268">1:28</text>
              <text class="display__fase" data-d-fase x="340" y="267">LOAD</text>
            </g>
            <!-- la manopola dei programmi -->
            <circle class="manopola-fondo" cx="384" cy="251" r="25" />
            <g data-manopola>
              <circle class="manopola" cx="384" cy="251" r="19" />
              <rect class="manopola-segno" x="382" y="234" width="4" height="12" rx="2" />
            </g>

            <!-- l'interno visto dall'oblò -->
            <circle class="incavo" cx="260" cy="445" r="124" />
            <circle class="guarnizione" cx="260" cy="445" r="104" />
            <g clip-path="url(#c-oblo)">
              <circle fill="url(#g-cestello)" cx="260" cy="445" r="98" />
              <g data-cestello></g>
              <g data-dentro></g>
              <g data-scia filter="url(#f-scia)" opacity="0"></g>
              <path class="getto" data-getto d="M196 352Q214 372 212 420" opacity="0" />
              <path class="acqua" data-acqua d="" />
              <g data-bolle></g>
              <g data-schiuma></g>
            </g>

            <!-- l'oblò: ruota sulla cerniera a sinistra -->
            <g data-porta>
              <circle class="anello" stroke="url(#g-cromo)" cx="260" cy="445" r="106" />
              <circle class="anello-dentro" cx="260" cy="445" r="96" />
              <circle class="vetro" data-vetro cx="260" cy="445" r="94" />
              <path class="riflesso" data-riflesso d="M196 396A80 80 0 0 1 232 366M188 420A80 80 0 0 1 192 408" />
              <rect class="maniglia" x="364" y="424" width="14" height="42" rx="6" />
            </g>
            <rect class="cerniera" x="134" y="410" width="12" height="22" rx="3" />
            <rect class="cerniera" x="134" y="458" width="12" height="22" rx="3" />
          </g>
        </g>

        <!-- i panni quando sono fuori dalla lavatrice (sul filo o in volo) -->
        <g data-fuori></g>
        <g data-mollette></g>
      </svg>
    </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.

48 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 washing machine” from Animorio and fit it into my site

What it does

On opening the washing machine drops from above and lands with a bounce and two puffs of dust, and the four clothes (a red T-shirt, a yellow sock, blue shorts and a striped green towel) fall onto the line, which sags and sways. Then one by one they jump off the pegs, which spring open, and fly with a flip into the open door; the door slams shut and the machine jolts. On the display LOAD turns into WASH and the minutes start going down. A jet of water comes in, the level rises in waves, bubbles rise from the bottom and foam grows on the surface; the drum with its holes and paddles turns and the clothes tumble: they ride up the wall and fall back. In the rinse some water drains, clearer water comes in, the foam nearly disappears and the drum turns the other way. Then the drain and the spin: the clothes press against the glass, the drum speeds up until it is a blur of colours, the display shows the revs per minute, the machine shakes and with every jolt walks a little across the floor, with a puff under its feet. It brakes, the clothes drop to the bottom, DONE and 0:00 appear, the door opens and the clothes fly one by one to the line, which bounces at each arrival; the machine hops back to its spot and it all starts again. A click on the scene or on the «Next program» button turns the dial to the next program (Cotton, Delicate, Quick, Wool, Extra hot): temperature, minutes, water colour, foam, revs, how much it shakes and how far it walks all change. Copy for the made-up launderette Spinwell.

How it works

Everything from a few numbers

The state of the machine is an object of numbers: door (0 closed, 1 open), water, foam, tumble (0 clothes resting on the bottom, 1 tumbling), spin (0 free, 1 pressed against the glass), lav and cen (the turns of the wash and of the spin), shake, mx (how far it has walked), progress and phase. Each piece of clothing has p (0 on the line, 1 in the drum) and colpo, the bounce after a landing. One draw function, called by GSAP's ticker every frame, works out all the shapes from these numbers.

Tumbling clothes

Each piece flips over every 150° of drum: for 72% of the loop it rides up the wall to 110° from the bottom, then falls with y growing like v² (gravity) and x going back to the middle, and lands exactly where the climb starts again. Four pieces a quarter apart never fall together. The resting position, the tumbling one and the one pressed against the glass are blended by tumble and spin; rotations always blend along the shortest way, with no idle spins.

In and out of the door

A flying piece sits in a layer above the whole drawing; when it is in the drum and the door starts closing it moves into the layer clipped by the door circle, under the water and the glass. The flight is a straight line between the line and the bottom of the drum with an arc of sin(π·p) × 150 and a full turn of rotation; the scale goes from 1 to 0.58 and the hold point moves from the peg to the middle of the piece. The line is a curve that sags with the weight of the hanging clothes and bounces when one arrives.

Water, foam and bubbles

The water surface is a line of points with a wave and a slope that follows the drum's direction; the foam is seventeen white circles that float on the surface and breathe, the bubbles rise at different speeds and vanish when they pass it. The spin is a tween from 0 to 1 with a hand-made curve, the integral of a trapezoid speed: it rises, holds and brakes. At full speed the clothes fade and in their place a blurred ring in their colours goes round.

The timeline and the click

A timeline repeating forever tells the whole story, from loading to the hop back home, and ends exactly as it began; even the breeze on the line makes a whole number of swings per loop, so the restart cannot be seen. The display reads phase and progress and counts down the program's minutes. The click stops nothing: it changes the program, and a tween slowly brings the revs factor (which makes it shake and walk more or less), the foam and the water colour to the new values, while the dial snaps round with an elastic.

Values to change

NameFileDefaultWhat it changes
DURATA_LAVAGGIOscript.js6Seconds of washing; the rinse lasts 0.8 times as long.
GIRI_CENTRIFUGAscript.js14Drum turns in the spin, with the 1200 rpm program.
TREMOREscript.js3How much the machine shakes in the spin.
SPOSTAMENTOscript.js18How far it walks across the floor during the spin.
SCHIUMAscript.js1How much foam the detergent makes.
BOLLEscript.js16Bubbles rising in the water.
--acqua, --accento, --display-testostyle.css#4C9BE0, #E8505B, #8DF0C4The water of the first program, the button and the display text.

Try them in the Playground

When to use it

For launderettes, dry cleaners, detergents, laundry pickup services, holiday rentals and home apps: a cheerful scene that tells the whole service in half a minute and invites a touch.

On phones

The launderette copy goes on top and the scene below, smaller but the same: same clothes, same water, same spin and same line. The program changes by tapping the scene or the button.

With reduced motion

The machine is still halfway through the wash, door closed, clothes on the bottom, water and foam, and it fades in; the click changes the program: the display and the label fade out and back in, the water changes colour, nothing moves.

Pitfalls

  • A piece entering the door must move from the top layer to the one clipped by the circle only when it is all inside the drum and the door starts to close: earlier it would be cut in flight, later it would pass over the glass.
  • Blending two rotations with a plain mix spins the piece by hundreds of degrees at once, since the tumbling rotation keeps growing: blend the difference reduced between −180° and 180°.
  • The drum direction changes only while the clothes rest on the bottom (tumble at 0): halfway through a flip the piece would jump to the other side of the drum.
  • A CSS class with opacity beats the opacity attribute: to hide the bubbles use style.opacity, or they stay visible with no water.
  • GSAP's jolt goes on the machine's child: the outer group already has its transform written every frame for the shake and the walk, and GSAP would wipe it.

Libraries

GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.

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

Testing

Tested on 11 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 animations