Vai al contenuto
animorio
EN
Tutti i componenti

Il menu dei comandi

Menu, Transizioni, FisicaGSAP, Solo CSSImpegnativaPeso compresso: Demo 13 KBGSAP + Flip 37 KBGratisScarica lo zip

La palette dei comandi ⌘K di un editor di progetti, fluida come in un’app nativa: a riposo è una pillola Search or jump to… col suo tasto disegnato, e premendola (o con ⌘K, Ctrl K) la pillola stessa si allarga e diventa la palette. Scrivendo i comandi si filtrano con un punteggio fuzzy, quelli che restano scivolano al loro posto e le lettere trovate si accendono; la fascia sotto la riga scelta scivola su una molla. Un comando con altro dentro apre la sua pagina: quella di prima arretra in profondità sfocandosi, e in alto compaiono le briciole. Sulla pagina dei temi, passando su un tema la palette lo indossa subito.

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 command menu</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist-mono@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the command menu of a project editor. At rest a search pill with its shortcut drawn as two little keys;
         pressed (or with Cmd K / Ctrl K) the pill itself grows into the palette. Typing filters the commands, the
         ones left slide to their places, the letters found light up; a command with more inside opens its own page,
         the page before sinking back behind it. The rows are made by the script from the list in script.js -->
    <div class="cmdk" data-cmdk data-autoclic>
      <div class="cmdk__shell" data-shell>
        <button class="cmdk__pill" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="cmdk-dialog" aria-keyshortcuts="Meta+K Control+K" data-pill>
          <svg class="cmdk__lens" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.5 4.5a6 6 0 1 0 0 12a6 6 0 1 0 0-12zM15 15l4.5 4.5"/></svg>
          <span class="cmdk__pilltext" data-pilltext>Search or jump to…</span>
          <span class="cmdk__keys" aria-hidden="true"><kbd class="cmdk__key" data-mod>⌘</kbd><kbd class="cmdk__key">K</kbd></span>
        </button>

        <div class="cmdk__dialog" id="cmdk-dialog" role="dialog" aria-modal="true" aria-label="Command menu" data-dialog hidden>
          <div class="cmdk__head">
            <svg class="cmdk__lens" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.5 4.5a6 6 0 1 0 0 12a6 6 0 1 0 0-12zM15 15l4.5 4.5"/></svg>
            <nav class="cmdk__crumbs" aria-label="Where you are in the menu" data-crumbs></nav>
            <input class="cmdk__input" type="text" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-label="Search commands" autocomplete="off" autocapitalize="off" spellcheck="false" enterkeyhint="go" placeholder="Search or jump to…" data-input>
            <kbd class="cmdk__key cmdk__key--esc" aria-hidden="true">esc</kbd>
          </div>
          <div class="cmdk__body" data-body></div>
          <div class="cmdk__foot" aria-hidden="true">
            <span class="cmdk__tip"><kbd class="cmdk__key cmdk__key--icon"><svg viewBox="0 0 24 24"><path d="M12 18V6M7 11l5-5 5 5"/></svg></kbd><kbd class="cmdk__key cmdk__key--icon"><svg viewBox="0 0 24 24"><path d="M12 6v12M7 13l5 5 5-5"/></svg></kbd>Move</span>
            <span class="cmdk__tip"><kbd class="cmdk__key cmdk__key--icon"><svg viewBox="0 0 24 24"><path d="M19 5v7.5H6M10 8.5l-4 4 4 4"/></svg></kbd>Open</span>
            <span class="cmdk__tip" data-backtip><kbd class="cmdk__key cmdk__key--icon"><svg viewBox="0 0 24 24"><path d="M9 6h11v12H9l-5.5-6z"/></svg></kbd>Back</span>
          </div>
        </div>
      </div>
      <p class="sr" role="status" 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="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/Flip.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.

