mirror of
https://github.com/tiennm99/loto.git
synced 2026-10-20 02:17:46 +00:00
Settings expansion: 4 new keys (theme auto/light/dark, masterMode, autoCallEnabled, autoCallSpeed 1-10) with per-key validators that preserve old saved data. Default empty-cell color flipped from Tân Tân blue to Excel Standard Purple #7030A0; preset palette swapped to Office's 10 standard colors (5x2 grid). 15 new tests, 53 total. Theme system: Tailwind v4 @variant dark (.dark *); applyTheme() toggles <html class="dark"> based on settings.theme; auto mode mirrors prefers-color-scheme via matchMedia listener (cleanly torn down when switching modes). Existing dark-mode CSS converted from @media to :where(.dark) selectors. Mobile fit: PlayerBoard cells aspect-square on mobile, sm:aspect-[3/5] desktop. Number text scales text-base sm:text-2xl md:text-3xl. Page padding tightened (px-2 py-4 sm:px-3 sm:py-12). Container bumped max-w-lg to max-w-2xl. Header / footer: removed instructions toggle and "Trang quản trò" link from player page. New PageFooter.svelte (tagline + Made by miti99 with [SVG heart] link); also duplicated in PlayerBoard's closing section-label band per request. Heart is inline SVG (red), not emoji. Master mode: extracted everything from /master route into reusable MasterPanel.svelte. /master route slimmed to header + MasterPanel + footer. / mounts MasterPanel conditionally when settings.masterMode. Storage prefixes unchanged. Master tracking grid removed: per request, the 11x9 ones-digit master board is gone. Host still gets controls, "Số vừa xổ" hero, draw history list, and their own player card. Player card is enough. Auto-call: single $effect lifecycle keyed on (autoRunning, settings.autoCallSpeed, settings.autoCallEnabled). Setup / clear setInterval cleanly across speed changes, master-mode toggle off, component unmount, and "user disabled auto" mid-run. Button toggles "Xổ số" -> "Bắt đầu / Dừng". Speed slider in Settings (only visible when master mode is on). aria-label / aria-valuetext on slider. Code-review nice-to-fixes applied: folded the two MasterPanel $effects into one, removed muddled onkeydown on the SettingsButton modal backdrop, added slider a11y attrs. Docs: PDR / codebase-summary / system-architecture / development-roadmap / code-standards all synced to the new state.
6.6 KiB
6.6 KiB
Lô Tô — Project Overview & PDR
What is Lô Tô?
This app replicates Lô tô hội chợ (Vietnamese fairground / carnival lô tô), specifically the Tân Tân style most familiar from southern Vietnam class reunions and Tết gatherings. Inspiration: TN1 class reunions (2014–2017) where players ran build of physical bingo cards.
It is not the British Bingo 90 / Italian Tombola 3×9 / 15-number ticket. That format is intentionally out of scope.
Game Variant & Scope
In scope (Lô tô hội chợ Tân Tân)
- Card: 9 rows × 9 columns. Exactly 5 numbers per row AND exactly 5 numbers per column (45 numbers per card; 36 blanks).
- Visual layout: card displayed as 3 stacked 3×9 mini-cards with
traditional separator labels — Tân Tân, An khang thịnh vượng,
Tân Tân tốt nhất — matching the physical Tân Tân BAMBOORAFT paper
sheet (tall non-square cells on mobile, wider on sm+; condensed bold black numbers on white,
purple empty-cell background by default — Excel Standard Purple
#7030A0). - Column ranges: col 0 = 1–9, col 1 = 10–19, …, col 7 = 70–79, col 8 = 80–90.
- Within a column: numbers placed top-to-bottom in ascending order.
- Number pool: 1–90.
- Win condition: 1 row complete = "Kinh!". After winning, the player may keep playing further rows (game does not end).
- Waiting state: when a row needs only 1 number, app announces "Chờ N".
- Host (quản trò) draws numbers from a shuffled 1–90 deck, tracks them on a master board with circular tokens (pink ring for 1–49, green for 50–90, cream fill on called, dim on uncalled, red ring + scale on the most recent draw), and may also play their own card.
- Settings: gear icon in headers opens a modal with 4 fieldsets:
- Giao diện: theme switcher (auto / light / dark; auto mirrors OS pref)
- Chế độ quản trò: toggle to show MasterPanel on
/ - Tự động xổ: enable auto-call; speed slider (1–10 seconds)
- Màu ô trống: color picker + 10 Excel preset swatches
Persisted to
loto_settings.
Out of scope
- 3×9 / 15-number Bingo 90 / Tombola tickets (European format).
- Two-line and full-house win tiers.
- Custom number ranges (1–75 American bingo, etc.).
- Stake / pot / payout logic.
- Multiplayer real-time sync.
Core Mechanics
- Players: Generate a randomized 9×9 card. The generator guarantees 5 per row and 5 per column (constraint-aware picker, not loose weighted random). Numbers within each column ascend top-to-bottom. Click cells to mark them.
- Host: Draws numbers randomly from a shuffled 1–90 deck, shows the current number, and tracks all called numbers on an 11×9 master board aligned by ones-digit (col 0 = 1–9, col 8 = 80–90; 1 / 11 / 21 / … / 81 share row 1, etc.). Each called cell shows its 1-based draw order as a small superscript so the host can quickly verify a "Kinh!" claim by reading the order across the winning row.
- Bingo: When a row is complete, a celebration popup shows "Kinh!" with confetti. Player keeps playing afterward — no game-end gate.
- Waiting: "Chờ N" toast when a row is one number away.
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:
/— Player page. Generate a card, click cells to mark them, see bingo popup and waiting toasts./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: Cloudflare Pages at
loto.miti99.com(canonical, CF dashboard, root basePath). GitHub Pages serves only a redirect to the canonical URL via.github/workflows/deploy-github-pages.yml. - Development:
npm run dev(local),npm run dev:codeserver(code-server via proxy). - Build:
npm run buildgenerates static export tobuild/directory.
Key Acceptance Criteria
- Player card is 9×9 with exactly 5 per row and 5 per column.
- Numbers within each column are ascending top-to-bottom.
- Player can click cells to toggle crossed state.
- Bingo popup triggers when row is complete, shows row number and "Kinh!" message.
- Player may keep marking after a Kinh — no game-end lock.
- Toast notifications show "Chờ X" before bingo (one number remaining).
- Host can draw numbers and see them on the 11×9 last-digit-aligned master board.
- Master board shows draw order on each called cell for Kinh verification.
- 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.
- Player card rendered as 3 stacked Tân Tân mini-cards with separator labels.
- Settings modal with 4 fieldsets (theme, master mode, auto-call, color); applies to both grids; persisted.
- Theme switcher (auto / light / dark) with explicit dark class selector on
<html>. - Master mode toggle to show MasterPanel on player page.
- Auto-call timer (1–10s speed) with start/stop button.
- Mobile-responsive layout (aspect-square sm:aspect-[3/5] cells, text scaling).
- MasterPanel extracted; mounted conditionally on
/and directly on/master. - PageFooter with tagline + link on both pages.
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-27 (scope locked: Lô tô hội chợ Tân Tân + theme/master/auto-call) Last synced: 2026-04-27 (6-phase refactor)