Skip to content
animorio
IT
Back to the library

The snow globe

Physics, SVGGSAPMediumCompressed weight: Demo 10 KBGSAP 28 KBFreeDownload the zip

A glass snow globe on a walnut base with a brass plaque, and inside a cottage with three firs. A click shakes it: the base tilts back and forth, the light runs across the glass, the water swirls and lifts the star-shaped flakes, which sink slowly, swinging, and settle on the roofs and the trees. The pointer tilts it a little and the snow follows.

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>Snow globe</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <header class="copy">
      <p class="copy__shop" data-reveal>Alder &amp; Pine Gift Shop</p>
      <h1 class="copy__title" data-title>Shake up a little winter</h1>
      <p class="copy__line" data-reveal>A hand-blown glass globe on a walnut base, with a cottage and three firs from the Fernhollow woods inside.</p>
      <p class="copy__meta" data-reveal><span class="copy__price">$38</span><span>14 cm tall, water and glitter-free snow</span></p>
    </header>

    <div class="shelf">
      <!-- the whole globe is the button: a click (or a tap) shakes it -->
      <button class="globe" type="button" aria-label="Shake the snow globe" data-globe data-autoclic>
        <svg class="globe__svg" viewBox="-215 -200 430 440" aria-hidden="true" focusable="false">
          <defs>
            <radialGradient id="sg-water" cx="0.4" cy="0.3" r="0.85">
              <stop offset="0" style="stop-color: var(--water-light)"/>
              <stop offset="1" style="stop-color: var(--water-deep)"/>
            </radialGradient>
            <linearGradient id="sg-wood" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" style="stop-color: var(--wood-light)"/>
              <stop offset="1" style="stop-color: var(--wood-dark)"/>
            </linearGradient>
            <linearGradient id="sg-brass" x1="0" y1="0" x2="1" y2="1">
              <stop offset="0" style="stop-color: var(--brass-light)"/>
              <stop offset="1" style="stop-color: var(--brass-dark)"/>
            </linearGradient>
            <linearGradient id="sg-sheen" 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.38"/>
              <stop offset="1" stop-color="#fff" stop-opacity="0"/>
            </linearGradient>
            <clipPath id="sg-clip"><circle r="160"/></clipPath>
            <clipPath id="sg-base"><path d="M-124 114H124L154 196H-154Z"/></clipPath>
            <!-- a six-armed snowflake: a soft blue outline under a white star, so it also shows on the snow -->
            <g id="sg-flake">
              <path class="flake__edge" d="M0 -4V4M-3.46 -2L3.46 2M-3.46 2L3.46 -2M-1.2 -3.1L0 -2.2L1.2 -3.1M-1.2 3.1L0 2.2L1.2 3.1M-3.3 -0.4L-2.4 -1.2M3.3 0.4L2.4 1.2M3.3 -0.4L2.4 -1.2M-3.3 0.4L-2.4 1.2"/>
              <path class="flake__body" d="M0 -4V4M-3.46 -2L3.46 2M-3.46 2L3.46 -2M-1.2 -3.1L0 -2.2L1.2 -3.1M-1.2 3.1L0 2.2L1.2 3.1M-3.3 -0.4L-2.4 -1.2M3.3 0.4L2.4 1.2M3.3 -0.4L2.4 -1.2M-3.3 0.4L-2.4 1.2"/>
            </g>
          </defs>

          <ellipse class="shadow" cx="0" cy="222" rx="176" ry="12" data-shadow/>

          <!-- tilt: the pointer and the hover; shake: the click. Both turn about the bottom of the base -->
          <g data-tilt>
            <g data-shake>
              <g data-water clip-path="url(#sg-clip)">
                <circle class="water" r="160" fill="url(#sg-water)"/>
                <path class="hill hill--far" d="M-170 40C-120 4 -80 10 -40 26C0 0 50 -14 100 12C130 22 150 14 170 20V120H-170Z"/>
                <path class="hill hill--near" d="M-170 58C-110 38 -60 50 0 46C60 40 120 34 170 50V120H-170Z"/>
                <g data-trees></g>
                <g class="house">
                  <rect class="house__chimney" x="-22" y="-26" width="12" height="32"/>
                  <rect class="house__chimney-cap" x="-24" y="-28" width="16" height="5" rx="1.5"/>
                  <rect class="house__wall" x="-78" y="6" width="72" height="64"/>
                  <path class="house__boards" d="M-78 22H-6M-78 38H-6M-78 54H-6"/>
                  <path class="house__roof" d="M-94 16L-42 -38L10 16L4 20L-42 -28L-88 20Z"/>
                  <path class="house__gable" d="M-78 10L-42 -26L-6 10Z"/>
                  <circle class="house__window" cx="-42" cy="-6" r="7"/>
                  <path class="house__frame" d="M-42 -13V1M-49 -6H-35"/>
                  <rect class="house__window" x="-70" y="28" width="16" height="15" rx="1"/>
                  <path class="house__frame" d="M-62 28V43M-70 35.5H-54"/>
                  <path class="house__door" d="M-32 70V40Q-24 32 -16 40V70Z"/>
                  <circle class="house__knob" cx="-20" cy="56" r="1.4"/>
                </g>
                <path class="ground" data-ground/>
                <g data-caps></g>
                <g data-flakes></g>
              </g>

              <!-- the glass: the rim, the reflection that stays with the light, the sheen that runs across on a shake -->
              <circle class="glass__rim" r="160"/>
              <g clip-path="url(#sg-clip)">
                <rect class="glass__sheen" x="-90" y="-200" width="90" height="400" fill="url(#sg-sheen)" data-sheen/>
              </g>
              <g data-shine>
                <path class="glass__shine" d="M-118 -78C-98 -122 -58 -146 -18 -150C-60 -136 -92 -112 -110 -70Z"/>
                <path class="glass__shine glass__shine--small" d="M112 46C118 30 120 18 120 6C126 20 124 34 118 50Z"/>
              </g>

              <!-- the walnut base with its brass plaque -->
              <g class="base">
                <ellipse class="base__collar" cx="0" cy="112" rx="122" ry="10"/>
                <path class="base__body" d="M-124 114H124L154 196H-154Z"/>
                <path class="base__grain" clip-path="url(#sg-base)" d="M-118 132C-60 128 20 136 120 130M-130 150C-40 146 60 154 134 148M-142 170C-50 166 40 174 146 168M-148 186C-60 182 50 190 150 184"/>
                <rect class="base__foot" x="-168" y="194" width="336" height="18" rx="5"/>
                <rect class="base__plate" x="-70" y="138" width="140" height="42" rx="6" fill="url(#sg-brass)"/>
                <rect class="base__plate-edge" x="-64" y="143" width="128" height="32" rx="4"/>
                <text class="base__small" x="0" y="155" text-anchor="middle">GREETINGS FROM</text>
                <text class="base__name" x="0" y="171" text-anchor="middle">Fernhollow</text>
              </g>
            </g>
          </g>
        </svg>
      </button>
      <p class="hint" data-hint>Click the globe to shake it</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.