25 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 «Il menu dei comandi» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco una pillola bianca con una lente, la scritta grigia Search or jump to… e a destra due piccoli tasti, ⌘ e K (Ctrl e K fuori dal Mac). Passandoci sopra la pillola si scurisce appena e i tasti si sollevano di un pixel; premendo si abbassano. Premendo la pillola, o ⌘K da qualunque punto, la pillola sale e si allarga fino a diventare un pannello con gli angoli meno tondi e un’ombra più profonda: le sue parole svaniscono dove comincia il campo, e sotto le righe dei comandi entrano una dopo l’altra, raccolte in Suggestions, Navigation, Preferences e Help, ognuna con la sua icona e a destra i suoi tasti (G D, ⌘ B) o una freccia. Scrivendo, le righe che non c’entrano spariscono, quelle che restano scivolano su a chiudere i buchi e le lettere che combaciano diventano viola; la fascia grigia corre sul comando migliore allungandosi un poco mentre viaggia. Le frecce la spostano, il puntatore anche, Invio esegue: la palette torna nella pillola e la pillola dice per un momento cosa è successo, con una spunta. Change theme… apre la sua pagina: la lista di prima arretra, rimpicciolisce e si sfoca mentre i quattro temi arrivano davanti, e nel campo compaiono le briciole Home e Theme. Spostandosi su Dark, Dusk o Paper la palette cambia subito colori; Invio li tiene, Backspace col campo vuoto torna indietro e rimette il tema di prima. Open recent… apre la pagina dei progetti. Esc o un clic fuori la chiudono.

Come funziona

Una sola superficie

La pillola e la palette sono lo stesso elemento: un riquadro col fondo, il bordo e l’ombra, di cui GSAP muove posizione, larghezza, altezza e raggio degli angoli dalla misura della pillola a quella del pannello (expo.out). Dentro ci sono il pulsante della pillola, ancorato in alto, e la finestra di dialogo: la prima svanisce in 0,12 secondi, la seconda compare subito dopo, col campo nello stesso punto dove stava la scritta, così sembra che la pillola si sia aperta. Chiudendo, lo stesso al contrario.

La ricerca fuzzy

Ogni lettera scritta deve comparire nell’etichetta, in ordine. Per ogni punto di partenza possibile si calcola un punteggio: uno per lettera, tre in più se è attaccata alla precedente, quattro se comincia una parola, quattro se la corrispondenza comincia l’etichetta, e un poco in meno per i buchi; vince la migliore, e le sue posizioni diventano i <mark> viola. Le parole nascoste di ogni comando (dark, appearance…) lo trovano anche se l’etichetta non combacia, con un punteggio più basso.

Le righe che scivolano

Prima di filtrare Flip fotografa righe e titoli dei gruppi; poi si nascondono quelle che non c’entrano e Flip.from le fa scivolare dalla vecchia posizione alla nuova. Le righe tengono il loro ordine, così si muovono solo dentro lo spazio lasciato libero e non si sovrappongono mai; la fascia va sul punteggio migliore. Le righe che ritornano aspettano metà della corsa delle altre prima di comparire, e l’altezza del pannello si misura dall’ultima riga (non da scrollHeight, che conta anche le righe ancora spostate).

La fascia su una molla

La fascia sotto la riga scelta è un solo elemento nella lista: la sua posizione e la sua altezza sono due molle (BAND) che inseguono la riga, integrate a passi di 1/240 di secondo; l’altezza ha una molla più morbida e cresce un poco con la velocità, così la fascia si allunga in corsa e si riassesta all’arrivo. Quando arriva, il ciclo si ferma.

Pagine in profondità

Ogni pagina ha la sua lista (role listbox) sovrapposta alle altre. Andando avanti la pagina di prima si rimpicciolisce di DEPTH, sale di quattro pixel, si sfoca di BLUR pixel e svanisce, mentre la nuova arriva da un poco più grande e sfocata e si mette a fuoco; tornando indietro il contrario. Il campo prende le briciole (pulsanti veri per tornare), un segnaposto nuovo e la ricerca di ogni pagina resta salvata per quando si torna.

