davide 0b7cbd00f6 test(component): porta ControllerPage e DisplayPage al 100% di statement coverage
Aggiunge 65 test per ControllerPage.vue (layout esteso/landscape,
popup automatico di set vinto con soglia decisiva, modal di
configurazione, validazione completa dei cambi giocatore, modal
time out con selezione video/ticker/countdown, cleanup dei listener)
e 35 per DisplayPage.vue (countdown overlay, riallineamento video su
riconnessione, fallback muto per autoplay bloccato, selezione voce
per la sintesi vocale). Nessun bug riscontrato nei componenti.
2026-07-03 12:00:45 +02:00

Segnapunti

Version Node Docker License

Segnapunti digitale in tempo reale per partite di pallavolo. Un server centrale gestisce lo stato della partita; un display mostra il tabellone pubblico e un controller (smartphone o tablet) permette all'operatore di gestire punti, formazioni e cambi.


Indice


Architettura

Controller (smartphone)  ──WebSocket──┐
                                      ├── Server Node.js ── gameState.js
Display (schermo)        ──WebSocket──┘         │
                                                └── .segnapunti/state.json

Il server è l'unica fonte di verità. Ogni azione del controller viene elaborata e trasmessa in broadcast a tutti i client connessi. Lo stato viene salvato su disco ad ogni azione e ricaricato all'avvio, sopravvivendo ai riavvii del server.

Percorso Ruolo
http://<host>:3000/display Tabellone pubblico — sola lettura
http://<host>:3000/controller Pannello operatore — gestione partita
ws://<host>:3000/ws WebSocket endpoint

Guida utente

Scenario tipico: schermo fisso + smartphone operatore

1. Avvia il server

docker compose up -d

All'avvio il terminale mostra gli URL locali e di rete.

2. Apri il display

Collega il PC/server allo schermo via HDMI e apri il browser a schermo intero:

http://localhost:3000/display

Se il display è su un dispositivo separato nella stessa rete:

http://<IP-del-server>:3000/display

Trovare l'IP: il server lo stampa all'avvio. In alternativa usa ip a su Linux.

3. Apri il controller sullo smartphone

Connetti il telefono alla stessa rete Wi-Fi e apri:

http://<IP-del-server>:3000/controller

Installazione come app: nel browser tocca "Aggiungi a schermata Home" per avere il controller come icona dedicata.


Funzionalità

Il sistema è composto da due interfacce complementari: il display è in sola lettura e mostra al pubblico lo stato della partita; il controller è il pannello operatore da cui parte ogni azione. Tutto ciò che l'operatore tocca sul controller si riflette istantaneamente sul display via WebSocket.

Display (tabellone pubblico)

