Skip to main content
Un mod può disegnare la propria interfaccia in Claude Code e modificare parti dell’interfaccia che Claude Code disegna già. Ogni luogo in cui un mod può disegnare è chiamato sito di rendering, come un riquadro, la banda sopra il prompt, o lo spinner. Claude Code genera l’evento ui.render ogni volta che sta per disegnare un sito di rendering, e il tuo hook per quell’evento restituisce cosa disegnare lì. Questa mappa mostra dove un mod può disegnare in una sessione terminale: Mappa di una sessione terminale di Claude Code. Un mod può aggiungere un riquadro come barra laterale sulla destra, un toast in alto a destra della trascrizione, una riga di log nella trascrizione, una banda sopra il prompt, e una riga di stato sotto il prompt. Un mod può ridisegnare messaggi, righe di chiamate di strumenti, e lo spinner. Il prompt è proprio di Claude Code. Mappa di una sessione terminale di Claude Code. Un mod può aggiungere un riquadro come barra laterale sulla destra, un toast in alto a destra della trascrizione, una riga di log nella trascrizione, una banda sopra il prompt, e una riga di stato sotto il prompt. Un mod può ridisegnare messaggi, righe di chiamate di strumenti, e lo spinner. Il prompt è proprio di Claude Code. In un terminale più stretto, il riquadro si trova sopra il prompt invece che accanto alla trascrizione. Costruisci il tuo primo mod prima di iniziare qui. Inizia con l’esempio pratico, che costruisce un riquadro con due schede e un contatore, quindi leggi la sezione per ogni parte che desideri modificare.
Per cercare una proprietà o un limite, consulta il riferimento.

Costruire un riquadro con schede

In questa sezione costruisci un mod che aggiunge un comando /hello-tabs e il comando apre un riquadro. Un riquadro è una barra laterale accanto alla trascrizione in un terminale fullscreen ampio, o una regione incorniciata sopra il prompt altrimenti. Questo riquadro mostra due schede, e la seconda scheda ha un pulsante che aggiunge uno a un contatore. Il conteggio è ancora lì dopo aver riavviato Claude Code. Il mod finito assomiglia a questo. La registrazione apre il riquadro, passa alla seconda scheda, preme il pulsante alcune volte e ritorna alla prima scheda:
Claude Code non ha un elemento schede integrato, quindi le schede sono due pulsanti in una riga. Il mod tiene traccia di quale è attivo e disegna il contenuto di quella scheda sotto la riga.
1

Creare il plugin

Un mod è un plugin con un manifesto, un hooks.json che punta al tuo codice, e il file di codice. Creare un mod spiega ognuno. Crea una directory denominata hello-tabs con directory .claude-plugin e hooks al suo interno, quindi salva i primi due file.Salva il manifesto come hello-tabs/.claude-plugin/plugin.json:
hello-tabs/.claude-plugin/plugin.json
Nomina il tuo punto di ingresso in hello-tabs/hooks/hooks.json:
hello-tabs/hooks/hooks.json
2

Scrivere il codice

Il codice fa tre lavori, uno in ogni hook:
  • Aggiunge il comando /hello-tabs
  • Apre il riquadro quando esegui quel comando
  • Disegna il contenuto del riquadro: la riga di schede e il corpo della scheda aperta
Due variabili a livello di modulo, tab e count, mantengono lo stato del riquadro.Salva questo come hello-tabs/hooks/register.js:
hello-tabs/hooks/register.js
Ogni hook fa anche qualcosa che il codice non rende evidente:
  • session.start legge anche il conteggio salvato da $.store, un archivio chiave-valore che persiste tra le sessioni.
  • command.run dice solo a Claude Code che il riquadro esiste. Aprire un riquadro non disegna nulla di per sé: Claude Code quindi genera ui.render per chiedere cosa metterci.
  • ui.render restituisce l’albero degli elementi, un Box che contiene altri box, testo e pulsanti, e lo costruisce di nuovo da tab e count ogni volta che viene eseguito.
Premere un pulsante esegue il suo callback onPress, che cambia una variabile e chiama redraw. Claude Code quindi esegue di nuovo l’hook ui.render, e l’hook costruisce un nuovo albero dai nuovi valori. Ogni disegno interattivo utilizza quel ciclo di rendering: un callback cambia lo stato, e l’hook esegue il rendering di nuovo dal nuovo stato.
3

