davide 7f52d81bbf chore: smetti di tracciare dev-dist (build artifact PWA, già in .gitignore)
I file del service worker generati da vite-plugin-pwa in modalità dev erano
committati nonostante dev-dist sia nel .gitignore. Vengono rigenerati a ogni
`npm run dev`, quindi non vanno versionati.
2026-06-21 18:37:36 +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 i video della cartella spot/ (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 attiva/disattiva la proiezione degli spot sul display. Quando la modalità è attiva il controller resta pienamente operativo ma è chiaramente evidenziato: compare un banner MODALITÀ TIME OUT ATTIVA e il pulsante diventa arancione e pulsante. Ripremendolo si esce e il display torna al punteggio.

I video da proiettare vanno messi in una cartella spot/ nella root del progetto (non versionata). Comportamento:

  • un solo video .mp4 → riprodotto in loop continuo;
  • più video .mp4 → riprodotti in sequenza in ordine alfabetico, poi si riparte dal primo;
  • cartella vuota o assente → il display mostra un overlay nero con la scritta TIME OUT.

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 nel volume Docker segnapunti-state e sopravvive ai riavvii del container.

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%