
Il pulsante da far scorrere
Pulsanti, Fisica, Transizioni
NuovaGratis
Il pulsante Export image di un editor è una piccola fotocamera istantanea: premuto, scatta il flash, la fotocamera sussulta e dalla fessura esce la stampa col bordo bianco, che scende e oscilla su una molla. Sulla stampa l'immagine si sviluppa come una pellicola istantanea: grigio verde scuro, poi i colori affiorano a chiazze, con una dominante che passa dal ciano al caldo, e i neri si chiudono per ultimi.
Una cartella che funziona da sola: index.html, style.css, script.js e le librerie da CDN. Nelle schede React e Vue la stessa demo è già un componente, che spegne le sue animazioni quando esce dalla pagina.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The instant photo button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the instant photo button: an editor's Export image button drawn as a small instant camera. Pressed, the flash
fires, the camera jolts and the print comes out of the slot underneath, swings and develops in a canvas -->
<div class="snap" data-snap data-autoclic>
<div class="snap__rig" data-rig>
<!-- the print: under the camera, clipped at the slot -->
<div class="snap__exit">
<button class="print" type="button" tabindex="-1" aria-label="Clear the exported image" data-print>
<span class="print__frame">
<canvas class="print__image" width="312" height="208" aria-hidden="true" data-canvas></canvas>
<span class="print__gloss" aria-hidden="true"></span>
</span>
<span class="print__note" aria-hidden="true">hillside-dusk.png</span>
</button>
</div>
<button class="cam" type="button" aria-label="Export image as PNG" data-cam>
<span class="cam__key" aria-hidden="true"></span>
<span class="cam__body" aria-hidden="true">
<span class="cam__cap"></span>
<span class="cam__finder"></span>
<span class="cam__flash" data-flash><span class="cam__fresnel"></span><span class="cam__fire" data-fire></span></span>
<span class="cam__seam"></span>
<span class="cam__lens">
<svg viewBox="0 0 100 100">
<defs>
<linearGradient id="ip-barrel" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#4a4f4c"/>
<stop offset="0.5" stop-color="#1b1e1d"/>
<stop offset="1" stop-color="#0c0e0d"/>
</linearGradient>
<linearGradient id="ip-bezel" x1="0.2" y1="0" x2="0.8" y2="1">
<stop offset="0" stop-color="#c9ccc6"/>
<stop offset="0.45" stop-color="#5b605c"/>
<stop offset="0.7" stop-color="#2a2e2c"/>
<stop offset="1" stop-color="#8b908b"/>
</linearGradient>
<radialGradient id="ip-glass" cx="0.42" cy="0.36" r="0.7">
<stop offset="0" stop-color="#3a4a7a"/>
<stop offset="0.35" stop-color="#1a2240"/>
<stop offset="0.8" stop-color="#07090f"/>
<stop offset="1" stop-color="#020304"/>
</radialGradient>
<radialGradient id="ip-deep" cx="0.5" cy="0.5" r="0.5">
<stop offset="0" stop-color="#05060a"/>
<stop offset="0.7" stop-color="#0d1222"/>
<stop offset="1" stop-color="#26315a"/>
</radialGradient>
</defs>
<circle cx="50" cy="50" r="49" fill="url(#ip-barrel)"/>
<circle class="lens__grip" cx="50" cy="50" r="44.5"/>
<circle cx="50" cy="50" r="38" fill="url(#ip-bezel)"/>
<circle cx="50" cy="50" r="34.5" fill="#0b0d0c"/>
<circle cx="50" cy="50" r="32" fill="url(#ip-glass)"/>
<circle cx="50" cy="50" r="17" fill="url(#ip-deep)"/>
<circle class="lens__ring" cx="50" cy="50" r="22"/>
<g class="lens__glints" data-glints>
<path class="lens__glint" d="M27 37a26 26 0 0 1 21-15" />
<path class="lens__glint lens__glint--soft" d="M70 66a24 24 0 0 1-12 9" />
<path class="lens__coat" d="M34 58a18 18 0 0 0 9 9" />
<path class="lens__coat lens__coat--green" d="M62 34a17 17 0 0 1 6 8" />
</g>
</svg>
</span>
<span class="cam__text">
<span class="cam__label" data-label>Export image</span>
<span class="cam__sub" data-sub>PNG · 2400 × 1600</span>
</span>
<span class="cam__chin"><span class="cam__slot"></span></span>
<span class="cam__sheen" data-sheen></span>
</span>
</button>
<p class="snap__saved" data-saved>
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M10 3.5v8.25M6.6 8.6 10 12l3.4-3.4"/><path d="M3.75 12.5v2.25c0 .7.56 1.25 1.25 1.25h10c.7 0 1.25-.55 1.25-1.25V12.5"/></svg>
<span data-saved-text>Saved to Downloads</span>
</p>
</div>
<span class="snap__bloom" aria-hidden="true" data-bloom></span>
<p class="sr" aria-live="polite" data-live></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>Cambia valori, colori e testi con le manopole e guarda l’animazione rispondere dal vivo. Oppure scrivi tu nel codice. Poi scarica la cartella con le tue modifiche.
21 valori da cambiare
Col connettore di Animorio, Claude Code la prende da qui con tutta la sua guida e la adatta al tuo progetto. Incolla questa richiesta:
Prendi «Il pulsante della polaroid» da Animorio e adattala al mio sitoIl piccolo paesaggio (cielo al tramonto, sole basso, tre file di colline con il filo di luce sulle creste, gli abeti e l'erba controluce, la vignettatura) si disegna una volta sola in un canvas nascosto a doppia densità, con gradienti e tracciati fatti di somme di onde. Con getImageData si tengono i colori finali di ogni pixel, con un po' di grana, e la loro luminanza.
Per ogni pixel si calcola una volta un rumore a valori su griglia, in quattro ottave, con le coordinate piegate da un secondo rumore (domain warping): così le chiazze vengono tonde e irregolari come il reagente che si spande. Le coordinate sono in pixel CSS, perché le chiazze abbiano la stessa misura a ogni densità.
Ogni pixel ha la sua soglia: luminanza (le parti chiare si schiariscono prima), rumore moltiplicato per BLOTCH e un poco di altezza (il reagente entra dall'alto). A ogni fotogramma il tempo dello sviluppo avanza e ogni pixel passa con uno smoothstep dal tono base grigio verde al suo colore. Due tempi in più, anche loro mossi dal rumore, decidono quando il colore sale dal grigio e quando le ombre, sollevate verso un grigio fangoso, si chiudono nei neri.
Su tutta la stampa si somma una dominante che parte verde ciano, passa al caldo verso metà e svanisce alla fine, moltiplicata per TINT. Il ciclo di disegno scrive un ImageData riutilizzato con putImageData solo mentre lo sviluppo è in corso; finito, si posa l'immagine finale e il ciclo non ridisegna più.
Una timeline di GSAP accende il flash, il riflesso sul corpo e la luce intorno, e fa sussultare la fotocamera con un elastic. Il motore spinge la stampa a passo costante in EJECT secondi; poi la stampa è libera: la sua discesa e il suo angolo sono due molle smorzate mosse a mano sul ticker, a quattro passi per fotogramma e col passo limitato a 1/30 di secondo, e l'angolo parte con una spinta che lo fa oscillare di SWING gradi.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
DEVELOP | script.js | 5.5 | I secondi che l'immagine impiega a svilupparsi. |
EJECT | script.js | 1.1 | I secondi che il motore impiega a spingere fuori la stampa. |
SWING | script.js | 6 | Quanto oscilla la stampa uscendo, in gradi. |
DAMPING | script.js | 0.16 | Quanto in fretta l'oscillazione si spegne (1 = nessuna oscillazione). |
BLOTCH | script.js | 1 | Quanto è a chiazze lo sviluppo: 0 uniforme, 2 a grandi macchie. |
TINT | script.js | 1 | Quanto sono forti le dominanti di colore durante lo sviluppo. |
LABELS | script.js | ['Export image', 'Exporting', 'Exported'] | Le parole sulla fotocamera: a riposo, mentre lavora, a lavoro fatto. |
SAVED | script.js | 'Saved to Downloads' | La riga sotto la stampa. |
Per l'azione che esporta o salva un'immagine in un editor, in un generatore di copertine o in un'app di foto, dove vedere la stampa che esce e si sviluppa dice chiaramente che il file c'è. Meglio per un'azione singola e voluta che per un salvataggio automatico.
La fotocamera, la stampa e la riga stanno in 260 pixel di larghezza e meno di 380 di altezza, quindi entrano intere in uno schermo da 390. Il canvas dell'immagine è sempre a doppia densità. Il tocco fa scendere il tasto di scatto come la pressione del mouse.
Niente sussulto, niente flash, niente uscita né oscillazione: la stampa compare in dissolvenza al suo posto e l'immagine sale dal grigio verde ai colori con una dissolvenza uniforme, senza chiazze. La riga Saved to Downloads compare in dissolvenza.
GSAP 3.15.0, Geist (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 11 KB; le librerie: GSAP 28 KB.
Provata il 5 ottobre 2026
Puoi usarla nei tuoi progetti e in quelli dei tuoi clienti. Non puoi rivenderla né ridistribuirla così com’è. GSAP resta sotto la sua licenza Standard. Licenza completa.
Con l’email e la password del tuo account.
oppure con l’email
Hai fatto l’accesso come .
Con l’account scarichi lo zip di ogni animazione e di ogni pacchetto, gratis.