Aprire il riquadro

Nella tua shell, avvia Claude Code con claude --plugin-dir ./hello-tabs. Al prompt di Claude Code, esegui /hello-tabs. Un riquadro si apre con 1: One e 2: Two nella parte superiore. Premi 2, quindi premi a, la scorciatoia da tastiera per Add one, alcune volte. Il conteggio aumenta.
4

Verificare che il conteggio sia stato salvato

Premi Esc per chiudere il riquadro, quindi esci dalla sessione. Nella tua shell, avvia di nuovo Claude Code con lo stesso comando claude --plugin-dir ./hello-tabs, e al prompt di Claude Code esegui /hello-tabs. Il conteggio è dove l’hai lasciato.Per cancellare il conteggio, fai in modo che il mod chiami $.store.delete('count'). Mantenere lo stato spiega quanto tempo dura ogni tipo di valore.

Scegliere dove disegnare

Un hook ui.render viene eseguito per ogni sito di rendering a meno che non lo restringi a quello che desideri disegnare. Per scegliere il sito di rendering, passa un filtro, chiamato matcher, come secondo argomento a on. { component: 'Pane' } esegue l’hook solo per i riquadri. Nell’hook, e.component nomina il sito, e.surface dice quale app sta disegnando, e e.props contiene i dati propri del sito. Per un riquadro, e.requestId è l’id con cui l’hai aperto. Due siti sono vuoti finché un mod non li riempie, il riquadro e la banda. Seleziona una scheda per vedere cosa è ognuno e come disegnare in esso:
Un riquadro è una barra laterale accanto alla trascrizione in un terminale fullscreen ampio, o una regione incorniciata sopra il prompt altrimenti. Con più riquadri aperti, ognuno ottiene una scheda che mostra il suo titolo.Un riquadro appare quando il tuo mod chiama $.ui.open con un id che scegli, come in $.ui.open({ id: 'hello-tabs' }). Aprire un riquadro al momento giusto copre gli altri campi e quando un riquadro aspetta un terminale più ampio.Per disegnare nel tuo riquadro, filtra su { component: 'Pane' } e verifica che e.requestId sia il tuo id.

Modificare quello che Claude Code disegna già

Claude Code disegna la maggior parte della sua interfaccia da solo: messaggi, righe di chiamate di strumenti, lo spinner, e altro. Ognuna di quelle parti è un sito di rendering anche, quindi un mod può ridisegnarlo o sostituirlo. Per modificarne uno, filtra il tuo hook ui.render sul suo nome da questa tabella: In un sito che Claude Code disegna già, il tuo hook ha tre scelte: modificare un dettaglio, sostituire il disegno, o lasciarlo in pace. Seleziona una scheda per vedere ognuno applicato allo spinner. Gli esempi leggono una variabile calls che un altro hook conta, come nel mod del tutorial.
Per mantenere il disegno di Claude Code e modificare una parte di esso, passa a next una copia dell’evento con props modificati. Questo hook cambia il testo dopo la parola dello spinner:
Lo spinner mantiene la sua animazione e la sua parola, e il tuo testo segue la parola:
Il prompt di autorizzazione non è un sito di rendering, quindi un mod non può modificare quello che mostra. La finestra di dialogo della domanda, AskUserQuestion, è uno, quindi un mod può modificare quello. Il terminale e l’app Desktop non generano tutti gli stessi siti. Pane, AbovePrompt, Spinner, e i siti della trascrizione funzionano in entrambi. Poche altre righe di stato vengono generate solo nel terminale. La tabella dei siti di rendering elenca dove viene generato ognuno.

Aprire un riquadro al momento giusto

Un riquadro appare solo quando il tuo mod lo apre. Come e quando lo apri decide se prende il focus della tastiera, quanto spazio chiede, e se appare affatto in un terminale stretto. Per aprire un riquadro, chiama $.ui.open con un id che scegli. L’id è il nome del riquadro: il tuo hook ui.render lo controlla, e lo passi di nuovo per chiudere il riquadro.
Per chiudere il riquadro, chiama $.ui.close con l’id con cui l’hai aperto:
Oltre a id, $.ui.open accetta questi campi opzionali: Per lasciare che un comando apra il riquadro mentre Claude sta lavorando, aggiungi immediate: true quando registri il comando. Senza di esso, un comando digitato durante un turno aspetta che il turno finisca.

