Files
loto/web
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>tiennm99
fac70e53e2 chore(deps): bump the minor-and-patch group with 13 updates (#28)
Bumps the minor-and-patch group with 13 updates:

| Package | From | To |
| --- | --- | --- |
| [@fontsource/roboto-condensed](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/roboto-condensed) | `5.2.8` | `5.3.0` |
| [@sveltejs/kit](https://github.com/sveltejs/kit/tree/HEAD/packages/kit) | `2.61.1` | `2.70.1` |
| [@sveltejs/vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte/tree/HEAD/packages/vite-plugin-svelte) | `7.1.2` | `7.2.0` |
| [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.0` | `4.3.3` |
| [eslint](https://github.com/eslint/eslint) | `10.4.0` | `10.7.0` |
| [eslint-plugin-svelte](https://github.com/sveltejs/eslint-plugin-svelte/tree/HEAD/packages/eslint-plugin-svelte) | `3.17.1` | `3.22.0` |
| [globals](https://github.com/sindresorhus/globals) | `17.6.0` | `17.7.0` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.9.0` | `20.11.0` |
| [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) | `5.55.9` | `5.56.7` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.0` | `4.3.3` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.16` | `8.1.5` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.7` | `4.1.10` |
| [lightningcss-linux-x64-gnu](https://github.com/parcel-bundler/lightningcss) | `1.32.0` | `1.33.0` |


Updates `@fontsource/roboto-condensed` from 5.2.8 to 5.3.0
- [Changelog](https://github.com/fontsource/font-files/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/roboto-condensed)

Updates `@sveltejs/kit` from 2.61.1 to 2.70.1
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/version-3/packages/kit/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/kit@2.70.1/packages/kit)

Updates `@sveltejs/vite-plugin-svelte` from 7.1.2 to 7.2.0
- [Release notes](https://github.com/sveltejs/vite-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/vite-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/vite-plugin-svelte/commits/@sveltejs/vite-plugin-svelte@7.2.0/packages/vite-plugin-svelte)

Updates `@tailwindcss/vite` from 4.3.0 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/@tailwindcss-vite)

Updates `eslint` from 10.4.0 to 10.7.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.4.0...v10.7.0)

Updates `eslint-plugin-svelte` from 3.17.1 to 3.22.0
- [Release notes](https://github.com/sveltejs/eslint-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/eslint-plugin-svelte/commits/eslint-plugin-svelte@3.22.0/packages/eslint-plugin-svelte)

Updates `globals` from 17.6.0 to 17.7.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0)

Updates `happy-dom` from 20.9.0 to 20.11.0
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.9.0...v20.11.0)

Updates `svelte` from 5.55.9 to 5.56.7
- [Release notes](https://github.com/sveltejs/svelte/releases)
- [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.56.7/packages/svelte)

Updates `tailwindcss` from 4.3.0 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/tailwindcss)

Updates `vite` from 8.0.16 to 8.1.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.1.5/packages/vite)

Updates `vitest` from 4.1.7 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest)

Updates `lightningcss-linux-x64-gnu` from 1.32.0 to 1.33.0
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.32.0...v1.33.0)

---
updated-dependencies:
- dependency-name: "@fontsource/roboto-condensed"
  dependency-version: 5.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@sveltejs/kit"
  dependency-version: 2.70.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@sveltejs/vite-plugin-svelte"
  dependency-version: 7.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: eslint
  dependency-version: 10.7.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: eslint-plugin-svelte
  dependency-version: 3.22.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: globals
  dependency-version: 17.7.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: happy-dom
  dependency-version: 20.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: svelte
  dependency-version: 5.56.7
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: tailwindcss
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: vite
  dependency-version: 8.1.5
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: vitest
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: lightningcss-linux-x64-gnu
  dependency-version: 1.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: tiennm99 <tiennm99@outlook.com>
2026-07-21 23:13:56 +07:00
..
2026-04-26 19:16:46 +07:00
2026-04-29 21:33:25 +07:00
2026-05-13 10:21:00 +07:00

Lô Tô

Web version of Lô tô hội chợ — Vietnamese fairground bingo. Built with SvelteKit (static export). The caller draws numbers one at a time; a host panel manages the game and called numbers are announced aloud in Vietnamese using bundled audio clips. No runtime TTS or server required.

Live: tiennm99.github.io/loto

Android port: tiennm99/loto-android


Features

  • Number board — 190 grid; called numbers highlight as they are drawn
  • Host panel — enable "Chế độ quản trò" (host mode) in settings to reveal the master draw panel inline below your player card
  • Vietnamese voice callouts — pre-generated MP3 clips for every number using Microsoft Edge TTS (edge-tts); multiple voices selectable in settings; no API key or internet connection needed at runtime
  • Auto-cross player card — optional automatic crossing of numbers on the player's bingo card as they are called
  • Auto-countdown — configurable delay between number draws for unattended calling
  • PWA — installable as a progressive web app; works offline after first load
  • Static export — no server; deploys to any static host or GitHub Pages

Requirements

Node.js 18+ and pnpm.


Quick Start

git clone https://github.com/tiennm99/loto
cd loto
pnpm install
pnpm dev        # dev server at http://localhost:5173

Commands

Command Description
pnpm dev Start development server
pnpm build Production build (root base path)
pnpm build:gh Production build for GitHub Pages (/loto base path)
pnpm preview Preview production build locally
pnpm test Run unit tests
pnpm lint ESLint check

Configuration

Copy .env.example to .env.local and set:

Variable Description
CODESERVER_HOST Hostname for code-server reverse-proxy dev (optional)
CODESERVER_PORT Port for code-server proxy (optional)

When running inside code-server use pnpm dev:codeserver and open https://<CODESERVER_HOST>/absproxy/<CODESERVER_PORT>/ (use /absproxy/, not /proxy/ — the latter strips the path prefix and breaks SvelteKit routing).


Architecture

Single-page SvelteKit app, statically exported. No backend.

src/
├── routes/          # Single route: /
├── lib/
│   ├── game-logic.js          # Draw state, number pool, called-number tracking
│   ├── master-store.svelte.js # Host panel state (Svelte 5 runes store)
│   ├── settings-store.svelte.js
│   ├── voice.js               # Audio manifest loader + clip player
│   ├── player-auto-cross.js   # Auto-cross logic
│   ├── MasterPanel.svelte     # Host draw UI
│   ├── PlayerBoard.svelte     # Bingo card + number grid
│   └── AutoCountdown.svelte   # Countdown timer between draws
static/
└── audio/{voiceId}/   # Pre-generated MP3 clips (one per number per voice)
scripts/
└── generate-audio.py  # Regenerates audio clips via edge-tts

Game state lives entirely in Svelte 5 rune stores; no server round-trips. Audio manifest is generated once at build prep time — the app reads a JSON manifest on load and plays the appropriate clip for each drawn number.


Regenerating Audio

Voice clips in static/audio/ were generated with edge-tts (free, no API key). To regenerate (e.g. to add a new Microsoft vi-* voice):

pip install edge-tts
python3 scripts/generate-audio.py

The script auto-discovers all available vi-* voices and writes an updated manifest.


Deployment

Deployed to GitHub Pages via .github/workflows/deploy-github-pages.yml on push to main. Build command: pnpm build:gh (sets /loto base path). Static output in build/.


License

Apache 2.0