Vai al contenuto
animorio
EN
Torna alla libreria

Le stampe sotto il phon

Hover, Fisica, WebGLWebGL, Canvas, GSAPImpegnativaPeso compresso: Demo 22 KBGSAP 28 KBThree.js 174 KBGratisScarica lo zip

Le prove di stampa di una fotografa di matrimoni, su carta lucida, posate su un tavolo di lino: il puntatore è un phon. Dove punta, l’aria passa sotto le foto: il bordo davanti si arriccia e sbatte, la foto si alza come un coperchio e scivola via, il caldo la incurva, la finestra della stanza scorre riflessa sulla carta lucida e i petali di rosa volano via. Tolto il phon, le stampe ricadono, sbattono sul tavolo e si assestano.

Il codice

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>Prints under the hair dryer</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full-italic.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
  <script type="importmap">
    { "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.178.0/build/three.module.min.js"
    } }
  </script>
</head>
<body>
  <main class="stage" data-stage>
    <!-- the linen table and the glossy prints, in WebGL -->
    <canvas class="stage__table" data-table aria-hidden="true"></canvas>

    <!-- the label of the proofs, lying on the corner of the table -->
    <header class="label" data-label>
      <p class="label__kicker"><span data-line>Wren Hollis Photography</span></p>
      <h1 class="label__title"><span data-line>Clara</span> <span data-line class="label__amp">&amp;</span> <span data-line>Sam</span></h1>
      <p class="label__line"><span data-line>Six glossy proofs, still damp from the lab. Give them a blow before they go in the album.</span></p>
      <dl class="label__facts">
        <div><dt><span data-line>Paper</span></dt><dd><span data-line>Glossy, 255 g</span></dd></div>
        <div><dt><span data-line>Album</span></dt><dd><span data-line>Ready by Friday</span></dd></div>
      </dl>
    </header>

    <!-- the cord of the dryer, then the dryer: the tip of the nozzle is the pointer -->
    <svg class="cord" data-cord aria-hidden="true"><path data-cord-path d="M0 0"></path></svg>
    <div class="dryer" data-dryer aria-hidden="true">
      <svg class="dryer__svg" viewBox="-110 -40 340 260" overflow="visible">
        <defs>
          <linearGradient id="dryer-body" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stop-color="var(--dryer-light)"></stop>
            <stop offset="0.45" stop-color="var(--dryer)"></stop>
            <stop offset="1" stop-color="var(--dryer-dark)"></stop>
          </linearGradient>
          <linearGradient id="dryer-trim" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stop-color="var(--trim-light)"></stop>
            <stop offset="1" stop-color="var(--trim)"></stop>
          </linearGradient>
          <linearGradient id="air-shade" x1="1" y1="0" x2="0" y2="0">
            <stop offset="0" stop-color="#5a3a2c" stop-opacity="0.3"></stop>
            <stop offset="1" stop-color="#5a3a2c" stop-opacity="0"></stop>
          </linearGradient>
          <linearGradient id="air-fade" x1="1" y1="0" x2="0" y2="0">
            <stop offset="0" stop-color="#fff" stop-opacity="0.95"></stop>
            <stop offset="1" stop-color="#fff" stop-opacity="0"></stop>
          </linearGradient>
        </defs>
        <g data-dryer-body>
          <!-- the air coming out of the nozzle -->
          <g class="dryer__air dryer__air--shade" data-air>
            <path d="M-6 54 C-40 49 -74 38 -124 22"></path>
            <path d="M-6 60 C-46 60 -86 60 -144 61"></path>
            <path d="M-6 66 C-40 71 -76 82 -128 98"></path>
            <path d="M-6 57 C-34 55 -60 49 -100 41"></path>
            <path d="M-6 63 C-34 66 -62 71 -102 80"></path>
          </g>
          <g class="dryer__air" data-air>
            <path d="M-6 54 C-40 49 -74 38 -124 22"></path>
            <path d="M-6 60 C-46 60 -86 60 -144 61"></path>
            <path d="M-6 66 C-40 71 -76 82 -128 98"></path>
            <path d="M-6 57 C-34 55 -60 49 -100 41"></path>
            <path d="M-6 63 C-34 66 -62 71 -102 80"></path>
          </g>
          <g data-dryer-shake>
            <!-- the handle, with its switch -->
            <path class="dryer__handle" d="M112 92 L152 92 L184 196 Q186 210 172 212 L160 212 Q150 212 146 202 Z"></path>
            <rect class="dryer__switch" x="150" y="120" width="12" height="30" rx="6" transform="rotate(-17 156 135)"></rect>
            <rect class="dryer__switch-knob" data-switch x="152" y="123" width="8" height="12" rx="4" transform="rotate(-17 156 135)"></rect>
            <!-- the barrel -->
            <rect class="dryer__barrel" x="26" y="16" width="160" height="88" rx="44"></rect>
            <path class="dryer__shine" d="M54 30 Q110 22 168 30"></path>
            <rect class="dryer__band" x="62" y="17" width="10" height="86" rx="3"></rect>
            <!-- the rear cap with the vents -->
            <ellipse class="dryer__cap" cx="184" cy="60" rx="16" ry="42"></ellipse>
            <g class="dryer__vents">
              <path d="M186 32 L186 88"></path>
              <path d="M193 38 L193 82"></path>
              <path d="M179 34 L179 86"></path>
            </g>
            <!-- the concentrator nozzle -->
            <path class="dryer__nozzle" d="M0 44 L36 30 L36 90 L0 76 Q-3 60 0 44 Z"></path>
            <path class="dryer__slot" d="M1 47 L1 73"></path>
          </g>
        </g>
      </svg>
    </div>

    <p class="hint" data-hint><span>Move the dryer over the prints. Hold to blow harder.</span></p>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script type="module" src="script.js"></script>