Accessibile come un’app

Il campo è un combobox con aria-controls sulla lista della pagina e aria-activedescendant sulla riga scelta; le righe sono option con aria-selected. La finestra è un dialog modale: Tab gira solo fra le briciole e il campo, Esc chiude e il fuoco torna alla pillola. Un annuncio dice quanti risultati ci sono e cosa ha fatto il comando.

Valori da cambiare

NomeFileDi partenzaCosa cambia
PILLscript.js300La larghezza della pillola a riposo, in pixel.
OPENscript.js0.55I secondi del passaggio dalla pillola alla palette.
DEPTHscript.js0.06Quanto arretra una pagina dietro la successiva (0,06 = il 6% più piccola).
BLURscript.js6Quanto è sfocata la pagina dietro, in pixel.
SLIDEscript.js0.4I secondi che le righe impiegano a scivolare al loro posto mentre si scrive.
BANDscript.js[520, 36]La molla della fascia sotto la riga scelta: rigidità e smorzamento.
SHORTCUTscript.js'k'Il tasto che la apre insieme a ⌘ (Mac) o Ctrl.

Provali nel Playground

Quando usarla

Per un’app con molte azioni e pagine: un editor, un pannello di amministrazione, uno strumento per sviluppatori o per squadre, la documentazione di un prodotto. Le pagine interne servono per le scelte con più opzioni (tema, progetto, lingua, persona a cui assegnare); i comandi e i gruppi si cambiano nell’elenco in cima allo script.

Sul telefono

Il riquadro prende la larghezza dello schermo meno 32 pixel; la pillola resta di 300. La riga dei suggerimenti in fondo e il tasto esc spariscono (sul telefono non c’è tastiera fisica), le righe restano alte 42 pixel per il dito, la lista scorre col dito dentro il pannello senza far scorrere la pagina, e un tocco fuori la chiude.

Con il movimento ridotto

Niente morph né profondità: la palette compare in dissolvenza già della sua misura e la pillola sparisce subito; le pagine si scambiano con una dissolvenza, senza scala né sfocatura. Le righe filtrate vanno subito al loro posto e la fascia salta sulla riga scelta. Tutto il resto, tastiera, temi, briciole, funziona uguale.

Trappole

  • Con le righe riordinate per punteggio, mentre scivolavano si incrociavano e per un attimo le parole si sovrapponevano: ora restano nel loro ordine, si muovono solo nello spazio liberato, e il punteggio migliore prende la fascia invece del primo posto.
  • Scrivendo subito dopo l’apertura, le righe stavano ancora entrando con il loro tween e Flip le misurava a metà: un titolo saltava sopra una riga. Prima di filtrare quell’entrata si porta alla fine.
  • Con Flip in modo absolute le righe che uscivano tenevano offsetTop vecchi, la fascia si fermava sul titolo del gruppo invece che sulla riga e Invio eseguiva un comando nascosto: Flip ora lavora solo con le trasformazioni.
  • L’altezza del pannello misurata con scrollHeight contava anche le righe ancora spostate dalla trasformazione di Flip e lasciava un buco in fondo: si misura dall’ultima riga visibile.
  • La pillola che riempiva tutta la superficie, mentre si allargava, portava le sue parole in mezzo alla lista che entrava: ora è ancorata in alto e la lista compare solo quando la pillola è sparita.
  • Provando i temi sulla pagina dei temi e poi tornando indietro o chiudendo, la palette restava col tema provato: tornare e chiudere rimettono quello tenuto.

Librerie

GSAP 3.15.0, Flip (GSAP) 3.15.0, Geist (font variabile) 5.3.0, Geist Mono (font variabile) 5.3.0.

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

Collaudo

Provata il 5 ottobre 2026

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

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