
The send button
Buttons, Transitions, SVG
NewFree
A dashed frame to drop files in: with files over the page the sheets fan out and the dashes join into one line; dropped, each file comes in as a row a sheet of its colour lands in, the bar fills up and a tick draws itself at the end, or the row turns red if the file is too big.
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 file drop zone</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/figtree@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the drop zone: three sheets inside a dashed frame. Dragging files over the page the sheets fan out and the
dashes join into a line; dropped (or chosen with a click), the files come down as rows that fill up while
they upload, then close with a tick. The upload is pretended: see send() in the script -->
<div class="drop" data-drop>
<div class="drop__zone" role="button" tabindex="0" aria-describedby="drop-hint" data-zone data-autoclic>
<svg class="drop__frame" aria-hidden="true" data-frame>
<rect class="drop__dash" data-dash/>
</svg>
<div class="drop__art" aria-hidden="true" data-art>
<span class="sheet sheet--back" data-sheet></span>
<span class="sheet sheet--mid" data-sheet></span>
<span class="sheet sheet--front" data-sheet>
<svg viewBox="0 0 24 24"><path d="M12 17V7.5M7.5 11.5 12 7l4.5 4.5"/></svg>
</span>
</div>
<p class="drop__title" data-title><span data-title-in>Drop files here or <span class="drop__browse">browse</span></span></p>
<p class="drop__hint" id="drop-hint">PDF, images or zip, up to 20 MB each</p>
<input class="drop__input" type="file" multiple tabindex="-1" aria-hidden="true" data-input>
</div>
<ul class="drop__list" data-list></ul>
<p class="sr" role="status" aria-live="polite" data-said></p>
</div>
</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.
25 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 file drop zone” from Animorio and fit it into my siteThe dashes are an SVG rectangle the script fits to the frame. A stroke-dashoffset loops over 170 pixels, ten times the dash pattern (9 drawn and 8 empty), so the loop has no seam; each state changes its speed with timeScale, and over the frame stroke-dasharray goes from 9 8 to 17 0 and the dashes become a line.
The window listens to dragover only for drags carrying files: it tells whether they are over the frame or outside it and restarts a 0.2-second wait. dragover keeps coming as long as the files are over the page, so when the wait runs out the files have gone and the frame goes back to rest.
Each sheet has a place at rest and a direction to open in: fan() takes them to a share of FAN, a little with the pointer over the frame, halfway with files over the page, all of it over the frame, where the sheets also move towards the pointer. When the files are dropped the sheets dip and come back up with elastic.out, and a copy of the rectangle grows and fades.
New rows are added to the list and the script measures straight away where their little sheet will end up, before they open from zero height. A copy of the front sheet flies there: x on one curve, y first up by 34 pixels and then down, so it is a toss; meanwhile it shrinks to the little sheet’s size and takes the colour of the kind of file.
send() is a pretend one: it gets the file, a function to call with the part sent so far (from 0 to 1) and a signal saying whether the row has been removed, and answers with a promise; the real upload goes in its place, for example an XMLHttpRequest with upload.onprogress. When it is done the bar folds away and the tick draws itself with stroke-dashoffset; over MAX_MB the row turns red and shakes.
| Name | File | Default | What it changes |
|---|---|---|---|
MAX_MB | script.js | 20 | The biggest file accepted, in megabytes. |
FAN | script.js | [16, 24, 12] | How far the sheets fan out with files over the frame: degrees, pixels sideways and pixels up. |
SPEED | script.js | 7 | The pretend upload’s speed, in megabytes a second. |
MARCH | script.js | 16 | How fast the dashes run round the frame with files over it, in pixels a second. |
SAMPLES | script.js | [['autumn-brochure.pdf', 2.4], ['farm-photos.zip', 14.8], ['drone-flight.mov', 48.2]] | The pretend files the library’s preview drops, with their size in megabytes. |
For uploading documents, photos or attachments: in a contact or application form, in a customer area, in a site’s back office.
On a phone files are not dragged: the words become Tap to choose files and a tap opens the file picker. The rows take the width of the screen and long names end with an ellipsis.
The dashes stand still and the sheets go from one position to the next without moving; no toss, bounce or shake: the rows appear already open, the words beside them change at once and the bar fills in steps.
GSAP 3.15.0, Figtree (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 8.3 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.