34 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 snow globe” from Animorio and fit it into my site

What it does

The product page of a made-up souvenir shop, Alder & Pine Gift Shop: on the left the title, the description and the price, on the right the glass globe on a walnut base with the brass plaque «Greetings from Fernhollow». Inside there is a blue winter night, with hills, a red cottage with lit windows and three firs; the snow already lies on the roofs, on the trees and on the ground. On arrival the letters of the title rise with a bounce and the globe drops on the shelf: the landing squashes the base a little, which springs back, and the knock lifts the snow, which falls again. A click shakes the globe: it tilts right and left, less and less, with a spring at the end, a band of light runs across the glass, the reflections stay on the side of the light and slide on the glass as the globe tilts, and the letters of the title jump one after the other. The water swirls and churns, lifts every flake (the ones on the roofs and the trees too) and then lets it sink slowly: every flake is a drawn six-pointed star that spins and swings from side to side, and where it touches a roof, a branch or the snow on the ground it stops; the white layer on the roofs and the branches grows as the snow settles. Moving the pointer tilts the globe a little and the snow still in the water follows; hovering lifts it a little off the shelf.

How it works

The scene is made of surfaces

The roof and every tier of the firs are triangles, the chimney is a flat line, the ground is a curve. A function tells, for every x, which surface is highest and at what height: that is where a falling flake settles. Near the sides, where the curved glass comes before the ground, the flake rests against the glass.

