diff --git a/web/README.md b/web/README.md index 189bee4..ec53be1 100644 --- a/web/README.md +++ b/web/README.md @@ -2,8 +2,9 @@ Bàn số của trò chơi "Lô tô" — SvelteKit app. -Two routes: `/` for players, `/master` for the host (quản trò) — calls -numbers, shows a tracking board, and has its own player card to play along. +Single page (`/`). The host enables "Chế độ quản trò" in settings to +reveal the master panel inline below their player card; called numbers +get spoken aloud in Vietnamese using bundled MP3 clips (no runtime TTS). See `docs/` for architecture, code standards, and deployment. @@ -36,3 +37,18 @@ npm run build:gh # /loto basePath, for tiennm99.github.io/loto manual expor Static export to `build/`. Deployed to Cloudflare Pages from `main` (set up via the CF dashboard — see `docs/deployment-guide.md`). + +## Regenerating audio + +Vietnamese voice clips live in `static/audio/{voiceId}/`. Generated +once with [edge-tts](https://github.com/rany2/edge-tts) (free, no API +key) — runtime never calls TTS. To regenerate (e.g., to add a new voice +that Microsoft ships, or to change wording): + +```bash +pip install edge-tts +python3 scripts/generate-audio.py +``` + +The script auto-discovers every `vi-*` voice and writes a manifest the +app reads on next reload. diff --git a/web/docs/codebase-summary.md b/web/docs/codebase-summary.md index 953e3ea..3c759eb 100644 --- a/web/docs/codebase-summary.md +++ b/web/docs/codebase-summary.md @@ -12,7 +12,7 @@ | File | Purpose | |------|---------| | `src/lib/PlayerBoard.svelte` | Reusable player card (9×9 grid rendered as 3 stacked 3×9 mini-cards: Tân Tân / An khang thịnh vượng / Tân Tân tốt nhất). Tall (3:5 on mobile; wider on sm+) cells with condensed bold black numbers (`tan-tan-num` font stack), white number cells, purple empty cells by default. Handles crossed state, bingo popup, "Chờ X" toast. Two header actions: "Tạo bảng mới" (regenerate grid) and "Xoá đánh dấu" (clear all marks, keep grid — only shown when a grid exists). Accepts `storagePrefix` prop for multi-card isolation. Empty cells use `--empty-cell-bg` CSS var from settings store. | -| `src/lib/SettingsButton.svelte` | Gear icon + modal. 4 fieldsets: Giao diện (theme auto/light/dark), Chế độ quản trò (master mode toggle), Tự động xổ (auto-call + speed 1–10s), Màu ô trống (10 Excel color swatches). Reset-to-default button. Mounted on `/`. | +| `src/lib/SettingsButton.svelte` | Gear icon + modal. 5 fieldsets: Giao diện (theme auto/light/dark), Chế độ quản trò (master mode toggle), Tự động xổ (auto-call + speed 1–10s), Âm thanh (voice toggles for master + player + voice picker from manifest), Màu ô trống (10 Excel color swatches). Reset-to-default button. Mounted on `/`. | | `src/lib/MasterPanel.svelte` | Host controls. New game / draw, "Số vừa xổ" hero token, "Thứ tự đã xổ" history list, 11×9 last-digit-aligned tracking grid (with circular tokens + draw-order overlay). No host's own player card (the player already has one above). "Xổ số" / "Bắt đầu / Dừng" button bound to auto-call. Mounted conditionally on `/` when `settings.masterMode === true`. | | `src/lib/PageFooter.svelte` | Footer with tagline ("Made by miti99 with ❤️ SVG icon") + link. Mounted on `/`. | @@ -20,7 +20,10 @@ | File | Purpose | |------|---------| | `src/lib/game-logic.js` | Stateless utilities: generateGrid (constraint-aware picker — exact 5 per row & per col, ascending-sorted columns, soft "no 3 consecutive filled cols per row" via rejection sampling), saveGrid, loadGrid, saveCrossedState, loadCrossedState, isRowComplete, getWaitingNumber. | -| `src/lib/settings-store.svelte.js` | Reactive global UI settings via Svelte 5 runes. Stores 5 keys: `theme` (enum: "auto" / "light" / "dark"), `masterMode` (bool), `autoCallEnabled` (bool), `autoCallSpeed` (1–10), `emptyCellColor` (hex). Persisted to localStorage `loto_settings`. Pushes values to CSS vars and `` on `:root`. Per-key validators preserve old data. | +| `src/lib/vietnamese-number.js` | `numberToVietnamese(n)` — pure utility mapping 0..90 to spoken Vietnamese, with tonal exceptions (15 → "mười lăm", 21 → "hai mươi mốt", 25 → "hai mươi lăm"). Out-of-range falls back to `String(n)`. | +| `src/lib/voice.js` | Bundled-MP3 playback. Exports `playNumber(n)`, `playWaiting(n)` (sequences cho + N), `playBingo()`, `cancelPlayback()`. Lazy `