
Tiles that rise
SVG, Hover, Physics
NewFree
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.
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 & 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>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
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 siteThe 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 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 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.
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 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.
| Name | File | Default | What it changes |
|---|---|---|---|
FLAKES | script.js | 90 | How many snowflakes are in the water. |
SHAKE | script.js | 14 | How many degrees the globe tilts when it is shaken. |
SWIRL | script.js | 1 | How hard the water swirls and how high it lifts the snow on a shake. |
FALL | script.js | 1 | How fast the snow sinks: lower is slower. |
FLUTTER | script.js | 1 | How much each flake swings from side to side as it falls. |
TILT | script.js | 6 | How many degrees the pointer tilts the globe. |
--water-deep | style.css | #183654 | The colour of the water at the edges (in the middle it is --water-light; the cottage is --wall, the firs --fir). |
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.
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.
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.
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.
Tested on 11 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.