
Words that melt into each other
Text, Scroll, SVG
NewFree
A carousel seen from three quarters, all in SVG: the striped roof with its valance and bulbs, the mirrored centre column and the little horses on twisted poles. It really turns in perspective, the horses rise and fall out of step, then it slows, stops with a sway and starts again. A click changes the speed.
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 giostra dei cavalli</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">Hollis Bay Pleasure Pier</p>
<h1 class="titolo">Pick a horse,<br>hold on tight.</h1>
<p class="frase">The painted gallopers at the end of the pier turn every summer evening, under the lights, until the last ride.</p>
<button class="velocita" type="button" data-velocita>
<span class="velocita__fondo" aria-hidden="true"></span>
<svg class="velocita__ferro" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6.5 20.5C4 17 3.6 11 6 7.2 8 4 11 3 12 3s4 1 6 4.2c2.4 3.8 2 9.8-.5 13.3" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" /><circle cx="6.6" cy="12" r="1.1" fill="currentColor" /><circle cx="17.4" cy="12" r="1.1" fill="currentColor" /><circle cx="8.6" cy="6.6" r="1.1" fill="currentColor" /><circle cx="15.4" cy="6.6" r="1.1" fill="currentColor" /></svg>
<span class="velocita__scritta">Speed: <span data-nome-velocita>steady</span></span>
</button>
</header>
<div class="palco" data-palco>
<svg class="scena" data-scena viewBox="0 0 900 820" preserveAspectRatio="xMidYMid meet" role="img" aria-label="A carousel with painted horses seen from three quarters: the platform turns, the horses rise and fall on their twisted poles, then it slows down and stops. Click to change the speed.">
<defs>
<linearGradient id="g-specchio" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" style="stop-color: var(--specchio-chiaro)" />
<stop offset="1" style="stop-color: var(--specchio)" />
</linearGradient>
<linearGradient id="g-ombra-tetto" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#000" stop-opacity="0.38" />
<stop offset="0.3" stop-color="#000" stop-opacity="0" />
<stop offset="0.62" stop-color="#000" stop-opacity="0" />
<stop offset="1" stop-color="#000" stop-opacity="0.42" />
</linearGradient>
<linearGradient id="g-colonna" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" style="stop-color: var(--colonna-scura)" />
<stop offset="0.45" style="stop-color: var(--colonna)" />
<stop offset="1" style="stop-color: var(--colonna-scura)" />
</linearGradient>
<linearGradient id="g-bordo" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#000" stop-opacity="0.4" />
<stop offset="0.5" stop-color="#000" stop-opacity="0" />
<stop offset="1" stop-color="#000" stop-opacity="0.4" />
</linearGradient>
</defs>
<ellipse class="ombra" cx="450" cy="752" rx="372" ry="30" />
<g class="giostra" data-giostra>
<!-- la piattaforma: il bordo, il pavimento con le assi che girano -->
<g data-piattaforma>
<ellipse class="piatto-sotto" cx="450" cy="648" rx="344" ry="90" />
<rect class="piatto-sotto" x="106" y="618" width="688" height="30" />
<g data-fascia></g>
<rect x="106" y="618" width="688" height="30" fill="url(#g-bordo)" />
<ellipse class="pavimento" cx="450" cy="618" rx="344" ry="90" />
<g data-assi></g>
<ellipse class="pavimento-orlo" cx="450" cy="618" rx="334" ry="86" />
</g>
<!-- i cavalli dietro la colonna -->
<g data-dietro></g>
<!-- la colonna centrale con gli specchi -->
<g data-colonna>
<rect x="404" y="236" width="92" height="384" fill="url(#g-colonna)" />
<g data-specchi></g>
<rect class="oro" x="398" y="300" width="104" height="10" rx="3" />
<rect class="oro" x="398" y="548" width="104" height="10" rx="3" />
<ellipse class="oro-scuro" cx="450" cy="620" rx="62" ry="16" />
<ellipse class="oro" cx="450" cy="614" rx="56" ry="13" />
</g>
<!-- i cavalli davanti alla colonna -->
<g data-davanti></g>
<!-- il tetto a strisce, la mantovana e le lampadine -->
<g data-tetto>
<path class="tetto" data-falda d="" />
<g data-strisce></g>
<path data-ombra-tetto fill="url(#g-ombra-tetto)" d="" />
<g data-mantovana></g>
<path class="orlo-tetto" data-orlo d="" />
<g data-lampadine></g>
<!-- il pennacchio in cima -->
<line class="asta" x1="450" y1="74" x2="450" y2="22" />
<path class="bandiera" data-bandiera d="" />
<circle class="oro" cx="450" cy="76" r="9" />
<circle class="oro-chiaro" cx="447" cy="73" r="3" />
</g>
</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>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 carousel” from Animorio and fit it into my siteThe state of the carousel is one number: A, the degrees turned by the platform. One draw function, called by GSAP’s ticker every frame, works out everything from it: the stripes, the scallops, the bulbs, the mirrors, the boards, the panels, the horses, the poles and the pennant. The carousel is seen from three quarters, so every circle is an ellipse: the point at angle g sits at x = centre + r·sin g and y = height + r·0.26·cos g. With a positive cos g it is in front, with a negative cos g it is behind.
The roof is a cone: the cream slope is fixed, and on top are the red stripes, each a sector between two angles. Of each sector only the front part is drawn, cut between −90° and 90°: a triangle from the top of the roof to seven points on the rim. The same cut works for the scallops of the valance (with a half-moon lower edge, 11 + 17·sin(π·u)), for the panels on the rim of the platform and for the mirrors of the column. A fixed dark gradient on the sides of the roof does the rest of the roundness.
The column sits between two empty groups: data-dietro before it, data-davanti after it. Every frame the horses are sorted by cos g and each goes into the right group with appendChild, only when needed. The farther they are, the smaller (from 0.78 to 1.04). Each horse is tangent to the circle, so its width is scale(cos g, 1): in front it heads right, behind it heads left, at the sides it is foreshortened (never below 0.2).
The rise is tied to the turn, not to time: up = ALTEZZA_SALTO × (0.5 − 0.5·cos(A × SALTI + phase)), with a different phase for each horse. So when the carousel slows down the horses slow down too, and when it stops they stop. The pitch is the sine of the same phase. The twists of the pole are slanted dashes shifted by A / 18: after a whole turn they are back in place, so the repeating loop does not jump.
A timeline repeating forever: the run is a tween from 0 to 1 with a hand-made curve (soft ramp, full speed, soft ramp) that lands on a whole number of turns; then the sway, five keyframes of extra degrees (back, forward, back, still), and a pause. The click changes the timeline’s timeScale with a 0.9 s tween, so the carousel speeds up or slows down without jumps, and it jolts the carousel with an elastic. The pennant uses the speed measured between two frames: it flutters and lifts while running, droops when still.
| Name | File | Default | What it changes |
|---|---|---|---|
DURATA_CORSA | script.js | 10 | Seconds of each run, from the start to the stop. |
GIRI | script.js | 3 | Platform turns in each run. |
CAVALLI | script.js | 6 | How many horses ride on the platform. |
SALTI | script.js | 4 | Rises and falls of each horse per turn (a whole number, so the loop comes back the same). |
ALTEZZA_SALTO | script.js | 30 | How high the horses climb the pole. |
DONDOLIO | script.js | 7 | Degrees of the sway when the carousel stops. |
--rosso, --crema, --oro | style.css | #D8443B, #F6E7CF, #E9B949 | The roof stripes, the valance and the brass. |
For fairs, funfairs, village fêtes, toy shops, children’s pages, birthday invitations and summer or Christmas pages: a cheerful scene people watch turning for a long time and that invites a touch.
The fair copy goes on top and the carousel below, smaller but the same: same horses, same turns, same sway. The speed changes by tapping the carousel or the button.
The carousel is already still in place with its lights on and fades in; the click only changes the speed label, with a fade, with nothing moving.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.5 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.