Ricreare il pulsante Arduino usando SVG e <lit-element>
Pubblicato: 2022-03-10In questo articolo imparerai come creare componenti HTML personalizzati che imitano oggetti fisici, come Arduino Pushbutton. Disegneremo il componente in Inkscape da zero, ottimizzeremo il codice SVG generato per il Web e lo avvolgeremo come componente Web autonomo utilizzando la libreria
lit-element
leggera, prestando particolare attenzione alle considerazioni sull'accessibilità e sull'usabilità mobile. Oggi ti condurrò attraverso il viaggio di creazione di un componente HTML che imita un componente pulsante momentaneo comunemente usato con Arduino e nei progetti elettronici. Utilizzeremo tecnologie come SVG, Web Components e lit-element
e impareremo come rendere accessibile il pulsante tramite alcuni trucchi JavaScript-CSS.
Iniziamo!
Da Arduino a HTML: la necessità di un componente a pulsante
Prima di intraprendere il viaggio, esploriamo cosa creeremo e, soprattutto, perché. Sto creando un simulatore Arduino open source in JavaScript chiamato avr8js. Questo simulatore è in grado di eseguire il codice Arduino e lo userò in una serie di tutorial e corsi che insegneranno ai maker come programmare per Arduino.
Il simulatore stesso si occupa solo dell'esecuzione del programma: esegue l'istruzione del codice per istruzione e aggiorna il suo stato interno e un buffer di memoria in base alla logica del programma. Per interagire con il programma Arduino, è necessario creare dei componenti elettronici virtuali in grado di inviare input al simulatore o reagire alle sue uscite.
L'esecuzione del simulatore da solo è molto simile all'esecuzione di JavaScript in isolamento. Non puoi davvero interagire con l'utente a meno che tu non crei anche alcuni elementi HTML e li colleghi al codice JavaScript tramite il DOM.
Quindi, oltre al simulatore del processore, sto lavorando anche su una libreria di componenti HTML che imitano l'hardware fisico, a cominciare dai primi due componenti che troverai in quasi tutti i progetti di elettronica: un LED e un pulsante.
Il LED è relativamente semplice, poiché ha solo due stati di uscita: acceso e spento. Dietro le quinte, utilizza un filtro SVG per creare l'effetto luminoso.
Il pulsante è più interessante. Ha anche due stati, ma deve reagire all'input dell'utente e aggiornare il suo stato di conseguenza, ed è da qui che viene la sfida, come vedremo tra breve. Ma prima, analizziamo i requisiti del nostro componente che creeremo.
Definizione dei requisiti per il pulsante
Il nostro componente assomiglierà a un pulsante da 12 mm. Questi pulsanti sono molto comuni negli starter kit elettronici e sono dotati di cappucci in più colori, come puoi vedere nella foto qui sotto:
In termini di comportamento, il pulsante dovrebbe avere due stati: premuto e rilasciato. Questi sono simili agli eventi HTML mousedown/mouseup, ma dobbiamo assicurarci che i pulsanti possano essere utilizzati anche da dispositivi mobili e siano accessibili agli utenti senza mouse.
Poiché utilizzeremo lo stato del pulsante come input per Arduino, non è necessario supportare gli eventi "clic" o "doppio clic". Spetta al programma Arduino in esecuzione nella simulazione decidere come agire sullo stato del pulsante e i pulsanti fisici non generano eventi di clic.
Se vuoi saperne di più, dai un'occhiata a un discorso che ho tenuto con Benjamin Gruenbaum alla SmashingConf Freiburg nel 2019: "Anatomy of a Click".
Per riassumere le nostre esigenze, il nostro pulsante deve:
- sembra simile al pulsante fisico da 12 mm;
- hanno due stati distinti: premuto e rilasciato e dovrebbero essere visivamente distinguibili;
- supportare l'interazione con il mouse, i dispositivi mobili ed essere accessibile agli utenti della tastiera;
- supporta diversi colori del cappuccio (almeno rosso, verde, blu, giallo, bianco e nero).
Ora che abbiamo definito i requisiti, possiamo iniziare a lavorare sull'implementazione.
SVG per la vittoria
La maggior parte dei componenti Web viene implementata utilizzando una combinazione di CSS e HTML. Quando abbiamo bisogno di una grafica più complessa, di solito utilizziamo immagini raster, in formato JPG o PNG (o GIF se ti senti nostalgico).
Nel nostro caso, invece, utilizzeremo un altro approccio: la grafica SVG. SVG si presta a grafiche complesse molto più facilmente dei CSS (sì, lo so, puoi creare cose affascinanti con CSS, ma non significa che dovrebbe). Ma non preoccuparti, non rinunciamo del tutto ai CSS. Ci aiuterà a modellare i pulsanti e, eventualmente, anche a renderli accessibili.
SVG ha un altro grande vantaggio, rispetto alle immagini grafiche raster: è molto facile da manipolare da JavaScript e può essere disegnato tramite CSS. Ciò significa che possiamo fornire una singola immagine per il pulsante e utilizzare JavaScript per personalizzare il limite di colore e gli stili CSS per indicare lo stato del pulsante. Pulito, non è vero?
Infine, SVG è solo un documento XML, che può essere modificato con editor di testo e incorporato direttamente in HTML, rendendolo una soluzione perfetta per la creazione di componenti HTML riutilizzabili. Sei pronto a disegnare il nostro pulsante?
Disegnare il pulsante con Inkscape
Inkscape è il mio strumento preferito per creare grafica vettoriale SVG. È gratuito e ricco di potenti funzionalità, come un'ampia raccolta di predefiniti di filtri incorporati, traccia bitmap e operazioni binarie di percorso. Ho iniziato a usare Inkscape per creare PCB art, ma negli ultimi due anni ho iniziato a usarlo per la maggior parte delle mie attività di editing grafico.
Disegnare il pulsante in Inkscape è piuttosto semplice. Disegneremo un'illustrazione dall'alto del pulsante e dei suoi quattro fili metallici che lo collegano ad altre parti, come segue:
- Rettangolo grigio scuro 12×12 mm per la custodia in plastica, con angoli leggermente arrotondati per renderlo più morbido.
- Rettangolo grigio chiaro più piccolo, 10,5×10,5 per la copertura in metallo.
- Quattro cerchi più scuri, uno in ogni angolo per i perni che tengono insieme il pulsante.
- Un grande cerchio al centro, che è il contorno del cappuccio del bottone.
- Un cerchio più piccolo al centro per la parte superiore del cappuccio del bottone.
- Quattro rettangoli grigio chiaro a forma di “T” per le mina metalliche del bottone.
E il risultato, leggermente ingrandito:
Come tocco finale, aggiungeremo un po' di magia gradiente SVG al contorno del pulsante, per dargli una sensazione 3D:
Eccoci! Abbiamo la grafica, ora dobbiamo portarla sul web.
Da Inkscape a Web SVG
Come accennato in precedenza, gli SVG sono piuttosto semplici da incorporare in HTML: puoi semplicemente incollare il contenuto del file SVG nel tuo documento HTML, aprirlo in un browser e verrà visualizzato sullo schermo. Puoi vederlo in azione nel seguente esempio CodePen:
Tuttavia, i file SVG salvati da Inkscape contengono molti bagagli non necessari come la versione di Inkscape e la posizione della finestra quando hai salvato il file l'ultima volta. In molti casi, ci sono anche elementi vuoti, gradienti e filtri inutilizzati e tutti gonfiano le dimensioni del file e rendono più difficile lavorarci all'interno di HTML.
Fortunatamente, Inkscape può pulire la maggior parte del disordine per noi. Ecco come lo fai:
- Vai al menu File e fai clic su Pulisci documento . (Ciò rimuoverà le definizioni non utilizzate dal tuo documento.)
- Vai di nuovo su File e fai clic su Salva con nome... . Durante il salvataggio, seleziona SVG ottimizzato ( *.svg ) nell'elenco a discesa Salva come tipo .
- Verrà visualizzata una finestra di dialogo "Output SVG ottimizzato" con tre schede. Seleziona tutte le opzioni, ad eccezione di "Mantieni i dati dell'editor", "Mantieni definizioni senza riferimenti" e "Conserva ID creati manualmente...".
La rimozione di tutte queste cose creerà un file SVG più piccolo con cui è più facile lavorare. Nel mio caso, il file è passato da 4593 byte a soli 2080 byte, meno della metà delle dimensioni. Per file SVG più complessi, questo può comportare un enorme risparmio di larghezza di banda e può fare una notevole differenza nel tempo di caricamento della tua pagina web.
L'SVG ottimizzato è anche molto più facile da leggere e capire. Nel seguente estratto, dovresti essere in grado di individuare facilmente i due rettangoli che compongono il corpo del pulsante:
<rect width="12" height="12" rx=".44" ry=".44" fill="#464646" stroke-width="1.0003"/> <rect x=".75" y=".75" width="10.5" height="10.5" rx=".211" ry=".211" fill="#eaeaea"/> <g fill="#1b1b1b"> <circle cx="1.767" cy="1.7916" r=".37"/> <circle cx="10.161" cy="1.7916" r=".37"/> <circle cx="10.161" cy="10.197" r=".37"/> <circle cx="1.767" cy="10.197" r=".37"/> </g> <circle cx="6" cy="6" r="3.822" fill="url(#a)"/> <circle cx="6" cy="6" r="2.9" fill="#ff2a2a" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08"/>
Puoi anche abbreviare ulteriormente il codice, ad esempio, modificando la larghezza del tratto del primo rettangolo da 1.0003
a solo 1
. Non fa una differenza significativa nella dimensione del file, ma rende il codice più facile da leggere.
In generale, è sempre utile un passaggio manuale sul file SVG generato. In molti casi, è possibile rimuovere gruppi vuoti o applicare trasformazioni matriciali, nonché semplificare le coordinate del gradiente mappandole da "spazio utente in uso" (coordinate globali) a "riquadro di delimitazione dell'oggetto" (relativo all'oggetto). Queste ottimizzazioni sono facoltative, ma ottieni un codice più facile da comprendere e mantenere.
Da questo momento in poi, metteremo via Inkscape e lavoreremo con la rappresentazione testuale dell'immagine SVG.
Creazione di un componente Web riutilizzabile
Finora abbiamo ottenuto la grafica per il nostro pulsante, pronta per essere inserita nel nostro simulatore. Possiamo facilmente personalizzare il colore del pulsante modificando l'attributo di fill
del cerchio più piccolo e il colore iniziale del gradiente del cerchio più grande.
Il nostro prossimo obiettivo è trasformare il nostro pulsante in un Componente Web riutilizzabile che può essere personalizzato passando un attributo di color
e che reagisca all'interazione dell'utente (eventi di stampa/rilascio). Utilizzeremo lit-element
, una piccola libreria che semplifica la creazione di Web Components.
lit-element
eccelle nella creazione di librerie di componenti piccole e autonome. È basato sullo standard dei componenti Web, che consente a questi componenti di essere utilizzati da qualsiasi applicazione Web, indipendentemente dal framework utilizzato: Angular, React, Vue o Vanilla JS sarebbero tutti in grado di utilizzare il nostro componente.
La creazione di componenti in lit-element
viene eseguita utilizzando una sintassi basata su classi, con un metodo render()
che restituisce il codice HTML per l'elemento. Un po' simile a React, se lo conosci. Tuttavia, a differenza di react, lit-element
usa i valori letterali di template con tag Javascript standard per definire il contenuto del componente.
Ecco come creeresti un semplice componente hello-world
:
import { customElement, html, LitElement } from 'lit-element'; @customElement('hello-world') export class HelloWorldElement extends LitElement { render() { return html` <h1> Hello, World! </h1> `; } }
Questo componente può quindi essere utilizzato ovunque nel codice HTML semplicemente scrivendo <hello-world></hello-world>
.
Nota : in realtà, il nostro pulsante richiede solo un po' più di codice: dobbiamo dichiarare una proprietà di input per il colore, usando il @property()
(e con un valore predefinito di rosso), e incollare il codice SVG nel nostro render()
, sostituendo il colore del cappuccio del pulsante con il valore della proprietà color (vedi esempio). I bit importanti sono nella riga 5, dove definiamo la proprietà color: @property() color = 'red';
Inoltre, nella riga 35 (dove usiamo questa proprietà per definire il colore di riempimento per il cerchio che forma il cappuccio del pulsante), usando la sintassi letterale del template JavaScript, scritta come ${color}
:
<circle cx="6" cy="6" r="2.9" fill="${color}" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08" />
Renderlo interattivo
L'ultimo pezzo del puzzle sarebbe rendere interattivo il pulsante. Ci sono due aspetti che dobbiamo considerare: la risposta visiva all'interazione e la risposta programmatica all'interazione.
Per la parte visiva, possiamo semplicemente invertire il riempimento sfumato del contorno del pulsante, che creerà l'illusione che il pulsante sia stato premuto:
Il gradiente per il contorno del pulsante è definito dal seguente codice SVG, dove ${color}
viene sostituito con il colore del pulsante da lit-element
, come spiegato sopra:
<linearGradient x1="0" x2="1" y1="0" y2="1"> <stop stop-color="#ffffff" offset="0" /> <stop stop-color="${color}" offset="0.3" /> <stop stop-color="${color}" offset="0.5" /> <stop offset="1" /> </linearGradient>
Un approccio per l'aspetto del pulsante premuto consiste nel definire un secondo gradiente, invertire l'ordine dei colori e utilizzarlo come riempimento del cerchio ogni volta che si preme il pulsante. Tuttavia, c'è un bel trucco che ci permette di riutilizzare lo stesso gradiente: possiamo ruotare l'elemento svg di 180 gradi usando una trasformazione SVG:
<circle cx="6" cy="6" r="3.822" fill="url(#a)" transform="rotate(180 6 6)" />
L'attributo transform
dice a SVG che vogliamo ruotare il cerchio di 180 gradi e che la rotazione dovrebbe avvenire attorno al punto (6, 6) che è il centro del cerchio (definito da cx
e cy
). Le trasformazioni SVG influiscono anche sul riempimento della forma, quindi anche il nostro gradiente verrà ruotato.
Vogliamo invertire il gradiente solo quando viene premuto il pulsante, quindi invece di aggiungere l'attributo transform
direttamente sull'elemento <circle>
, come abbiamo fatto sopra, imposteremo effettivamente una classe CSS per questo elemento, e quindi ne approfitteremo del fatto che gli attributi SVG possono essere impostati tramite CSS, anche se utilizzando una sintassi leggermente diversa:
transform: rotate(180deg); transform-origin: 6px 6px;
Queste due regole CSS fanno esattamente lo stesso della transform
che avevamo sopra: ruota il cerchio di 180 gradi attorno al suo centro in (6, 6). Vogliamo che queste regole vengano applicate solo quando viene premuto il pulsante, quindi aggiungeremo un nome di classe CSS alla nostra cerchia:
<circle class="button-contour" cx="6" cy="6" r="3.822" fill="url(#a)" />
E ora possiamo usare la pseudo-classe :active CSS per applicare una trasformazione al button-contour
ogni volta che si fa clic sull'elemento SVG:
svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; }
lit-element
ci permette di allegare un foglio di stile al nostro componente dichiarandolo in un getter statico all'interno della nostra classe componente, usando un letterale template taggato:
static get styles() { return css` svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; } `; }
Proprio come il modello HTML, questa sintassi ci consente di iniettare valori personalizzati nel nostro codice CSS, anche se qui non ne abbiamo bisogno. lit-element
si occupa anche della creazione di Shadow DOM per il nostro componente, in modo che il CSS influisca solo sugli elementi all'interno del nostro componente e non sanguini su altre parti dell'applicazione.
Ora, che dire del comportamento programmatico del pulsante quando viene premuto? Vogliamo attivare un evento in modo che gli utenti del nostro componente possano capire ogni volta che lo stato del pulsante cambia. Un modo per farlo è ascoltare gli eventi mousedown e mouseup sull'elemento SVG e attivare gli eventi "button-press"/"button-release" di conseguenza. Ecco come appare con la sintassi lit-element
:
render() { const { color } = this; return html` <svg @mousedown=${() => this.dispatchEvent(new Event('button-press'))} @mouseup=${() => this.dispatchEvent(new Event('button-release'))} ... </svg> `; }
Tuttavia, questa non è la soluzione migliore, come vedremo a breve. Ma prima, dai una rapida occhiata al codice che abbiamo ottenuto finora:
import { customElement, css, html, LitElement, property } from 'lit-element'; @customElement('wokwi-pushbutton') export class PushbuttonElement extends LitElement { @property() color = 'red'; static get styles() { return css` svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; } `; } render() { const { color } = this; return html` <svg @mousedown=${() => this.dispatchEvent(new Event('button-press'))} @mouseup=${() => this.dispatchEvent(new Event('button-release'))} width="18mm" height="12mm" version="1.1" viewBox="-3 0 18 12" xmlns="https://www.w3.org/2000/svg" > <defs> <linearGradient x1="0" x2="1" y1="0" y2="1"> <stop stop-color="#ffffff" offset="0" /> <stop stop-color="${color}" offset="0.3" /> <stop stop-color="${color}" offset="0.5" /> <stop offset="1" /> </linearGradient> </defs> <rect x="0" y="0" width="12" height="12" rx=".44" ry=".44" fill="#464646" /> <rect x=".75" y=".75" width="10.5" height="10.5" rx=".211" ry=".211" fill="#eaeaea" /> <g fill="#1b1b1"> <circle cx="1.767" cy="1.7916" r=".37" /> <circle cx="10.161" cy="1.7916" r=".37" /> <circle cx="10.161" cy="10.197" r=".37" /> <circle cx="1.767" cy="10.197" r=".37" /> </g> <g fill="#eaeaea"> <path d="m-0.3538 1.4672c-0.058299 0-0.10523 0.0469-0.10523 0.10522v0.38698h-2.1504c-0.1166 0-0.21045 0.0938-0.21045 0.21045v0.50721c0 0.1166 0.093855 0.21045 0.21045 0.21045h2.1504v0.40101c0 0.0583 0.046928 0.10528 0.10523 0.10528h0.35723v-1.9266z" /> <path d="m-0.35376 8.6067c-0.058299 0-0.10523 0.0469-0.10523 0.10523v0.38697h-2.1504c-0.1166 0-0.21045 0.0939-0.21045 0.21045v0.50721c0 0.1166 0.093855 0.21046 0.21045 0.21046h2.1504v0.401c0 0.0583 0.046928 0.10528 0.10523 0.10528h0.35723v-1.9266z" /> <path d="m12.354 1.4672c0.0583 0 0.10522 0.0469 0.10523 0.10522v0.38698h2.1504c0.1166 0 0.21045 0.0938 0.21045 0.21045v0.50721c0 0.1166-0.09385 0.21045-0.21045 0.21045h-2.1504v0.40101c0 0.0583-0.04693 0.10528-0.10523 0.10528h-0.35723v-1.9266z" /> <path d="m12.354 8.6067c0.0583 0 0.10523 0.0469 0.10523 0.10522v0.38698h2.1504c0.1166 0 0.21045 0.0938 0.21045 0.21045v0.50721c0 0.1166-0.09386 0.21045-0.21045 0.21045h-2.1504v0.40101c0 0.0583-0.04693 0.10528-0.10523 0.10528h-0.35723v-1.9266z" /> </g> <g> <circle class="button-contour" cx="6" cy="6" r="3.822" fill="url(#a)" /> <circle cx="6" cy="6" r="2.9" fill="${color}" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08" /> </g> </svg> `; } }
- Vedi demo →
Puoi fare clic su ciascuno dei pulsanti e vedere come reagiscono. Quello rosso ha anche alcuni listener di eventi (definiti in index.html ), quindi quando fai clic su di esso dovresti vedere alcuni messaggi scritti sulla console. Ma aspetta, e se invece volessi usare la tastiera?
Rendere il componente accessibile e ottimizzato per i dispositivi mobili
Evviva! Abbiamo creato un componente pulsante riutilizzabile con SVG e lit-element
!
Prima di concludere il nostro lavoro, ci sono alcuni problemi che dovremmo considerare. Innanzitutto, il pulsante non è accessibile alle persone che utilizzano la tastiera. Inoltre, il comportamento sui dispositivi mobili è incoerente: i pulsanti appaiono premuti quando tieni premuto il dito su di essi, ma gli eventi JavaScript non vengono attivati se tieni premuto il dito per più di un secondo.
Iniziamo affrontando il problema della tastiera. Potremmo rendere il pulsante accessibile dalla tastiera aggiungendo un attributo tabindex all'elemento svg, rendendolo attivabile. Un'alternativa migliore, secondo me, è semplicemente avvolgere il pulsante con un elemento <button>
standard. Utilizzando l'elemento standard, lo facciamo anche giocare bene con lettori di schermo e altre tecnologie assistive.
Questo approccio ha uno svantaggio, come puoi vedere di seguito:
L'elemento <button>
viene fornito con uno stile integrato. Questo potrebbe essere facilmente risolto applicando alcuni CSS per rimuovere questi stili:
button { border: none; background: none; padding: 0; margin: 0; text-decoration: none; -webkit-appearance: none; -moz-appearance: none; } button:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; }
Si noti che abbiamo anche sostituito il selettore che inverte la griglia del contorno dei pulsanti, utilizzando button:active
al posto di svg:active
. Ciò garantisce che lo stile del pulsante premuto si applichi ogni volta che viene premuto l'elemento <button>
effettivo, indipendentemente dal dispositivo di input utilizzato.
Possiamo anche rendere il nostro componente più intuitivo per la lettura dello schermo aggiungendo un attributo aria-label
che include il colore del pulsante:
<button aria-label="${color} pushbutton">
C'è ancora un'altra cosa da affrontare: gli eventi "pressione del pulsante" e "rilascio del pulsante". Idealmente, vogliamo attivarli in base alla pseudo-classe CSS :active del pulsante, proprio come abbiamo fatto nel CSS sopra. In altre parole, vorremmo attivare l'evento "pressione del pulsante" ogni volta che il pulsante diventa :active
e l'evento "rilascio del pulsante" attivarsi ogni volta che è :not(:active)
.
Ma come ascolti una pseudo-classe CSS da Javascript?
Si scopre che non è così semplice. Ho fatto questa domanda alla comunità JavaScript Israel e alla fine ho tirato fuori un'idea che ha funzionato dal thread infinito: usa il selettore :active
per attivare un'animazione CSS super breve, e poi posso ascoltarla da JavaScript usando animationstart
evento.
Un rapido esperimento CodePen ha dimostrato che funziona davvero in modo affidabile. Per quanto mi piacesse la raffinatezza di questa idea, ho deciso di scegliere una soluzione diversa e più semplice. L'evento animationstart
non è disponibile su Edge e iOS Safari e l'attivazione di un'animazione CSS solo per rilevare la modifica dello stato del pulsante non sembra il modo corretto di fare le cose.
Invece, aggiungeremo tre coppie di listener di eventi all'elemento <button>
: mousedown/mouseup per il mouse, touchstart/touchend per dispositivi mobili e keyup/keydown per la tastiera. Non è la soluzione più elegante, secondo me, ma fa il trucco e funziona su tutti i browser.
<button aria-label="${color} pushbutton" @mousedown=${this.down} @mouseup=${this.up} @touchstart=${this.down} @touchend=${this.up} @keydown=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.down()} @keyup=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.up()} >
Dove SPACE_KEY
è una costante uguale a 32 e up
/ down
sono due metodi di classe che inviano gli eventi di pressione del button-press
button-release
:
@property() pressed = false; private down() { if (!this.pressed) { this.pressed = true; this.dispatchEvent(new Event('button-press')); } } private up() { if (this.pressed) { this.pressed = false; this.dispatchEvent(new Event('button-release')); } }
- Puoi trovare il codice sorgente completo qui.
Ce l'abbiamo fatta!
È stato un viaggio piuttosto lungo che è iniziato con la delineazione dei requisiti e il disegno dell'illustrazione per il pulsante in Inkscape, è passato attraverso la conversione del nostro file SVG in un componente Web riutilizzabile utilizzando lit-element
e, dopo esserci assicurati che fosse accessibile e ottimizzato per i dispositivi mobili, abbiamo finito con quasi 100 righe di codice di un delizioso componente pulsante virtuale.
Questo pulsante è solo un singolo componente in una libreria open source di componenti elettronici virtuali che sto costruendo. Sei invitato a sbirciare il codice sorgente o a dare un'occhiata allo Storybook online dove puoi vedere e interagire con tutti i componenti disponibili.
E infine, se sei interessato ad Arduino, dai un'occhiata al corso di programmazione Simon for Arduino che sto attualmente costruendo, dove puoi anche vedere il pulsante in azione.
Alla prossima volta, allora!