Files
loto/docs/project-overview-pdr.md
tiennm99 574c22ddc1 refactor: rewrite from Next.js + React to SvelteKit + Svelte 5
Full stack swap to enable future extension (more pages / load functions /
backend) while keeping JSDoc-only code style.

Stack:
- SvelteKit 2 + adapter-static
- Svelte 5 runes ($state, $derived, $effect, $props)
- Vite 7 + @sveltejs/vite-plugin-svelte 6
- Tailwind 4 (Vite plugin)
- ESLint 9 (flat) + eslint-plugin-svelte
- Pure JS + JSDoc, no TypeScript

Source moves:
- app/page.jsx              → src/routes/+page.svelte
- app/master/page.jsx       → src/routes/master/+page.svelte
- app/layout.jsx            → src/routes/+layout.svelte (+ +layout.js)
- components/player-board.jsx → src/lib/PlayerBoard.svelte
- lib/game-logic.js         → src/lib/game-logic.js (verbatim)
- next.config.mjs           → svelte.config.js + vite.config.js
- app/globals.css           → src/app.css
- (new)                     → src/app.html

Behavior preserved: PlayerBoard with bingo "Kinh!" popup + waiting "Chờ X"
toast, master 9x10 tracking board with shuffled draw, host's own player
card via storagePrefix="loto_master_card", localStorage prefix model
(loto_*, loto_master, loto_master_card_*), basePath dual mode (CF default
empty, BUILD_PROFILE=gh → /loto, codeserver dev → /absproxy/{port}).

A11y kept from prior hardening: role-correct buttons, aria-pressed on
cells, role=dialog modal with Escape, role=status toast.

Plans: ts-to-jsdoc plan marked completed; sveltekit-refactor plan tracks
the work above. Docs under ./docs/ rewritten by docs-manager subagent to
match the SvelteKit terminology.
2026-04-26 21:03:41 +07:00

3.4 KiB
Raw Permalink Blame History

Lô Tô — Project Overview & PDR

What is Lô Tô?

Lô tô is a traditional Vietnamese bingo game. The app replicates the game digitally for players to generate their own 9×9 number cards and mark cells as a host calls numbers from 190. First player to complete an entire row wins and shouts "Kinh!" (the game's victory cheer).

The inspiration comes from TN1 class reunions (20142017) where players often ran build of physical bingo cards.

Core Mechanics

  • Players: Generate a randomized 9×9 card with 45 numbers (5 per row, weighted distribution across columns 190). Click cells to mark them as numbers are called.
  • Host: Draws numbers randomly from a shuffled 190 deck, displays the current number on a large board, and tracks which numbers have been called.
  • Bingo: When a row is complete, the player's card triggers a celebration popup showing "Kinh!" with confetti emojis. Before bingo, toast notifications prompt "Chờ X" (waiting for X) when only one number remains in a row.

Tech Stack

  • Framework: SvelteKit 2 with Svelte 5 (runes mode)
  • Runtime: Svelte 5 runes ($state, $derived, $effect, $props)
  • Styling: Tailwind CSS 4 (utility-first, animations)
  • Persistence: localStorage (no backend)
  • Deploy: Cloudflare Pages (root domain), GitHub Pages fallback (/loto)
  • Dev Profile: code-server compatible via /absproxy/{port} basePath + HMR proxy config

Architecture Overview

Two public pages:

  1. / — Player page. Generate a card, click cells to mark them, see bingo popup and waiting toasts.
  2. /master — Host page. Control number drawing, view 9×10 master board (tracking called vs uncalled), and host's own player card.

State is entirely client-side. Each page/card instance uses a unique localStorage prefix (e.g., "loto" for player, "loto_master" for host's state, "loto_master_card" for host's player card).

Deployment

  • Production: GitHub Pages auto-deploys from master branch via .github/workflows/deploy.yml. App is served at /loto basePath.
  • Development: npm run dev (local), npm run dev:codeserver (code-server via proxy).
  • Build: npm run build generates static export to build/ directory.

Key Acceptance Criteria

  • Player can generate a new 9×9 card with valid number distribution.
  • Player can click cells to toggle crossed state.
  • Bingo popup triggers when row is complete, shows row number and "Kinh!" message.
  • Toast notifications show "Chờ X" before bingo (one number remaining).
  • Host can draw numbers and see them on the 9×10 master board.
  • Host has their own player card (isolated by localStorage prefix).
  • Offline persistence via localStorage (grid and crossed state).
  • Dark mode support (Tailwind dark classes).
  • Mobile-responsive (base + sm breakpoints).
  • HMR works on code-server via proxy.

Visual Language

  • Player gradient: indigo → purple (primary brand, positive action).
  • Host gradient: orange → red (higher-stakes, control action).
  • Completed rows: emerald (success indicator).
  • Waiting toast: amber (attention, ephemeral).
  • Emojis: 🎉 🎊 🥳 ❤️ (celebration, joy).

Future Considerations (Not Committed)

  • Undo last crossed cell
  • Sound effects on bingo
  • Theme switcher
  • PWA install
  • Multiplayer sync (real-time via WebSocket)
  • i18n beyond Vietnamese

Last reviewed: 2026-04-26