Vai al contenuto
animorio
EN
Tutti i componenti

La ricerca che pesa le lettere

Ricerca, Testo, TransizioniGSAP, Solo CSSImpegnativaPeso compresso: Demo 13 KBGSAP 28 KBGratisScarica lo zip

Nello stile minimal: la ricerca nel catalogo di una piccola fonderia di caratteri. Mentre si scrive, nei nomi che corrispondono le lettere trovate prendono peso una dopo l’altra, con una molla misurata, e ognuna si stringe quanto basta per restare larga uguale: i nomi non si spostano mai di lato. Le voci che non c’entrano più si assottigliano fino a un filo e se ne vanno, le altre si richiudono su molle vere, e il conteggio è in cifre tabellari che rotolano.

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>The search that weighs the letters</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the catalogue search of a small type foundry. Typing, the letters found in every name take weight one after
         another, while each letter narrows just enough to keep its width: the names never move sideways. The rows
         that stop matching thin out and leave, the others ride on springs to their new places. The rows are made by
         the script from the list at the top of script.js -->
    <div class="weigh" data-search data-autoclic>
      <div class="weigh__field" data-field>
        <svg class="weigh__lens" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.5 4.75a5.75 5.75 0 1 0 0 11.5a5.75 5.75 0 1 0 0-11.5zM14.75 14.75l4.75 4.75"/></svg>
        <input class="weigh__input" id="weigh-input" type="text" inputmode="search" enterkeyhint="search" role="combobox" aria-label="Search typefaces" aria-autocomplete="list" aria-expanded="true" aria-controls="weigh-list" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Search the catalogue" data-input>
        <span class="weigh__caret" aria-hidden="true" data-caret></span>
        <span class="weigh__count" aria-hidden="true"><span class="weigh__num" data-num></span><span class="weigh__unit" data-unit>typefaces</span></span>
        <button class="weigh__clear" type="button" aria-label="Clear the search" tabindex="-1" data-clear>
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 8l8 8M16 8l-8 8"/></svg>
        </button>
        <span class="weigh__rule" aria-hidden="true"></span>
      </div>

      <div class="weigh__room" data-room>
        <span class="weigh__band" aria-hidden="true" data-band></span>
        <ul class="weigh__list" id="weigh-list" role="listbox" aria-label="Typefaces" data-list></ul>
        <div class="weigh__none" data-none hidden>
          <p class="none__word" aria-hidden="true"><span class="none__letters" data-none-letters></span><span class="none__strike" data-strike></span></p>
          <p class="none__what">No typeface in the catalogue matches.</p>
          <p class="none__try">Try <span data-tries></span></p>
        </div>
      </div>

      <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>

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.

57 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 «La ricerca che pesa le lettere» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco un campo di ricerca fatto solo di una lente, delle parole e di una riga sottile, con a destra il conteggio, 12 typefaces. Sotto, sei nomi di caratteri in un grottesco leggero, ognuno con la sua classe e quanti stili ha. All’arrivo i nomi salgono da un peso sottilissimo al loro peso, lettera per lettera. Col fuoco nel campo la riga sotto diventa nera dalla lente in poi. Scrivendo, le lettere cercate vengono trovate nell’ordine anche se non stanno vicine, come in una palette dei comandi: in ogni nome quelle lettere diventano nere e pesanti una dopo l’altra, con un piccolo eccesso e il ritorno, e si stringono quanto basta per non allargare il nome. Le altre lettere si fanno grigie. I nomi che non valgono più si assottigliano e svaniscono, gli altri salgono a chiudere i buchi su una molla, e le cifre del conteggio rotolano. Le frecce o il puntatore portano una fascia grigia su un nome, le cui lettere trovate diventano vermiglie, con il tasto Invio disegnato accanto; Invio o un clic lo scelgono: il nome va nel campo e diventa tutto pesante, da sinistra a destra. Esc svuota il campo e la lista torna com’era. Se niente corrisponde, la parola scritta compare grande, perde il peso lettera per lettera, una riga sottile la cancella e sotto si propongono due parole da provare, che prendono peso sotto il puntatore. Senza niente scritto, il nome sotto il puntatore prende appena un po’ di peso.

Come funziona

Misurare le lettere

Caricato il carattere, lo script mette ogni lettera del catalogo in una griglia di 9 pesi per 9 larghezze (asse wght da 100 a 900, asse wdth da 62 a 125) in un riquadro nascosto e ne misura la larghezza con getBoundingClientRect, in em. La crenatura è spenta (font-kerning: none), così la larghezza di ogni lettera è solo sua e la somma dà il nome intero.

Il peso che non allarga

Per un peso qualsiasi holdWidth() interpola la riga della griglia fra i due pesi vicini e risolve la larghezza dell’asse wdth che rende la lettera larga come a riposo (REST con wdth 100). Lo fa a ogni fotogramma del tween di GSAP che porta il peso, quindi anche nell’eccesso della molla: misurato nel browser, il nome resta largo uguale al centesimo di pixel.

Trovare le lettere

match() cerca le lettere scritte nell’ordine dentro il nome con una piccola programmazione dinamica: lettere vicine, all’inizio di una parola e presto nel nome valgono di più, un salto lungo vale meno. Tiene la sistemazione migliore, e quelle sono le lettere che prendono peso, una dopo l’altra ogni STAGGER secondi, con una curva a molla smorzata scritta come funzione di GSAP.

Le righe sulle molle

