
The menu under the page
Menus, 3D, Physics, Transitions
NewFree
The card of a hand-blown glass vase, half full of water, on a pale table in the sun: the pointer is the sun. The vase throws a shadow in the colour of its glass and the water, a lens, gathers the light into a bright patch; the shadow is worked out by tracing rays in three colours through slices of the vase. Choosing another glass heats the vase up again, a glow climbs it from the foot and it cools into the new colour; Add to bag wraps it in bubble wrap and tapes the seam.
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 vase in the sun</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/imbue@5.3.0/opsz.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/hanken-grotesk@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the card of a hand-blown glass vase standing in the sun. The pointer is the sun: the vase throws a shadow in
the colour of its glass, with the bright line of light that the water inside focuses on the table. Another
glass heats the vase up again and it cools into the new colour; Add to bag wraps it in bubble wrap. The vase
and the light are worked out by the script -->
<article class="vase" aria-labelledby="vase-name" data-vase data-autoclic>
<div class="vase__shot" data-shot>
<canvas class="vase__canvas" role="img" aria-label="The Drift vase in sea glass, half full of water, standing in the sun on a pale table" data-canvas></canvas>
</div>
<div class="vase__body">
<div class="vase__head">
<h2 class="vase__name" id="vase-name">Drift vase</h2>
<p class="vase__price" data-price>€68</p>
</div>
<p class="vase__meta">Hand-blown glass · 24 cm</p>
<div class="glass" role="radiogroup" aria-labelledby="glass-label" data-glass>
<p class="glass__label" id="glass-label">Glass</p>
<p class="glass__name" aria-hidden="true" data-name>Sea glass</p>
<div class="glass__tiles">
<label class="tile">
<input class="tile__input" type="radio" name="glass" value="sea" checked>
<span class="tile__glass" aria-hidden="true"></span>
<span class="sr">Sea glass</span>
</label>
<label class="tile">
<input class="tile__input" type="radio" name="glass" value="amber">
<span class="tile__glass" aria-hidden="true"></span>
<span class="sr">Amber</span>
</label>
<label class="tile">
<input class="tile__input" type="radio" name="glass" value="cobalt">
<span class="tile__glass" aria-hidden="true"></span>
<span class="sr">Cobalt</span>
</label>
<label class="tile">
<input class="tile__input" type="radio" name="glass" value="smoke">
<span class="tile__glass" aria-hidden="true"></span>
<span class="sr">Smoke</span>
</label>
</div>
</div>
<div class="buy" data-buy>
<button class="add" type="button" data-add>
<span class="add__fill" aria-hidden="true" data-fill></span>
<span class="add__icon" aria-hidden="true">
<svg class="add__bag" viewBox="0 0 24 24" data-bag><path d="M5.6 8.4h12.8l-.9 11.2a1.2 1.2 0 0 1-1.2 1.1H7.7a1.2 1.2 0 0 1-1.2-1.1z"/><path d="M9 10.4V7.2a3 3 0 0 1 6 0v3.2"/></svg>
<svg class="add__tick" viewBox="0 0 24 24" data-tick><path d="M5.5 12.6l4.2 4.1 8.8-9.3"/></svg>
</span>
<span class="add__label" data-label>Add to bag</span>
</button>
<button class="undo" type="button" data-undo hidden>Undo</button>
</div>
<p class="sr" aria-live="polite" data-live></p>
</div>
</article>
</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.
39 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 vase in the sun” from Animorio and fit it into my siteThe vase is a surface of revolution seen by a camera raised 26 degrees. For every pixel the script finds the height the eye sees first (the vase's slices, ellipses laid from the lip down) and how much glass the gaze crosses: the front wall, the water or the air, then the back wall, or the thick bottom. The glass takes light away as its colour to the power of the glass crossed (Beer-Lambert): pale in the middle, deep at the edges and in the foot, never black, with a fine dark rim at the outline. It is a layer that multiplies the table behind, worked out once for each glass.
On top, a layer that adds up at every frame in which the sun moves: the room reflected with Fresnel and a tall window on the left, the sun as a sharp glint (Blinn, exponent 900) and as a broad sheen, the reflection off the inside of the back wall, which nearly vanishes under water because glass against water reflects very little, and the glow of the glass when the sun is behind it. The light adds up in linear light, as the difference between sRGB(behind + light) and sRGB(behind): added in sRGB it would wash everything out.
The vase is cut into 56 horizontal slices. In each slice 220 rays of the sun, in red, green and blue, cross the circle of glass, the water or the air and the glass again: at every surface they bend with Snell, with the index the slice shows to a ray coming down at a slant (Bravais), and lose light with Fresnel and in the glass with its colour. They reach the table after a way as long as the slice's height times the cotangent of the sun's height: where they crowd there is the water's light, where they are missing, the shadow. The three colours have slightly different indices (SPREAD) and the shadow softens with the distance (SOFT).
The slices become two small images, one that darkens the table and one that adds the gathered light, laid down with an affine transform along the direction away from the sun and squeezed by the perspective. Part of the light through the hand-blown glass (the seeds and ripples of glass made by hand) spreads inside the shadow in its colour; under the foot the shadow is cut out and the table takes the light of the thick glass. The rays are traced again only when the sun's height changes by more than a degree: their way along the table is worked out at every frame.
Every height of the vase has its own temperature. Choosing a glass, a front climbs from the foot in HEAT[0] seconds: behind it the glass is hot along a ramp, and where the front has just passed the colour becomes the new one, hidden by the glow. Then every height cools exponentially, faster where the glass is thin, and the glow's colour comes from a scale running from dark red to yellow white, stronger where the gaze crosses more glass. The table round it takes the warm light.
A sheet that follows the vase's profile, a little wider: its edge goes round from right to left, then the sheet's end comes back to the seam and two strips of tape close it, in WRAP seconds. The bubbles are a hexagonal lattice on the surface, the same size at every height, drawn all together in a few paths; each has the sun's glint where its dome faces halfway between the sun and the eye. The shadow turns milky and takes a speck of light for each bubble.
| Name | File | Default | What it changes |
|---|---|---|---|
SUN | script.js | [232, 27] | Where the sun stands when nobody points: round the vase in degrees (0 in front, 90 right, 180 behind), and how high. |
HEIGHT | script.js | [17, 66] | How high the sun goes, in degrees: with the pointer far from the vase, and right over it. |
FOLLOW | script.js | [34, 0.9] | The spring that takes the sun where the pointer is: how stiff, and how much it is held back (1 = no bounce). |
WATER | script.js | 0.62 | How full of water the vase is, from 0 to 1: the water is the lens that gathers the light. |
SPREAD | script.js | 3 | How far the glass and the water split the light into colours (1 = as much as real glass). |
SOFT | script.js | 1.2 | How big the sun is, in degrees: the bigger, the softer the shadows. |
HEAT | script.js | [0.55, 1.7] | Changing glass: the seconds the glow takes to climb the vase, and the vase to cool down. |
WRAP | script.js | 1.25 | The seconds the bubble wrap takes to go round the vase and have its seam taped. |
WORDS | script.js | ['Wrapping it up', 'In your bag'] | The button's words while the vase is being wrapped, and after. |
For the card of a glass or crystal product in an online shop: a vase, a carafe, a tumbler, a bottle, a lamp; wherever a clear object has colours to choose from and deserves to be seen in real light, and for the moment it goes into the bag.
The card is 340 pixels wide, or the screen minus 32, and the picture is drawn again at the real size. A finger resting on the picture puts the sun there, and sliding it sideways the sun follows: the picture has touch-action: pan-y, so up and down the page scrolls. Let go, the sun stays where the finger left it. The tiles are 44 pixels and the buttons 50 high.
The sun stays put and does not follow the pointer, and the vase does not arrive hot. Changing glass, the new colour comes in a fade, with no glow; the bubble wrap comes and goes in a fade, without going round; the chosen tile is already up, without rising, and the button's words change in a fade.
GSAP 3.15.0, Imbue (font variabile) 5.3.0, Hanken Grotesk (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 22 KB; the libraries: GSAP 28 KB.
Tested on 6 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.