</body>
</html>

Playground

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.

29 valori da cambiare

Oppure chiedila a Claude Code

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 «Le stampe sotto il phon» da Animorio e adattala al mio sito

Cosa fa

Il tavolo di lino di Wren Hollis, una fotografa di matrimoni inventata, con sei prove di stampa del matrimonio di Clara e Sam su carta lucida: il bacio controluce in un prato, le fedi su un panno scuro, il bouquet visto dall’alto, l’uscita dalla cappella sotto i coriandoli, la sposa di spalle davanti al mare in bianco e nero, la torta a tre piani. Le foto sono dipinte dallo script, con la grana della pellicola, e sul retro bianco c’è la scritta del laboratorio ripetuta in diagonale. All’arrivo le stampe vengono lanciate sul tavolo una dopo l’altra, planano su un cuscino d’aria e atterrano col bordo che sbatte, mentre una manciata di petali di rosa cade girando. Il puntatore diventa un phon rosa con il beccuccio, il filo e il getto d’aria che esce: dove punta, l’aria corre sul tavolo e si infila sotto le foto vicine. Il lato rivolto al phon si arriccia, fino a stare quasi in piedi e mostrare il retro, e sbatte con un’onda che corre lungo il bordo; la foto si alza come un coperchio, appoggiata sul bordo opposto, scivola un poco lontano dal getto e gira se il getto la prende di lato. Con il phon fermo sopra una foto i bordi tutto intorno si sollevano e tremano, e il caldo la incurva come una grondaia, poi si raffredda piano e torna piatta. Sulla carta lucida si riflette la finestra della stanza, che scorre e si deforma mentre la carta si piega. I petali volano via dal getto, si alzano girando, ricadono e si posano su una faccia o sull’altra. Tenendo premuto il phon va al massimo: le foto si arricciano di più e galleggiano. Spostato il phon, ogni foto ricade, rimbalza un poco sul tavolo e torna al suo posto.

Come funziona

Le foto dipinte

Ogni foto è un canvas di 640 per 800 punti dipinto dallo script: cieli e prati a sfumature, sagome con le curve di Bézier, fedi fatte di tanti pezzetti di ellisse ognuno con la sua luce, fiori a petali sovrapposti. Le parti fuori fuoco sono solo l’ombra sfocata di una forma spostata fuori dal foglio, che funziona anche dove il filtro di sfocatura del canvas non c’è. Alla fine la grana della pellicola, la vignettatura e, per una, il bianco e nero. Diventano le texture del davanti; il retro è un altro canvas con la scritta del laboratorio.

Un foglio che si piega

Ogni stampa è un piano di Three.js di 21 per 26 punti, piegato a ogni fotogramma sul processore. Prima il caldo, un cilindro che tiene la lunghezza della carta; poi il lato rivolto al phon, che oltre una linea si avvolge su un raggio fisso (ROLL) e, passato il punto più ripido, prosegue dritto, così non si arrotola mai su sé stesso; poi i bordi che tremano e l’inclinazione. Alla fine il foglio viene alzato finché il suo punto più basso tocca il tavolo: è così che si appoggia sul bordo opposto.

L’aria del phon

