
Stacking certificates
Hover, Images
NewFree
A minimal-style hover gallery for an invented studio’s prints: six narrow panels between hairlines; the one under the pointer opens on a spring while the others make room, the print inside slides slower than the edge and the upright name lies down into a title that gains width and weight.
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>Sallow, landscape prints</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>
<header class="top" data-enter>
<span class="top__name">Sallow</span>
<span class="top__note">Landscape prints, autumn edition</span>
</header>
<!-- the gallery: narrow panels side by side between hairlines; the panel under the pointer opens wide on a spring,
the others make room, the print inside slides slower than the edge and the name turns from upright to level -->
<section class="gallery" data-gallery aria-label="Prints">
<button class="panel" type="button" data-panel style="--paper: #d8d1c2">
<span class="panel__art" data-art>
<svg viewBox="0 140 600 660" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<rect width="600" height="800" class="paper" />
<circle class="accent" cx="380" cy="300" r="46" />
<path d="M0 420H600" class="ink" />
<path d="M0 470H600M0 515H600M0 556H600M0 592H600M0 624H600M0 652H600M0 676H600M0 697H600M0 715H600" class="fine" />
<path d="M0 420C120 404 210 402 300 412S470 426 600 404V420H0Z" class="fill" />
</svg>
</span>
<span class="panel__upright" data-upright>Tidewater</span>
<span class="panel__title" data-title>Tidewater</span>
<span class="panel__line" data-line>Low sun on a flat sea, nine lines of water.</span>
</button>
<button class="panel" type="button" data-panel style="--paper: #cdd1c9">
<span class="panel__art" data-art>
<svg viewBox="0 140 600 660" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<rect width="600" height="800" class="paper" />
<path d="M0 800V560H120V500H230V430H340V360H450V300H600V800Z" class="fill" />
<path d="M0 560H120V500H230V430H340V360H450V300H600" class="ink" />
<path d="M60 560V800M175 500V800M285 430V800M395 360V800M525 300V800" class="fine" />
<rect class="accent" x="438" y="262" width="24" height="38" />
</svg>
</span>
<span class="panel__upright" data-upright>Quarry</span>
<span class="panel__title" data-title>Quarry</span>
<span class="panel__line" data-line>Steps of cut stone climbing to one red marker.</span>
</button>
<button class="panel" type="button" data-panel style="--paper: #ddd3c1">
<span class="panel__art" data-art>
<svg viewBox="0 140 600 660" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<rect width="600" height="800" class="paper" />
<path d="M0 470H600M0 560H600M0 650H600M0 740H600" class="fine" />
<g class="fill">
<circle cx="60" cy="440" r="26" /><circle cx="160" cy="440" r="26" /><circle cx="260" cy="440" r="26" /><circle cx="360" cy="440" r="26" /><circle cx="460" cy="440" r="26" /><circle cx="560" cy="440" r="26" />
<circle cx="110" cy="528" r="30" /><circle cx="210" cy="528" r="30" /><circle cx="310" cy="528" r="30" /><circle cx="410" cy="528" r="30" /><circle cx="510" cy="528" r="30" />
<circle cx="60" cy="616" r="34" /><circle cx="160" cy="616" r="34" /><circle cx="360" cy="616" r="34" /><circle cx="460" cy="616" r="34" /><circle cx="560" cy="616" r="34" />
</g>
<circle class="accent" cx="260" cy="616" r="34" />
</svg>
</span>
<span class="panel__upright" data-upright>Orchard</span>
<span class="panel__title" data-title>Orchard</span>
<span class="panel__line" data-line>Rows of apple trees, and the one that ripened first.</span>
</button>
<button class="panel" type="button" data-panel style="--paper: #d4cdd3">
<span class="panel__art" data-art>
<svg viewBox="0 140 600 660" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<rect width="600" height="800" class="paper" />
<path d="M0 520C140 440 260 470 360 430S520 360 600 380V800H0Z" class="fill" />
<path d="M0 600C120 560 250 590 380 540S540 500 600 510" class="ink" />
<path d="M0 660C150 630 280 650 400 610S560 580 600 590M0 720C130 700 260 712 420 680S560 660 600 664" class="fine" />
<circle class="accent" cx="150" cy="250" r="22" />
</svg>
</span>
<span class="panel__upright" data-upright>Dunes</span>
<span class="panel__title" data-title>Dunes</span>
<span class="panel__line" data-line>Wind-drawn ridges under a small evening moon.</span>
</button>
<button class="panel" type="button" data-panel style="--paper: #d9cebd">
<span class="panel__art" data-art>
<svg viewBox="0 140 600 660" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<rect width="600" height="800" class="paper" />
<path d="M170 800V420A130 130 0 0 1 430 420V800Z" class="fill" />
<path d="M170 800V420A130 130 0 0 1 430 420V800" class="ink" />
<path d="M230 800V430A70 70 0 0 1 370 430V800" class="fine" />
<path d="M0 800H600" class="ink" />
<rect class="accent" x="284" y="560" width="32" height="240" />
</svg>
</span>
<span class="panel__upright" data-upright>Kiln</span>
<span class="panel__title" data-title>Kiln</span>
<span class="panel__line" data-line>A brick arch with the fire still glowing inside.</span>
</button>
<button class="panel" type="button" data-panel style="--paper: #c9d1ce">
<span class="panel__art" data-art>
<svg viewBox="0 140 600 660" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<rect width="600" height="800" class="paper" />
<path d="M120 800V460L300 330L480 460V800" class="ink" />
<path d="M180 800V417M240 800V374M300 800V330M360 800V374M420 800V417M120 540H480M120 620H480M120 700H480" class="fine" />
<path d="M120 460L300 330L480 460" class="ink" />
<circle class="accent" cx="300" cy="470" r="20" />
</svg>
</span>
<span class="panel__upright" data-upright>Glasshouse</span>
<span class="panel__title" data-title>Glasshouse</span>
<span class="panel__line" data-line>Iron ribs, thin panes, one bloom under the roof.</span>
</button>
</section>
<footer class="bottom" data-enter>
<span>Six prints on cotton paper</span>
<span class="bottom__hint" data-hint>Pass over a print</span>
</footer>
</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.
45 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 images that open like an accordion” from Animorio and fit it into my siteEvery panel has a weight: 1 when closed and, when open, the one that makes it take OPEN_RATIO of the row. On every frame the row is divided in proportion to the weights and the panels take left and width in pixels (top and height on a phone): the sum is always the whole row, even while the springs swing.
When the open panel changes, each one receives its new weight with a delay of STAGGER per place of distance: neighbours start first. The weight follows its target with a spring integrated in 1/240 second steps on GSAP’s ticker (stiffness and damping in SPRING), so it overshoots a hair and settles.
The print is an SVG as large as the open panel, so it never distorts: the panel shows a window onto it. Its position is (panel width minus print width) times PARALLAX: with 0.5 it stays centred, with less it moves slower than the edge and is revealed little by little.
The panel’s openness (0 to 1) drives: the upright name, which fades early; the title, which appears halfway rising 14 pixels and goes from the starting TITLE_WIDTH and TITLE_WEIGHT to the final ones with Archivo’s axes; the line below, towards the end; the paper-coloured veil (a CSS variable --o) and the print’s red detail.
A repeating GSAP timeline carries a number from 0 to 1 in STEP seconds per print: from it comes the panel to open, always in the same order, so the round comes back the same. The real pointer rules for 2.4 seconds after its last move; on a phone a tap opens the panel for 6 seconds and another tap closes it. With reduced motion the weights jump straight to their target and the title appears without spring or parallax.
| Name | File | Default | What it changes |
|---|---|---|---|
OPEN_RATIO | script.js | 0.56 | How much of the row the open panel takes (0.3 to 0.8). |
SPRING | script.js | [170, 17] | The panels’ spring: how stiff and how damped it is (less damping, more bounce). |
STAGGER | script.js | 0.045 | The delay between a panel and its neighbour when the row changes, in seconds. |
PARALLAX | script.js | 0.36 | How much the print follows the widening edge: 0.5 keeps it centred, less makes it slide slower. |
TITLE_WIDTH | script.js | [72, 112] | The title’s width as it arrives and with the panel open (62 to 125). |
TITLE_WEIGHT | script.js | [300, 640] | The title’s weight as it arrives and with the panel open (100 to 900). |
STEP | script.js | 1.6 | How many seconds the ghost pointer stays on each print. |
WANDER | script.js | true | The ghost pointer that opens the prints one after another when nobody touches them. |
For a photographer’s or illustrator’s gallery, an art shop’s prints, a brand’s collections, a hotel’s rooms, the sections of a project: a few strong images revealed one at a time without leaving the page.
The same animations, with the panels stacked: the tapped one opens, growing in height with the same spring and wave, and the print slides vertically. Another tap on the same panel closes it; after 6 seconds the automatic round comes back.
No springs, no parallax and no automatic round: one panel is already open, and moving over another the row changes at once while the title fades in.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 6.6 KB; the libraries: GSAP 28 KB.
Tested on 21 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.