
The send button
Buttons, Transitions, SVG
NewFree
A music player that really plays: three pieces composed in the browser with Web Audio, nothing downloaded. The wave is drawn from the notes themselves and is dragged to move through the piece, the bars near the playhead swell with the music, play turns into pause, and while it plays the drawn cover comes alive.
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 player that plays</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/readex-pro@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the player that plays: three little pieces made in the browser with Web Audio; the wave is drawn from the
notes and moves with them, the cover comes alive while it plays, play turns into pause -->
<section class="player" aria-label="Music player" data-player data-autoclic>
<div class="cover" data-cover><div class="cover__in" data-cover-in></div></div>
<div class="track">
<p class="track__title"><span class="roll" data-title></span></p>
<p class="track__by">Made in your browser</p>
</div>
<div class="wave" role="slider" tabindex="0" aria-label="Position in the piece" aria-valuemin="0" data-wave></div>
<div class="times" aria-hidden="true"><span data-at>0:00</span><span data-left>0:00</span></div>
<div class="buttons">
<button class="btn" type="button" aria-label="Previous piece" data-prev><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 6v12M18 6.5v11L9.5 12z"/></svg></button>
<button class="btn btn--play" type="button" aria-label="Play" data-play><svg viewBox="0 0 24 24" aria-hidden="true"><polygon data-a/><polygon data-b/></svg></button>
<button class="btn" type="button" aria-label="Next piece" data-next><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M17 6v12M6 6.5v11l8.5-5.5z"/></svg></button>
</div>
<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.
63 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 player that plays” from Animorio and fit it into my siteEach piece is sixteen bars on four chords, played twice: quiet at the start, full in the middle, thinner at the end. The notes are events (when, what, how long, how loud): long chords, an arpeggio in quavers (crotchets in the first bars; in the rain high notes at random, like drops), a bass two octaves below, and at night hats of filtered noise.
The AudioContext is born at the first play really pressed (isTrusted). Each note is an oscillator with a filter and a volume envelope (rise, hold, exponential fall down to 0.0001); behind there is a room made with a ConvolverNode and noise that dies away, and a compressor. Each stretch played has its own channel: pause fades it in 80 milliseconds and stops its notes, so starting again does not bring the old notes back.
Notes do not start with a setTimeout at their instant: every 40 milliseconds the ones in the next 0.35 seconds are looked at and fixed on the audio clock (2.5 seconds if the page is hidden). The position comes from that clock when there is sound, and from GSAP's when there is not (the library's preview cannot play).
Every twentieth of a second how much the piece is sounding is worked out, adding up the notes with their envelopes; each bar mixes the peak and the average of its stretch, with some contrast. On GSAP's ticker the bars near the playhead grow with how much is sounding at that instant and the ones passed take the colour. Dragging (with pointer capture) or with the keys moves through the piece.
Play and pause are two polygons whose points slide from the two halves of the triangle to the two bars. Changing piece the old cover leaves the way of the change and the new one comes from the other side in SWAP seconds, the title slides, the --tint variable changes colour and the bars grow one after another. Each cover is an SVG with a paused timeline that starts and stops with the music. A click from a script (the library's preview) presses play, then forward, then drags along the wave, then pause, without sound.
| Name | File | Default | What it changes |
|---|---|---|---|
TRACKS | script.js | [['Morning Fields', 92, [[62, 66, 69], …], 'fields', '#ffb35c'], …] | The pieces: the title, the beats a minute, the four chords in MIDI numbers (60 is middle C), the cover (fields, drive or rain) and the colour. |
BARS | script.js | 64 | The bars of the wave. |
VOLUME | script.js | 0.7 | How loud. |
SWAP | script.js | 0.6 | The seconds the cover takes to change. |
For the site of a musician or a label, a podcast, a gallery of sounds, a meditation app, an event page with its soundtrack: any player that should feel alive.
The card is at most 380 pixels wide; the finger drags along the wave without scrolling the page (touch-action none on the wave) and the buttons are 48 and 64 pixels. On iPhone the sound starts from the first tap on play.
The music plays the same; the bars do not swell, the covers do not move, they change without sliding, the icon and the new wave change at once, and no entrance.
GSAP 3.15.0, Readex Pro (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.7 KB; the libraries: GSAP 28 KB.
Tested on 3 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.