Every flake follows the water and sinks

Every flake has a position and a velocity. At each step the velocity moves towards the water around it (a vortex plus two crossing waves, which calm down by themselves) and the weight pulls it down: with the water braking, it falls at a slow, steady speed. On top of that it swings from side to side on a sine of its own, and spins faster when it moves fast.

The water lags behind the glass

The physics runs inside the globe. When the globe tilts, the weight seen from inside tilts the other way; when it speeds up, the flakes feel a push the opposite way; when it turns, the water turns late and the flakes are dragged backwards. It is the same for the shake and for the pointer tilt: that is why the snow follows.

The shake is a timeline

On a click a GSAP timeline takes the rotation and the shift of the globe through a series of shrinking swings, with a spring at the end, squashes the base a little, runs the band of light across the glass and makes the letters of the title jump. At the same moment the water gets a vortex and a churn, and every flake gets a push upwards and sideways.

The glass reflects and the snow piles up

The reflections are in a group that turns against the globe: they stay on the side of the light and slide on the glass. Every roof and fir tier has a white line, drawn only where it is open to the sky, which thickens with the flakes resting on it (a tween with a bounce) and thins out when the shake takes them away.

Values to change

NameFileDefaultWhat it changes
FLAKESscript.js90How many snowflakes are in the water.
SHAKEscript.js14How many degrees the globe tilts when it is shaken.
SWIRLscript.js1How hard the water swirls and how high it lifts the snow on a shake.
FALLscript.js1How fast the snow sinks: lower is slower.
FLUTTERscript.js1How much each flake swings from side to side as it falls.
TILTscript.js6How many degrees the pointer tilts the globe.
--water-deepstyle.css#183654The colour of the water at the edges (in the middle it is --water-light; the cottage is --wall, the firs --fir).

Try them in the Playground

When to use it

For a product page in a gift shop, a Christmas or winter campaign, a digital greeting card, an advent calendar, the page of a mountain place or a 404 page that makes up for itself: anywhere an object to touch that rewards the click is needed.

On phones

The same animations with the sizes adapted: the words on top and the globe below, as wide as the screen. A tap shakes the globe; dragging a finger tilts it and, on release, it springs back upright.

With reduced motion

Nothing moves: the snow already lies, the globe stays still and the words fade in. On a click the snow fades out and comes back settled another way.

Pitfalls

  • With the click push given only to the flakes, the water braked them at once and the snow barely rose: it takes a stronger push and lighter braking, and above all water that keeps turning by itself for a couple of seconds.
  • The white line of a lower fir tier, drawn along the whole triangle, ran over the tier above and looked like an outline: the line is drawn only where that tier is really the highest surface.
  • The glass as a resting place also worked halfway up: flakes pushed against the sides stuck to the glass in mid-air. The glass holds the snow only in its lower part.
  • The globe transforms (pointer tilt, shake, squash) are written by the script on the two SVG groups, with the pivot at the bottom of the base: so the physics knows the same angle and the same position that are seen.
  • A CSS variable in the stop-color attribute of SVG gradients does not work: it has to go in style.

Libraries

GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Instrument Sans (font variabile) 5.3.0.

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