Pagina di sola visualizzazione, pensata per uno schermo grande o un proiettore. Mostra:

  • Nomi squadre con indicatore di servizio (l'icona della palla compare accanto alla squadra che sta servendo).
  • Punteggio del set corrente in caratteri molto grandi, leggibili da lontano.
  • Contatore dei set vinti per ciascuna squadra.
  • Striscia storica dei punti del set in corso: una sequenza scorrevole che ricostruisce l'andamento punto su punto.
  • Modalità formazioni: in alternativa al punteggio, mostra le posizioni dei 6 giocatori in campo (numeri di maglia disposti come a referto).
  • Ordine di visualizzazione invertibile: le due squadre possono essere scambiate di lato per rispecchiare l'orientamento reale del campo.
  • Overlay time out / spot: durante un time out copre il tabellone con un countdown e il video scelto dall'operatore, o con la scritta TIME OUT (vedi sotto).
  • Annuncio vocale del punteggio (sintesi vocale del browser), comandato dal controller.
  • Indicatore di connessione: scompare quando tutto è connesso, diventa un punto rosso lampeggiante con scritta Disconnesso in caso di problemi.
  • Fullscreen automatico all'apertura sui dispositivi mobili.

Controller (pannello operatore)

Il controller adatta automaticamente il proprio layout all'orientamento del dispositivo:

  • Verticale (smartphone) — layout compatto: anteprima punteggio toccabile in alto e griglia di pulsanti sotto.
  • Orizzontale (tablet) — layout esteso "da regia": due grandi pannelli squadra affiancati con punteggio, campo e tasto set, più una barra di azioni in basso.

Gestione del punteggio

  • Punto — tocca il punteggio/la card di una squadra per assegnarle +1. Il sistema gestisce automaticamente il cambio palla e la rotazione della squadra che riconquista il servizio.
  • Annulla punto — rimuove l'ultimo punto assegnato, ripristinando anche eventuale rotazione e servizio.
  • Tasti SET — incrementano manualmente il contatore dei set vinti di una squadra (utile per correzioni); il contatore cicla da 0.
  • Dialog automatico SET VINTO / PARTITA FINITA — compare da solo al raggiungimento delle condizioni di vittoria (25 punti, o 15 nel set decisivo, con 2 di scarto). Da qui puoi:
    • VAI AL SET SUCCESSIVO — chiude il set, lo registra come vinto e prepara il set successivo aprendo la configurazione delle formazioni;
    • INDIETRO — annulla l'ultimo punto se il dialog è comparso per errore;
    • a partita conclusa, REFERTO per generare il referto e CHIUDI per tornare al tabellone.

Configurazione partita

Dal pulsante Config si apre una finestra che permette di impostare:

  • Nomi delle squadre (Home e Guest);
  • Modalità partita: 2/3 (al meglio dei 3 set), 3/5 (al meglio dei 5 set) o Amichevole (senza vittoria automatica della partita);
  • Formazioni iniziali: i numeri di maglia dei 6 giocatori in campo per ciascuna squadra, disposti per zona.

Cambi giocatore

Il pulsante Cambi apre, dopo aver scelto la squadra, un dialog con righe IN → OUT. Le sostituzioni vengono validate prima di essere applicate: i numeri devono essere cifre, il giocatore entrante non può essere già in campo, quello uscente deve essere effettivamente in formazione, e nessuno può sostituire sé stesso. Eventuali errori sono segnalati in chiaro.

Servizio e visualizzazione

  • Cambio Palla — assegna manualmente il servizio; disponibile solo a 0-0 (a inizio set).
  • Inverti — scambia il lato delle due squadre sul display.
  • Formazioni / Punteggio — alterna sul display la vista formazioni in campo e la vista punteggio.
  • Striscia ON/OFF — mostra o nasconde lo storico punti del set sul display.
  • Voce — fa annunciare al display il punteggio corrente con la sintesi vocale (es. "15 a 12", "15 pari", "zero a zero").

Time Out e spot pubblicitari

Il pulsante Time Out apre una finestra in cui l'operatore sceglie quale squadra ha chiamato il time out (obbligatorio) e quale video proiettare sul display, scegliendo tra i file della cartella spot/ oppure nessun video (overlay con la scritta TIME OUT). Alla conferma:

  • il display copre il tabellone con un overlay a tutto schermo: countdown in sovraimpressione e video scelto; se non c'è video, o se il video finisce prima del tempo, compare la scritta TIME OUT con il nome della squadra. Nell'ultimo secondo il video sfuma in dissolvenza.
  • il controller resta pienamente operativo: compare un banner TIME OUT con il conto alla rovescia e il pulsante Time Out mostra i secondi rimanenti. Ripremendolo si chiude il time out in anticipo.
  • il server chiude automaticamente il time out dopo 30 secondi, anche se il controller si disconnette o va in standby.

I video da proiettare vanno messi in una cartella spot/ nella root del progetto (non versionata): vengono elencati nella finestra di scelta in ordine alfabetico (solo file .mp4). Se un display si riconnette a metà time out, il video riparte dal punto corretto.

Audio: i video partono con audio, ma il display è in genere uno schermo senza tastiera/mouse e i browser bloccano l'autoplay con suono senza un'interazione dell'utente. In assenza di configurazione il video parte automaticamente muto (il video si vede comunque). Per avere l'audio, avvia il browser del display in modalità kiosk consentendo l'autoplay con suono (es. Chrome con --autoplay-policy=no-user-gesture-required, oppure impostando un'eccezione del sito per audio/video).

