
The loader that becomes a logo
Transitions, SVG, Text
NewFree
A minimal page change: the diaphragm of a lens, a few dark blades with thin edges, turns shut over the old page and snaps onto a vermilion pinhole while the f-number climbs to f/22. Then it turns open the other way on the new page and the title widens out of the middle of the hole, letter after letter.
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 aperture transition</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage" data-stage>
<!-- the first page: everything is centred on the point where the lens closes -->
<section class="page page--a is-on" data-page="a" aria-label="Still light">
<header class="bar">
<span class="brand">Oriel</span>
<nav class="nav" aria-label="Pages">
<a href="#still-light" aria-current="page">Still light</a>
<a href="#portraits" data-go="b">Portraits</a>
</nav>
</header>
<div class="hero">
<h1 class="title" data-title>Still light</h1>
<div class="below">
<p class="lede" data-rise>Photographs made by one north window, slowly, with the shutter open a little longer than it should be.</p>
<a class="go" href="#portraits" data-go="b" data-autoclic data-rise>
<span class="go__text">See the portraits</span>
<svg class="go__iris" viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="8.5"/><path class="go__hex" d="M10 4.6 14.68 7.3v5.4L10 15.4 5.32 12.7V7.3Z"/></svg>
</a>
</div>
</div>
<footer class="foot">
<span>A photography studio</span>
<span>Film and paper</span>
</footer>
</section>
<!-- the second page: its title widens out of the hole the lens leaves -->
<section class="page page--b" data-page="b" aria-label="Portraits" aria-hidden="true">
<header class="bar">
<span class="brand">Oriel</span>
<nav class="nav" aria-label="Pages">
<a href="#still-light" data-go="a">Still light</a>
<a href="#portraits" aria-current="page">Portraits</a>
</nav>
</header>
<div class="hero">
<h2 class="title" data-title>Portraits</h2>
<div class="below">
<p class="lede" data-rise>Forty faces, the same chair and the same hour of the afternoon, one exposure each.</p>
<a class="go" href="#still-light" data-go="a" data-autoclic data-rise>
<span class="go__text">Back to still light</span>
<svg class="go__iris" viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="8.5"/><path class="go__hex" d="M10 4.6 14.68 7.3v5.4L10 15.4 5.32 12.7V7.3Z"/></svg>
</a>
</div>
</div>
<footer class="foot">
<span>A photography studio</span>
<span>Sittings by letter</span>
</footer>
</section>
<!-- the accent seen through the smallest hole, the blades of the lens and the f-number (all moved by the script) -->
<div class="spot" data-spot aria-hidden="true"></div>
<svg class="iris" data-iris aria-hidden="true">
<path class="iris__blades" data-blades fill-rule="evenodd"/>
<path class="iris__edges" data-edges/>
</svg>
<span class="stop" data-stop aria-hidden="true">f/22</span>
</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.
33 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 aperture transition” from Animorio and fit it into my siteThe diaphragm is a single SVG as big as the stage with two paths. The first is a rectangle bigger than the screen with a regular polygon inside it, filled with fill-rule evenodd: the polygon becomes a hole. The second is the blades' edges: each side of the hole carries on past its corner out of the screen, so the lines turn like a pinwheel, as in a real lens. The polygon has one side per blade, at distance a from the centre, and turns by rot degrees.
The size of the hole is not animated in pixels but on a scale: a = PINHOLE times (R / PINHOLE) to the power k, with R half the screen's diagonal. With k going from 1 to 0 the hole halves in the same time over and over, like a steady zoom, and the last stretch, where the hole is small, does not go by in a flash. Closing uses power2.in, so it speeds up into the snap; the same timeline turns rot from 0 to TURN and redraws both paths on every update.
At the pinhole the blades go SNAP pixels further in 0.07 seconds and come back with elastic.out(1, 0.4), turning a degree and a half more and then back; the number under the hole feels the knock and bounces 3 pixels. Behind the blades there is a vermilion circle as big as the pinhole out to its corners: it grows in the last third of the closing, so in the hole the page gives way to colour. The number counts the stops from f/1.4 to f/22 following k and only shows while the hole is small.
The title is split into centred inline-block letters, with font-stretch and font-weight tied to the --w and --g variables (Roboto Flex runs from 25 to 151 in width). The letters start at --w 25 and --g 200 and widen with back.out(1.7), staggered from the centre: the middle ones grow first and push the others away, and the overshoot takes each letter a breath past its width before it settles. The title is measured with the letters at 110 width, so even the top of the bounce stays inside the screen. The middle of the capitals sits right on the centre of the stage, where the hole closes.
Each change is one timeline with the labels close, shut, open and title, and timeScale for SPEED; the pages swap behind the shut blades. A click that comes while the page is changing waits in a queue. The diaphragm is already shut on the first frame, before the fonts arrive. With reduced motion the diaphragm never shows: the old page fades out, the new one fades in with its title already in place, then the text.
| Name | File | Default | What it changes |
|---|---|---|---|
BLADES | script.js | 6 | How many blades the diaphragm has: 5 makes a pentagon of a hole, 9 is nearly round. |
TURN | script.js | 60 | How many degrees the blades turn while they close (and back while they open): 0 = the hole shrinks without turning. |
CLOSE | script.js | 0.9 | The seconds the diaphragm takes to close on the old page. |
HOLD | script.js | 0.55 | The seconds it stays shut on the pinhole of colour. |
OPEN | script.js | 1.25 | The seconds the diaphragm takes to open on the new page. |
PINHOLE | script.js | 6 | How big the pinhole is, in pixels from the centre to a side. |
SNAP | script.js | 2 | How many pixels the blades go past the pinhole when they snap shut: 0 = they just stop. |
SPEED | script.js | 1 | The speed of everything: 2 is twice as fast, 0.5 half as fast. |
To move from one page to another on a site about pictures: a photographer or a photo studio, a print lab, a film festival, a gallery, a cinematographer's portfolio. It also works as the site's opening, with the diaphragm opening on the first page.
The same transition with the sizes adapted: the diaphragm closes on the centre of the tall screen, the titles shrink to fit the width even at the widest point of their bounce and the text wraps under the title. A tap on the link starts it and brings it back.
Nothing moves or turns: the diaphragm never shows, the old page fades out as the new one fades in with its title already in place, then the text and the link fade in.
GSAP 3.15.0, Roboto Flex (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.3 KB; the libraries: GSAP 28 KB.
Tested on 16 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.