Le righe sono in posizione assoluta e ognuna ha una molla vera (rigidità e smorzamento di SPRING, passo limitato a 1/30 di secondo e diviso in passi da 1/240), che conserva la velocità se il bersaglio cambia mentre si muove. Restano nell’ordine del catalogo: una lettera in più toglie solo righe e le altre si richiudono, una in meno le rimette. Chi se ne va si assottiglia a FAINT e svanisce in 0,16 secondi; chi resta parte un attimo dopo, e le righe nuove aspettano che le altre siano passate. Il ciclo si ferma quando tutto è fermo.

Tastiera, conteggio e stato vuoto

Il campo ha role combobox, aria-expanded e aria-activedescendant sulla riga scelta, che ha role option e aria-selected; le frecce spostano la fascia (anche lei su una molla), Invio sceglie, Esc svuota, e una riga nascosta con aria-live dice quanti caratteri ci sono. Le cifre del conteggio cambiano una per una da destra, rotolando su o giù. Senza risultati la parola scritta perde peso lettera per lettera e una riga la cancella; le parole di TRIES la sostituiscono nel campo.

Il giro dell’anteprima

Un clic da script (detail 0, quello dell’anteprima della libreria) avvia una timeline di GSAP lunga circa 10 secondi con un cursore finto e senza prendere il fuoco: scrive ser, scende di una riga, sceglie, scrive mo, poi zq che non trova niente, e infine Esc riporta tutto a riposo. Un tocco o un tasto veri la fermano subito.

Valori da cambiare

NomeFileDi partenzaCosa cambia
TYPEFACESscript.js[['Esker Sans', 'Sans', 12], ['Ashlar Grotesk', 'Sans', 9], …]Il catalogo: nome, classe e numero di stili, dai più venduti.
SHOWNscript.js6Quanti caratteri mostra al massimo la lista.
RESTscript.js300Il peso dei nomi a riposo (da 100 a 900).
HITscript.js780Il peso che prende una lettera trovata (da 100 a 900).
FAINTscript.js110Il peso dei nomi che se ne vanno e della parola che non trova niente.
STAGGERscript.js0.07I secondi fra una lettera trovata e la successiva che prende peso.
SETTLEscript.js0.6I secondi in cui una lettera prende il suo peso e si assesta.
SPRINGscript.js[420, 32]La molla che porta le righe al loro posto: rigidità e smorzamento.
TRIESscript.js['serif', 'mono']Le parole proposte quando niente corrisponde.

Provali nel Playground

Quando usarla

Per la ricerca di una fonderia di caratteri, di un catalogo, di un negozio con pochi prodotti, di una documentazione o di una palette dei comandi: ovunque i nomi sono corti, si cerca mentre si scrive e conta vedere subito quali lettere hanno trovato il risultato. La funzione search() è la sola da cambiare per chiedere i risultati a un server.

Sul telefono

Il campo prende la larghezza dello schermo meno 32 pixel; le parole nel campo sono di 17 pixel (da 16 in su iPhone non ingrandisce la pagina toccandolo) e la tastiera mostra il tasto per cercare. I nomi scendono a 20 pixel e le righe restano alte 52 per il dito: un tocco porta la fascia sulla riga e la sceglie. Il tasto Invio disegnato non c’è, perché sul telefono non serve; tutto il resto, pesi, molle e conteggio, è uguale.

Con il movimento ridotto

Niente molle né rotolamenti: le righe compaiono e spariscono in dissolvenza già al loro posto, la fascia salta da una riga all’altra, le cifre del conteggio cambiano in dissolvenza e la riga del fuoco si accende invece di disegnarsi. Le lettere trovate cambiano peso tutte insieme in un quinto di secondo, senza onda né eccesso, e restano larghe uguali; la riga che cancella la parola non trovata è già al suo posto.

Trappole

  • Una lettera che prende peso si allarga e spinge tutte quelle dopo: il nome tremava a ogni lettera scritta. Ora la larghezza di ogni lettera si misura a 81 combinazioni di peso e larghezza, e a ogni fotogramma si risolve l’asse wdth che la tiene larga come a riposo; misurato, il nome resta uguale al centesimo di pixel anche a metà dell’animazione.
  • Con la crenatura accesa la larghezza di una lettera dipende da quella vicina e i conti non tornavano: i nomi hanno font-kerning: none, come il riquadro in cui si misura.
  • Con i risultati in ordine di punteggio, a ogni lettera le righe si scambiavano di posto e due nomi passavano uno sopra l’altro, illeggibili. Ora restano nell’ordine del catalogo, così una lettera in più toglie solo righe; se search() le riordina, una riga che deve scavalcarne un’altra si spegne in viaggio e si riaccende arrivando.
  • Le righe nuove entravano proprio dove una riga stava salendo a chiudere un buco: ora aspettano 0,16 secondi quando qualcuna si sposta di più di mezza riga, e chi se ne va svanisce in 0,16 secondi invece di 0,2 con power2.in, che la teneva visibile fino in fondo.
  • L’anteprima della libreria clicca ogni 2,8 secondi, ma il giro dura circa 10: ogni clic lo faceva ripartire da capo a metà. Ora i clic da script si ignorano finché la timeline del giro è in corso, e un tocco o un tasto veri la fermano.

Librerie

GSAP 3.15.0, Archivo (font variabile, assi wght e wdth) 5.3.0.

Compressi con gzip, i tre file della demo pesano 13 KB; le librerie: GSAP 28 KB.

Collaudo

Provata il 16 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.

Tutti i componenti