
The loader that becomes a logo
Transitions, SVG, Text
NewFree
A page change in the minimal style: the page is one huge word and its O is vermilion. On a click the counter of the O opens like a lens with the next page already inside it, tiny, word and all; then the view flies into the O, which grows and slides to the middle until the hole is the whole screen.
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 through-the-O transition</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage" data-stage>
<!-- the first page: one huge word, and the next page waits inside its O -->
<section class="page page--a is-on" data-page="a" aria-label="Shop">
<header class="bar">
<span class="brand">Orra</span>
<nav class="nav" aria-label="Pages">
<a class="w" href="#shop" aria-current="page"><span class="w__t">Shop</span></a>
<a class="w" href="#frames" data-go="b"><span class="w__t">Frames</span></a>
</nav>
</header>
<h1 class="big" data-big aria-label="Look">L<span class="o" data-o>o<i class="o__base"></i></span>ok</h1>
<div class="below" data-late>
<p class="lede">Hand-made frames and ground lenses, from one small workshop.</p>
<a class="go w" href="#frames" data-go="b" data-autoclic>
<span class="w__t">See the frames</span>
<svg class="go__arrow" viewBox="0 0 26 12" aria-hidden="true"><path d="M1 6h22M18.5 1.5 23.5 6l-5 4.5"/></svg>
</a>
</div>
<footer class="foot" data-late>
<span>Eyewear and lenses</span>
<span>Since 1968</span>
</footer>
</section>
<!-- the second page: dark, with its own O to go back through -->
<section class="page page--b" data-page="b" aria-label="Frames" aria-hidden="true">
<header class="bar">
<span class="brand">Orra</span>
<nav class="nav" aria-label="Pages">
<a class="w" href="#shop" data-go="a"><span class="w__t">Shop</span></a>
<a class="w" href="#frames" aria-current="page"><span class="w__t">Frames</span></a>
</nav>
</header>
<h2 class="big" data-big aria-label="Round">R<span class="o" data-o>o<i class="o__base"></i></span>und</h2>
<ul class="list" aria-label="Round frames">
<li class="row" data-late><span class="row__rule" data-rule></span><span class="row__name">Round 46</span><span class="row__kind">Tortoise acetate</span><span class="row__size">46 mm</span></li>
<li class="row" data-late><span class="row__rule" data-rule></span><span class="row__name">Round 49</span><span class="row__kind">Black acetate</span><span class="row__size">49 mm</span></li>
<li class="row" data-late><span class="row__rule" data-rule></span><span class="row__name">Round 52</span><span class="row__kind">Crystal</span><span class="row__size">52 mm</span></li>
</ul>
<div class="below below--b" data-late>
<a class="go go--back w" href="#shop" data-go="a" data-autoclic>
<svg class="go__arrow" viewBox="0 0 26 12" aria-hidden="true"><path d="M25 6H3M7.5 1.5 2.5 6l5 4.5"/></svg>
<span class="w__t">Back to the shop</span>
</a>
</div>
</section>
</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.
38 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 through-the-O transition” from Animorio and fit it into my siteThe hole in the letter is not guessed: the script draws an o on a canvas in the same typeface (Archivo, weight 700, expanded width), starts from the middle of the letter and walks right, left, up and down until it meets ink. Then it walks along the diagonal to see how square the counter is and turns it into a superellipse, |x/a|^n + |y/b|^n = 1. The measures are kept in ems, so they hold for any size of the word; the real place of the O on the page comes from an empty box resting on its baseline.
The new page sits on top of the old one, cut by a 96-point clip-path polygon that draws the superellipse. The clip-path is applied before the transform, so the lens is written in the small page's own pixels: radii divided by the page's scale. While it is small, a layer of its colour as big as the screen sits behind it (a ::before with a negative inset, not a box-shadow, which left a light seam on the edge).
The old page grows with its transform-origin at the top left: the scale is exponential (exp(ln(most) · z)), so the flight feels steady and power3.in makes it speed up. Meanwhile the centre of the counter slides to the centre of the screen. The largest scale is the one at which the ellipse inside the counter covers the corners: the square root of (W/2)²/a² + (H/2)²/b². The page inside the lens grows with the same scale times a factor that at first fits its word in the lens (FIT), and reaches 1 before the end; the point at the centre of the lens moves from its word to the middle of the page.
Each letter is an inline-block whose font-stretch is tied to the --w variable. On arrival the word starts at 108 and springs back to 125 with elastic.out, staggered from the O out to both sides; on load the letters start at 62, Archivo's narrowest width, and rise from below one after another.
The flight is a state made of numbers (how open the lens is, how far the zoom has gone) and every frame redraws it with the measures of the moment: if the window changes halfway, the word is measured again, the counter is worked out again and the flight carries on right. On a phone it is the same transition with the word fitted to the width. With reduced motion the two pages swap with a fade.
| Name | File | Default | What it changes |
|---|---|---|---|
OPEN | script.js | 0.6 | The seconds the lens takes to open inside the O. |
ZOOM | script.js | 1.15 | The seconds of the flight through the O. |
PULL | script.js | 0.02 | How far the page steps back before the flight: 0 = it goes at once. |
FIT | script.js | 0.86 | How wide the next page's word is inside the lens, against the hole: 1 = edge to edge. |
SPEED | script.js | 1 | The speed of everything: 2 is twice as fast, 0.5 half as fast. |
To go from the home page to a section on a site where a single word is the cover: an eyewear brand, an optician, a photo studio, an agency with an O in its name, the opening page of a collection. It works with any word that has an o, a d, a p or a q: just move the baseline box to the right letter.
The same transition: the word shrinks to fit the width of the screen and the lens is smaller, but the next page fits inside it with its word; the flight takes the counter to the middle of the tall screen and widens it to the corners.
Nothing flies: the next page fades in over the first one, with its word and its list already in place.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.8 KB; the libraries: GSAP 28 KB.
Tested on 19 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.