Quando un riquadro aspetta un terminale più ampio

Un riquadro che il tuo mod apre senza essere chiesto non appare in un terminale stretto, quindi non può prendere il controllo di uno schermo piccolo. Se appare dipende da cosa l’ha aperto:
  • Aperto da qualcosa che l’utente ha fatto, come un comando che ha eseguito o un pulsante che ha premuto, il riquadro appare a qualsiasi larghezza
  • Aperto dal tuo mod che agisce da solo, come da un timer o un hook turn.start, il riquadro appare solo in un terminale di almeno 144 colonne di larghezza. Dopo che l’utente ha aperto quel riquadro una volta da solo, 110 colonne sono sufficienti.
Quando il riquadro appare, $.ui.open si risolve in { isPlaced: true }. Quando il riquadro è in attesa, isPlaced è false e reason è una stringa che dice perché. Un riquadro in attesa appare quando l’utente lo apre o allarga il terminale. Per dire che qualcosa è disponibile senza aprire un riquadro, chiama $.ui.toast('Your message'), che mostra un piccolo avviso che scompare dopo pochi secondi.

Costruire un albero da elementi

Quello che un hook ui.render restituisce è un albero di elementi: una descrizione di cosa disegnare, fatta di box, testo e controlli annidati l’uno dentro l’altro. Descrivi il disegno, e Claude Code lo renderizza nel terminale o nell’app Desktop. Per ottenere gli elementi, chiama $.ui.resolve(e) nel tuo hook, come in const { Box, Text, Button } = $.ui.resolve(e). Ogni elemento è una funzione. Passi le proprietà, e metti gli elementi e le stringhe che vanno dentro di esso in children. La maggior parte dei disegni usa quattro elementi. Seleziona una scheda per vedere ognuno e come il terminale lo disegna:
Text disegna una stringa, con stile opzionale come bold e color:
Questa tabella elenca ogni elemento: Se il tuo modulo è un file .tsx o .jsx, puoi scrivere l’albero come JSX. Destruttura gli elementi da $.ui.resolve(e) per primo, perché un modulo di hook non ha globali di elementi. Se un albero usa un elemento che l’app non ha, una proprietà che un elemento non accetta, o un figlio dove nessuno va, Claude Code disegna la sua versione del sito. In una sessione avviata con --plugin-dir, una riga di trascrizione lo dice, come ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own. Il log di debug lo registra come ui.render (Pane): a hook returned a tree that does not validate con la stessa ragione. Nient’altro appare nella sessione, quindi quando un disegno non si mostra, controlla quella riga o il log.

Disegnare una griglia di celle colorate

Per una mappa di calore, una sparkline, o una tavola di gioco nel terminale, disegna un Raster e non un Box per ogni cella. Un Raster accetta una key, la sua dimensione in columns e rows, e cells, che compatta ogni cella in una stringa. Ogni cella è tre numeri: il punto di codice del carattere, il suo colore, e il colore di sfondo. Un colore è un numero esadecimale con due cifre ciascuno per rosso, verde e blu, come 0xc62828 per un rosso, o 0x01000000 per il default del terminale. L’app Desktop non ha Raster, quindi controlla e.surface e disegna testo lì. Questo corpo del riquadro disegna una mappa di calore tre per due:
Nel terminale, il riquadro mostra la griglia: Un riquadro nel terminale che contiene una piccola griglia di blocchi colorati, due righe di tre. La riga superiore è verde, ambra e rossa. La riga inferiore è verde, verde e ambra. L’array rows è la parte che cambieresti, e cellsOf lo trasforma nella stringa compatta. L’hook disegna solo in un riquadro il cui id è heat, quindi aprine uno con $.ui.open({ id: 'heat' }) da un comando, come l’esempio hello-tabs apre il suo riquadro. Ogni carattere deve essere largo una cella. Per animare un Raster che è già sullo schermo, chiama $.ui.blit con l’id del riquadro come requestId, la key del Raster, la stessa dimensione, e celle nuove. Per questo esempio, è $.ui.blit({ requestId: 'heat', key: 'grid', columns: 3, rows: 2, cells: cellsOf(newRows) }). Ridipinge solo quell’elemento senza eseguire di nuovo il tuo hook ui.render.

