
The inchworm menu
Menus, Hover, Transitions
NewFree
A camera's focus frame sits on the current link. Pointing at another link the frame slides over and hunts for focus, opening and closing while the word goes from blurred to sharp, then its brackets blink green; a click takes the picture, with the viewfinder going black for an instant and a flash of light in the frame.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The Vue tab holds 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 viewfinder nav</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/spline-sans-mono@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the nav: the focus frame of a camera sits on the current link; pointed at, another link is brought into focus,
and a press takes the picture, with the viewfinder going black for an instant -->
<nav class="vf" aria-label="Main" data-nav>
<ul class="vf__list" data-list>
<li><a class="vf__link" href="#" aria-current="page" data-link><span data-word>Portraits</span></a></li>
<li><a class="vf__link" href="#" data-link data-autoclic><span data-word>Weddings</span></a></li>
<li><a class="vf__link" href="#" data-link data-autoclic><span data-word>Travel</span></a></li>
<li><a class="vf__link" href="#" data-link data-autoclic><span data-word>About</span></a></li>
</ul>
<!-- the faint frame that stays on the current link, and the focus frame that moves -->
<span class="vf__frame vf__frame--ghost" data-ghost aria-hidden="true"><i></i><i></i><i></i><i></i></span>
<span class="vf__frame vf__frame--af" data-af aria-hidden="true"><b class="vf__flash" data-flash></b><i></i><i></i><i></i><i></i></span>
<span class="vf__shutter" aria-hidden="true"><i data-blade></i><i data-blade></i></span>
</nav>
</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.
14 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 viewfinder nav” from Animorio and fit it into my siteThe frame is a span with four i at its corners, each a square of --arm pixels with only two borders, --line thick. The script puts it on a link's box (measured with offsetLeft, offsetTop, offsetWidth and offsetHeight) opened or closed by pad pixels: translate for the place and width and height for the size, so the brackets keep their thickness.
A timeline moves the box onto the link with expo.out in SLIDE seconds, while pad goes through the keyframes PAD + 11, PAD − 5, PAD + 3 and PAD in SLIDE × 0.7 plus HUNT seconds. The word pointed at is blurred by |pad − PAD| × 0.22 pixels, 3 at most: it is sharp exactly when the frame stops.
At the end the frame takes the is-locked class (green, with a 0.12 second colour transition), the line goes from 3 to 2 pixels, the arms go back from 12 to 9 pixels with back.out(3) and the corners blink (opacity from 0.25 to 1, three passes of 0.07 seconds).
Two black blades, each half the row plus a margin and with its origin on the outer edge, go from scaleY 0 to 1 in BLINK × 0.35 seconds, wait BLINK × 0.15 and open again in BLINK × 0.65; meanwhile a white radial gradient in the frame lights up at 0.7 and fades, and pad drops to PAD − 3 and comes back with elastic.out. A press on a link not yet in focus waits for the focus: the shot starts from there.
Tab onto a link (focus-visible) brings the frame there and Enter takes the shot; leaving the row with the pointer (after 0.25 seconds) or the focus brings the frame back to the current link, and the thin frame shows only while the other one is elsewhere. A ResizeObserver measures again when the words change width. The library's preview clicks the other links in turn.
| Name | File | Default | What it changes |
|---|---|---|---|
SLIDE | script.js | 0.32 | The seconds the frame takes to move to another link. |
HUNT | script.js | 0.5 | The seconds it takes to find focus once there. |
BLINK | script.js | 0.2 | The seconds of the shutter's blackout. |
PAD | script.js | 5 | How far the frame stands off the word in focus, in pixels. |
For the nav of people who work with images: a photographer, a video studio, an equipment rental, a film festival, a photography school, a photo app.
The text goes from 12 to 16 pixels with the width and the gaps shrink, so the four links fit one row even on 390 pixels; each link is 45 pixels tall and a tap focuses and shoots, without waiting for a double tap.
The frame jumps onto the link without sliding or hunting for focus, the word does not blur, the brackets turn green without blinking, the viewfinder does not go black and the shot is just a short light in the frame; the thin frame on the current link appears and disappears without fading.
GSAP 3.15.0, Spline Sans Mono (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 4.8 KB; the libraries: GSAP 28 KB.
Tested on 4 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.