Il puntatore si porta sul tavolo con un raggio. Per ogni foto si misura la distanza fra il getto e il suo rettangolo: la forza cala con una campana (REACH). Il lato che si arriccia ruota dolcemente verso il getto; arricciatura, inclinazione, bordi e galleggiamento sono molle con poco freno, che ricadono e rimbalzano quando il getto se ne va. La spinta allontana la foto dal getto, un colpo di lato la fa girare, e una molla (SETTLE) la riporta al suo posto.

La carta lucida

Il davanti è un materiale fisico con una vernice trasparente sopra (clearcoat, GLOSS): sotto è quasi opaco, la vernice riflette nitida. La stanza da riflettere è una piccola scena a parte, una stanza scura con una finestra a quattro vetri e un pannello chiaro, cotta in una mappa d’ambiente. Quando la carta si piega la finestra riflessa scorre e si deforma. Una luce dall’alto fa le ombre: un bordo alzato ombreggia il tavolo e la foto stessa.

Il phon e i petali

Il phon è un SVG che sta col beccuccio sul puntatore e si inclina contro la direzione in cui va; il getto è fatto di tratteggi che scorrono, il filo è una curva di Bézier con un punto su una molla, così ciondola. I petali sono un’unica mesh a istanze: ognuno ha posizione, altezza, velocità e due giri. Il getto li spinge via e, se è forte, li solleva; in aria cadono piano e oscillano, a terra si fermano e si posano su una faccia.

Valori da cambiare

NomeFileDi partenzaCosa cambia
BLOWscript.js1Quanto è forte l’aria del phon.
REACHscript.js1Quanto lontano arriva l’aria sul tavolo: di più, e si muovono anche le foto vicine.
CURLscript.js1Quanto si arriccia il lato della foto rivolto al phon.
FLUTTERscript.js1Quanto sbattono e tremano i bordi sollevati.
HEATscript.js1Quanto il caldo incurva le foto come una grondaia (0 = mai).
GLOSSscript.js1Quanto è lucida la carta: 0 è una carta opaca, senza riflessi.
SETTLEscript.js1Quanto in fretta le foto ricadono e tornano al loro posto.
--dryerstyle.css#e7a99cIl colore del phon (con --dryer-light e --dryer-dark per la luce e l’ombra; il tavolo è --table).

Provali nel Playground

Quando usarla

Per il sito di un fotografo di matrimoni o di ritratti, di un laboratorio di stampa, di uno studio che consegna gli album: la pagina delle prove, la galleria dei lavori o la prima pagina. Le foto si toccano come foto vere appena stampate, e il gioco del phon fa venire voglia di guardarle tutte.

Sul telefono

L’etichetta sta in alto e le foto in due colonne da tre. Il dito è il phon: compare dove si tocca e soffia finché si trascina, con la stessa fisica, gli stessi riflessi e gli stessi petali, solo più piccoli e meno petali. Senza il tasto da tenere premuto, il getto forte lì non c’è.

Con il movimento ridotto

Niente si muove: le foto sono già sul tavolo, piatte, e i petali al loro posto; il phon non c’è. Il puntatore è una lampada: dove passa, la carta lucida si accende di un riflesso, che compare e svanisce in dissolvenza.

Trappole

  • Una foto piatta sta due millesimi sopra il tavolo, troppo vicina per la profondità di molte schede grafiche (e di quella del browser senza scheda): il tavolo vinceva e bucava la carta proprio dove era più bassa, con dei buchi che sembravano strappi. Il tavolo va disegnato per primo e senza scrivere la profondità (renderOrder -1, depthWrite false): non nasconde mai niente, perché sotto di lui non c’è nulla.
  • Con la carta tutta lucida, cioè ruvidità bassa anche sotto la vernice, il riflesso della finestra diventa una nebbia grigia che spegne le foto scure. Il riflesso nitido lo dà solo la vernice (clearcoat); sotto la carta è quasi opaca e riflette poco (specularIntensity bassa). E la finestra va puntata sul bordo della fila in alto, non in mezzo, altrimenti da ferma una foto è tutta coperta.
  • Lo script è un modulo (import di Three.js): aprendo index.html con un doppio clic il browser lo blocca. Per provarlo in locale serve un piccolo server, per esempio npx serve nella cartella.

Librerie

Three.js 0.178.0, GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 22 KB; le librerie: GSAP 28 KB, Three.js 174 KB.

Collaudo

Provata il 13 ottobre 2026

  • Computer: Fatto
  • Telefono: Fatto
  • Movimento ridotto: Fatto
  • Safari su iPhone: Da fare

Licenza d’uso

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.

Tutte le animazioni