Rispondere a pressioni e digitazione

Quando l’utente preme un pulsante, digita in un campo, o sceglie da un elenco che il tuo mod ha disegnato, Claude Code chiama la funzione che hai dato a quel controllo, e viene eseguita nel tuo modulo. Ogni controllo accetta i suoi callback:
  • Button: accetta onPress(e), dove e.surface è l’app da cui viene la pressione
  • Input: accetta onSubmit(value) e onInput(value)
  • Select: accetta onSelect(value) con le sue scelte in options, un elenco di almeno una scelta con valori unici, come [{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]
Un test preme o digita in un controllo per la sua key, quindi dagli uno. Ogni uso di un controllo genera anche ui.press, ui.input, o ui.select con la key in e.element, e un altro mod può agganciare quegli eventi. Il suo hook viene eseguito prima del tuo callback, quindi vede quello che l’utente digita nel tuo Input e può cambiarlo o rispondere al posto del tuo callback. L’API dei mod non ha un metodo che preme il pulsante di un altro mod.

Focus della tastiera e scorciatoie da tastiera

Il tuo mod non legge mai la tastiera da solo. L’utente preme un tasto, Claude Code decide quale dei tuoi controlli è per esso, e il callback di quel controllo viene eseguito. A parte una scorciatoia da tastiera con cifra sulla banda, questo accade solo mentre il tuo riquadro o banda ha il focus della tastiera. Il resto del tempo, i tasti vanno al prompt.

Come un riquadro ottiene il focus della tastiera

Un riquadro ottiene il focus della tastiera in uno di tre modi:
  • Il tuo mod lo apre con focus: true da un comando o una pressione
  • L’utente preme Ctrl+X poi Tab
  • L’utente lo fa clic
Claude Code concede focus: true solo mentre il prompt è vuoto e nient’altro ha il focus della tastiera. Un riquadro che si apre mentre l’utente sta digitando non prende i suoi tasti.

Cosa fa ogni tasto

Questa tabella elenca cosa fa un tasto mentre il tuo riquadro o banda ha il focus della tastiera: Un mod non può associare Tab o i tasti freccia a nient’altro, quindi un gioco si muove con w, a, s, e d.

Impostare una scorciatoia da tastiera e il primo focus

Due proprietà su un controllo decidono come la tastiera lo raggiunge:
  • hotkey: per lasciare che l’utente preme un Button con un tasto, dagli una hotkey di una cifra o una lettera minuscola, come in hotkey: 'a'
  • autoFocus: per scegliere quale controllo ha il focus quando il riquadro si apre, aggiungi autoFocus: true ad esso. Lascia la proprietà fuori dagli altri, perché Claude Code rifiuta autoFocus: false.
Come una scorciatoia da tastiera si mostra dipende dal pulsante e dall’app: Nel terminale, nomina il tasto nell’etichetta di un pulsante tra parentesi, o usa plain: true, così l’utente può vedere cosa premere. Il riferimento degli elementi ha le altre regole di Button: action, scorciatoie da tastiera con cifra sulla banda, e due pulsanti su una scorciatoia da tastiera.

Prendere input digitato e disegnare una riga per ogni elemento

Molti riquadri sono un campo di testo con un elenco sotto. L’esempio in questa sezione è un riquadro di note: digiti una nota e premi Invio per aggiungerla, e ogni nota ha un pulsante x che la elimina. Con due note aggiunte, il terminale disegna il riquadro in questo modo:
L’esempio usa due tecniche:
  • Prendere input digitato: un Input chiama onSubmit(value) con il testo del campo quando l’utente preme Invio, e onInput(value) ad ogni cambio
  • Disegnare un elenco: mappa i tuoi dati a una riga ciascuno, e dai a ogni pulsante della riga la sua key
Questo hook disegna il contenuto del riquadro:
Per provare il riquadro:
  • Aggiungi una nota: digita una riga e premi Invio. La riga appare come una nuova riga, e il campo si svuota.
  • Elimina una nota: premi Tab finché il pulsante x della nota non ha il focus, quindi premi Invio. La x è l’etichetta del pulsante e non una scorciatoia da tastiera, quindi digitare la lettera non lo preme.
Ogni cambio segue lo stesso ciclo di rendering di hello-tabs: il callback cambia notes, chiama redraw, e salva l’elenco in $.store. Il campo si svuota dopo ogni invio a causa della sua proprietà value. value è il testo che il campo contiene quando viene disegnato, e la digitazione dell’utente lo sostituisce finché il tuo hook non disegna il campo di nuovo. L’esempio disegna sempre il campo con ''. L’esempio salva le note e non le carica. Per riportarle nella sessione successiva, leggile in un hook session.start, come hello-tabs legge count. Tre proprietà compongono la riga del campo, Note: Type a note and press Enter ⏎ add: Inviare un Input non avvia un turno a meno che il tuo callback non chiami $.prompt.submit.

Ridisegnare un sito

Un disegno è un’istantanea: mostra quello che il tuo hook ui.render ha restituito l’ultima volta che l’hook è stato eseguito. Per mostrare qualcosa di nuovo, l’hook deve essere eseguito di nuovo. Claude Code lo esegue di nuovo per alcuni cambiamenti, e il tuo mod chiede il resto.

Quando Claude Code ridisegna senza essere chiesto

Claude Code esegue di nuovo il tuo hook ui.render quando le proprietà del sito cambiano o la larghezza del terminale cambia. Non esegue l’hook su un timer, e non può dire quando una variabile nel tuo modulo cambia.

Ridisegnare quando i tuoi dati cambiano

Per avere i tuoi siti disegnati di nuovo dopo che i tuoi dati cambiano, chiama $.ui.invalidate('ui.render'). Questo riquadro conta le pressioni. Il callback del pulsante cambia count, quindi chiede un ridisegno:
Ogni pressione alza il numero nel riquadro. L’esempio hello-tabs avvolge la stessa chiamata nella sua funzione redraw. Un valore che mantieni in $.state non ha bisogno della chiamata, perché scrivere il valore ridisegna i siti che lo leggono.

Ridisegnare su un timer

Per mantenere un orologio, un conto alla rovescia, o un valore da fuori la sessione attuale, ridisegna su un programma. Avvia un timer nell’hook session.start del modulo. Se il modulo ne ha già uno, come hello-tabs, aggiungi la riga $.clock.every ad esso:
Claude Code ora esegue il tuo hook ui.render una volta al secondo. Il timer si ferma quando il modulo si ricarica, e la nuova copia del modulo avvia il suo.

Quanto spesso un sito può ridisegnare

Claude Code limita quanto spesso ridisegna un sito, quindi il tuo mod può chiamare $.ui.invalidate quanto spesso i suoi dati cambiano. Il riquadro visibile e la banda hanno un limite più alto rispetto ad altri siti, e la tabella dei limiti contiene i numeri. Le chiamate che arrivano più velocemente del limite vengono combinate in un ridisegno. Quel ridisegno esegue il tuo hook una volta, e l’hook legge i tuoi dati come sono in quel momento, quindi il valore più recente si mostra e i valori in mezzo no. Un’animazione non può essere eseguita più velocemente del limite.

Mantenere lo stato

Un mod ha tre posti per mantenere un valore, e differiscono in quanto tempo il valore dura: finché il modulo non si ricarica, finché la sessione non finisce, o da una sessione all’altra. Scegli in base a quanto tempo il valore deve durare: $.store.get(key) si risolve nel valore o undefined, e $.store.set(key, value) accetta qualsiasi valore JSON.

Mantenere un valore in $.state

$.state contiene valori per la durata di una sessione, e ridisegna per te. È uno stato reattivo: un hook ui.render che legge un valore si iscrive ad esso, quindi Claude Code ridisegna quel sito ogni volta che scrivi il valore, e non chiami $.ui.invalidate. Un valore in $.state sopravvive anche a un ricaricamento del modulo, che una variabile non fa. Per configurarlo, dichiara i tuoi valori, punta il tuo manifesto alla dichiarazione, quindi definisci e usa ogni valore. Gli esempi spostano il count da hello-tabs in $.state.

Dichiarare i valori

Dichiara i valori in un file di tipi. La chiave esterna è il nome del tuo plugin, e ogni voce sotto di esso è un valore e il suo tipo. Salva questo come hello-tabs/types/index.d.ts:
hello-tabs/types/index.d.ts

Puntare il manifesto alla dichiarazione

Per lasciare che claude plugin validate controlli il tuo codice contro quel file, aggiungi un campo types al manifesto con il suo percorso:
hello-tabs/.claude-plugin/plugin.json

Definire, leggere e scrivere un valore

Nel tuo modulo, definisci ogni valore con un default, leggilo mentre disegni, e scrivilo da un callback. atom nomina un valore e il suo default, read lo restituisce, e update lo scrive. I tre helper chiamano $.state.get e $.state.set per te:
Perché l’hook ui.render ha letto count, Claude Code esegue l’hook di nuovo ogni volta che il pulsante lo scrive. Tre regole si applicano al codice:
  • Scrivi plugin e key come stringhe letterali: claude plugin validate le legge dal tuo sorgente
  • Dichiara ogni valore nel file di tipi: altrimenti la validazione fallisce con hello-tabs.count is not declared
  • Scrivi da un callback o dall’hook di un altro evento: un hook ui.render può leggere lo stato e non può scriverlo, quindi scrivi da onPress, onSubmit, o un hook per un altro evento

Cambiare hello-tabs per usare $.state

Per spostare count in hello-tabs in $.state, cambia ogni riga che lo usa:
  • In cima al modulo: aggiungi la riga import, e sostituisci let count = 0 con la riga atom
  • Nell’hook ui.render: aggiungi la riga read prima di tabButton, e disegna 'Count: ' + n nel Text
  • Nel pulsante Add one: sostituisci onPress con quello in Salvare da più di una sessione, che salva il conteggio così come lo scrive
  • Nell’hook session.start: sostituisci le due righe che leggono saved con la chiamata loadCount da Caricare un valore salvato di nuovo dopo /clear
Mantieni redraw per i pulsanti delle schede, perché tab è ancora una variabile.

Caricare un valore salvato di nuovo dopo /clear

Se il tuo mod copia un valore salvato da $.store in $.state a session.start, deve copiarlo di nuovo dopo /clear, /resume, o /branch. Questi comandi rimettono ogni valore $.state al suo default, e session.start non viene generato di nuovo. classic.SessionStart viene generato dopo ognuno di essi, con e.source impostato a clear, resume, o fork, quindi copia il valore di nuovo in un hook su di esso. Altrimenti il tuo disegno mostra il default, e un callback che salva il valore $.state scrive il default su quello che hai archiviato. Questo codice carica count da entrambi gli hook. Si basa sulla versione $.state di hello-tabs, dove count è un atom e update è importato. Metti loadCount sopra register, e aggiungi la chiamata loadCount all’hook session.start che hai già. classic.SessionStart viene generato anche all’avvio e dopo la compattazione, che non ripristina $.state, quindi il filtro su source mantiene l’hook ai tre ripristini:
Con entrambi gli hook in posizione, il riquadro mostra il conteggio salvato dopo /clear e non 0, e la prossima pressione di Add one aggiunge al conteggio salvato. loadCount scrive il valore archiviato su quello in $.state, e session.start viene generato di nuovo ogni volta che il modulo si ricarica. Per mantenere lo store dal rimanere indietro, salva ad ogni cambio, come il pulsante Add one fa. Per controllare il ricaricamento senza una sessione, testa il disegno dopo /clear.

Salvare da più di una sessione

Ogni sessione sulla tua macchina che esegue il tuo mod condivide uno $.store. Un get seguito da un set non è atomico. Quando due sessioni leggono ciascuna un valore, lo cambiano, e lo scrivono di nuovo, corrono, e la seconda scrittura sostituisce la prima. Due scelte lo rendono meno probabile:
  • Dai a ogni elemento la sua chiave: un set cambia solo la sua chiave, quindi le sessioni che scrivono chiavi diverse non si sovrascrivono a vicenda
  • Leggi di nuovo subito prima di scrivere: per un valore che più sessioni cambiano, get la chiave nel callback e costruisci il nuovo valore da quello, non da una copia che hai caricato a session.start. Un’altra scrittura della sessione è ancora persa se atterra tra il tuo get e il tuo set.
Questo pulsante aggiunge uno a quello che lo store contiene ora, quindi aggiorna il disegno:
Se una seconda sessione ha premuto il suo pulsante tre volte da quando questa sessione è iniziata, questa pressione mostra e salva un conteggio che include quei tre.

Prossimi passi