Reset e referto

  • Reset — azzera la partita (punteggi, set e formazioni) previa conferma, e riapre subito la configurazione per impostare la partita successiva.
  • Referto — a fine partita, dal dialog PARTITA FINITA, genera un referto di gara stampabile/PDF con i punteggi per set, le formazioni di partenza e l'andamento punto-punto. Funzione prototipale.

Regole pallavolo integrate

Le condizioni di vittoria del set sono applicate automaticamente dal server (è quello che fa comparire il dialog SET VINTO):

Set Condizione di vittoria
Set 14 (modalità 3/5) o 12 (modalità 2/3) Primo a 25 con almeno 2 punti di scarto
Set decisivo (tie-break) Primo a 15 con almeno 2 punti di scarto

La partita è vinta da chi raggiunge 3 set su 5 (modalità 3/5) o 2 set su 3 (modalità 2/3). In modalità Amichevole non c'è vittoria automatica della partita: si continua a giocare set senza che compaia PARTITA FINITA.


Deploy con Docker

Prima installazione

docker compose up -d

Lo stato viene salvato nella cartella ./.segnapunti montata come volume nel container e sopravvive ai riavvii.

Video spot in Docker: la cartella spot/ non è inclusa nell'immagine. Per usare i video del time out aggiungi un volume in docker-compose.yml: ./spot:/app/spot.

Aggiornamento a nuova versione

docker compose pull && docker compose up -d

Build e pubblicazione immagine

docker build \
  -t santantonio.sytes.net/attilio/segnapunti:2.0.0 \
  -t santantonio.sytes.net/attilio/segnapunti:latest .

docker push santantonio.sytes.net/attilio/segnapunti:2.0.0
docker push santantonio.sytes.net/attilio/segnapunti:latest

Sviluppo

Requisiti

Strumento Versione minima
Node.js >= 18
npm >= 9

Avvio

npm install
npm run dev
URL Interfaccia
http://localhost:5173/display Display
http://localhost:5173/controller Controller

Lo stato viene salvato in .segnapunti/state.json anche in modalità dev.

Comandi disponibili

Comando Descrizione
npm run dev Dev server con hot reload
npm run build Build di produzione in dist/
npm run serve Build + avvio server produzione

Test

Comando Descrizione
npm run test:unit Unit + integration (Vitest)
npm run test:component Componenti Vue (Happy-DOM)
npm run test:stress Load test WebSocket (50+ client)
npm run test:all Tutti i test tranne E2E
npm run test:ui Vitest con interfaccia grafica
npm run test:e2e Playwright — Chromium, Firefox, Mobile Chrome

Le suite Vitest coprono la logica di gioco (gameState, inclusa formInizio), il protocollo e il routing del server, la persistenza, il client WebSocket (wsMixin), i componenti Vue e la generazione del referto.

I test E2E richiedono il server in esecuzione (npm run serve) e i browser Playwright installati:

npx playwright install chromium firefox

Changelog

Vedere CHANGELOG.md per la storia delle versioni.

S
Description
Segnapunti digitale per partite di pallavolo. Tabellone pubblico e controller per smartphone sincronizzati in tempo reale via WebSocket. Deploy via Docker.
Readme 3.9 MiB
Release 2.1.0 Latest
2026-07-08 10:29:21 +02:00
Languages
JavaScript 81.6%
Vue 16%
CSS 2%
HTML 0.2%
Dockerfile 0.2%