
The cookie banner
Consent, Transitions, SVG, Physics
NewFree
The ticket of a concert in an open-air amphitheatre: shown at the door, the screen goes to full brightness and the scanner's red line reads the code. Once you are in, the code has done its job: its bars lift off the paper and bend, row after row, into the plan of the hall, with the stage, your seat in amber and the way to it.
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 ticket that becomes the hall</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/imbue@5.3.0/opsz.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/schibsted-grotesk@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the ticket of a concert in an open-air amphitheatre, as the app that sold it shows it. Shown at the door,
the screen brightens for the scanner and a red line of light reads the barcode; once you are in, the bars
of the barcode lift off the paper and bend into the plan of the hall, with your seat and the way to it.
The bars, the hall and the icons are drawn by the script -->
<section class="pass" aria-label="Concert ticket" data-pass>
<div class="pass__glow" aria-hidden="true" data-glow></div>
<article class="ticket" data-ticket>
<header class="head">
<p class="head__venue">
<svg class="head__mark" viewBox="0 0 24 24" aria-hidden="true">
<path d="M2.5 6.5h19M8.6 6.5a3.4 3.4 0 0 0 6.8 0M5.4 6.5a6.6 6.6 0 0 0 13.2 0M2.5 6.5a9.5 9.5 0 0 0 19 0"/>
</svg>
<span>Cove Amphitheatre</span>
</p>
<p class="head__date"><time datetime="2026-10-10T20:45">Sat 10 Oct</time></p>
<h2 class="head__artist">Ilse Varga</h2>
<p class="head__tour">The Tide Sessions</p>
<!-- the moon rising on the sea, behind the empty side of the head -->
<svg class="head__sea" viewBox="0 0 120 64" aria-hidden="true">
<path class="head__moon" d="M60 50a24 24 0 0 1 48 0z"/>
<path class="head__line" d="M0 50.5h120"/>
<path class="head__wave" d="M52 55h64M64 59h40M76 63h16"/>
</svg>
</header>
<!-- the entrance, the row and the seat are written by the script, from ROW and SEAT in script.js -->
<dl class="facts">
<div class="fact"><dt>Doors</dt><dd>19:30</dd></div>
<div class="fact"><dt>Show</dt><dd>20:45</dd></div>
<div class="fact"><dt>Tier</dt><dd>Lower</dd></div>
<div class="fact fact--big"><dt>Entrance</dt><dd data-door></dd></div>
<div class="fact fact--big"><dt>Row</dt><dd data-row></dd></div>
<div class="fact fact--big"><dt>Seat</dt><dd data-seat></dd></div>
</dl>
<p class="holder"><span>Leni Arnau</span><span>Adult, €48.00</span></p>
<div class="perf" aria-hidden="true" data-perf></div>
<div class="code" data-code>
<p class="note" data-note>
<span class="note__icon" aria-hidden="true" data-note-icon></span>
<span class="note__text" data-note-text>Scan at Door 3 from 19:30</span>
</p>
<div class="code__box">
<svg class="code__svg" viewBox="0 0 300 156" role="img" aria-label="Barcode of ticket 4021 8860 1427 39" data-svg></svg>
<div class="laser" aria-hidden="true" data-laser><i class="laser__glow"></i><i class="laser__core"></i></div>
</div>
</div>
</article>
<button class="show" type="button" data-show data-autoclic>
<span class="show__icon" aria-hidden="true" data-show-icon></span>
<span class="show__label" data-show-label>Show at the door</span>
</button>
<p class="sr" aria-live="polite" data-live></p>
</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.
39 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 ticket that becomes the hall” from Animorio and fit it into my siteThe ticket number, 14 figures, is written in a Code 128 with set C: the start symbol C, the figures two at a time, the check (each value times its place, modulo 103) and the stop symbol. Every symbol is a row of six widths from 1 to 4 modules (seven for the stop); a module is 2 pixels and the bars fall on whole pixels, so the code is sharp and a reader would really read it. It always comes out as 31 bars.
Every bar is drawn as a piece of circle described by five numbers: the middle point, the direction there, the curvature (1 over the radius, 0 when straight), the length and the width. The ends come from the middle: x + (sin(a ± c·L/2) − sin a)/c and y + (cos a − cos(a ± c·L/2))/c, and the path is an SVG A command with a stroke as wide as the bar; with the curvature close to zero it becomes a line. So the same straight bar of the code bends, without changing element, into the arc of a row. The drawn turn stops a little past half a circle, or a bar still long and already very curved would wind round itself.
The hall has exactly 31 pieces: the stage, a half disc, and ten rows by three wedges. The ten bars on the left of the code become the left wedge (the outermost one the back row), the ten on the right the right wedge, the middle one the stage and the others the middle wedge, the ones nearest the centre at the front. An arc can be run either way: each bar takes the way that turns it least, and in the middle, where both ways are the same, they all turn the same way, so two bars crossing in flight never make an X.
Each of the nine quantities of a bar (middle, direction, curvature, length, width, the lift in flight, the lift under the pointer and the colour) has its own spring, a multiple of SPRING, worked out on GSAP's ticker in steps of 1/240 of a second with the frame capped at 1/30; when everything is still the loop switches off. A GSAP timeline only changes the targets: the back rows leave first, one every STAGGER seconds, so no bar crosses rows already in place; the stage leaves last, thin, and widens into its half disc after it has landed. In flight a bar rises by LIFT and grows a little, and its shadow, a group blurred with feGaussianBlur, stays on the paper.
Once landed, the rows split into seats with stroke-dasharray: the same number of seats, with the gaps growing from 0 to 1.8 pixels and the seats getting shorter, in a wave from the stage outwards. Your seat comes from the row and the number (counted from the left across the wedges), together with the nearest aisle and its door; an amber arc a touch larger covers it with a bounce, and the dashed way draws itself through a mask: a solid stroke with pathLength 1 whose stroke-dashoffset goes from 1 to 0.
Show at the door takes the --lum variable to 1: the paper goes from stone to white with color-mix, and a blurred white glow behind the ticket lights up in the dark, in proportion to GLOW. The scanner is a red line with its glow, in mix-blend-mode multiply over the code: red on the white paper and black on the black bars, like real light. It trembles with two sines like a hand for SCAN seconds, reads with a flash and goes out.
| Name | File | Default | What it changes |
|---|---|---|---|
TICKET | script.js | '40218860142739' | The ticket number, 14 figures: the script writes it into a real Code 128 (with fewer figures it adds zeros). |
ROW | script.js | 'F' | Your row, from A by the stage to J at the back. |
SEAT | script.js | 14 | Your seat in the row, counted from the left: it also decides the aisle and the door. |
ADMITTED | script.js | '19:42' | The time the door lets you in. |
SPRING | script.js | [150, 0.62] | The bars' springs: how stiff they are and how much they are held back (1 = no bounce). |
LIFT | script.js | 1 | How high the bars rise off the paper in flight (0 = they slide flat). |
STAGGER | script.js | 0.045 | The seconds between one row of the hall and the next. |
SCAN | script.js | 0.7 | The seconds the scanner's light rests on the code before it reads it. |
GLOW | script.js | 0.6 | How much the ticket shines in the dark while you show it at the door. |
For a ticketing app for concerts, theatres, stadiums or cinemas; for the page that opens after you are in; for a conference pass with its room and seat; anywhere a code, once used, can turn into something useful.
The ticket is 340 pixels wide and fits a 390 screen; with a finger you tap the button and everything goes as with the mouse. The bars and rows lifting under the pointer are there only with a mouse: with a finger the button is enough.
Nothing moves: full brightness is only the colour of the paper and the glow that lights up, the scanner appears and disappears still, and the code fades into the hall already formed, with the seats, your seat and the way already drawn; going back, the hall fades into the code. As it comes in the bars are already on the paper, and under the pointer they do not lift.
GSAP 3.15.0, Imbue (font variabile) 5.3.0, Schibsted Grotesk (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 14 KB; the libraries: GSAP 28 KB.
Tested on 6 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.