tiennm99 4d10f0a879 feat(audio): play sound effects and background music
Nine one-shot effects on the play flow and one ambient loop, both on by
default and mutable independently from every header.

lib/audio.js owns the single AudioContext, the decoded-buffer cache and
the two preferences. Those preferences live in module variables mirrored
into localStorage rather than read back from it: a private window throws
on both read and write, and re-reading before each sound turned a mute
that could not be persisted into a mute that never happened.

The gesture listeners stay registered for the life of the page. They
open the context on the first interaction, but they are also the only
thing that resumes one the browser suspended -- removing them after the
first gesture left the game silent for the rest of a session once a
phone had been locked.

MusicPlayer mounts in the root layout, not in a page, so walking from
the menu into a round does not tear down and restart the loop. It loops
a decoded buffer rather than an <audio> element, which returns to sample
zero and so has no seam.

The game header has no room below sm for a second pair of 44px cells
beside ThemeToggle's three, so sound collapses there to one
mute-everything switch. Both variants stay mounted and subscribe to the
preferences, or crossing the breakpoint would reveal a control showing
its mount-time state.

Assets are CC0 throughout, from Kenney and OpenGameArt, with per-file
provenance in public/audio/SOURCES.md. The loop was chosen on a
measurement: its first and last 250ms sit within 0.5dB, so the loop
point carries continuous energy.
2026-09-09 11:14:47 +07:00
2026-09-03 15:17:42 +07:00
2026-09-03 15:17:42 +07:00
2025-08-07 13:08:06 +07:00
2025-08-07 12:27:13 +07:00
2025-08-04 23:11:11 +07:00
2025-08-07 12:27:13 +07:00

VNGeoGuessr

A GeoGuessr clone focused on Vietnamese locations with accurate boundary detection and anti-cheat security. Play geolocation guessing games across a region tree covering the whole country using real street-level imagery.

🎮 Features

  • Region Tree: Whole country, 5 provinces, 61 districts — including Da Lat (Lam Dong) and Duc Hoa (Long An)
  • 360° Street View: Mapillary panoramic images with PhotoSphere viewer
  • Anti-Cheat Security: Server-side session management prevents cheating
  • Distance-Based Scoring: 0-5 point system based on accuracy
  • Persistent Leaderboards: Redis-powered top 200 player rankings
  • Accurate Boundaries: Nominatim API + Turf.js for precise city detection

📚 Documentation

For detailed information about this project, see the documentation in /docs/:

🚀 Getting Started

Prerequisites

  • Node.js 24+
  • npm 11+
  • Redis server (sessions and leaderboards)
  • Postgres database (panorama index; Neon in production)

Development

# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build

# Start production server
npm start

# Run linting
npm run lint

Open http://localhost:3000 to play the game.

🏗️ Built With

  • Frontend: Next.js 16 + React 19 + Tailwind CSS 4
  • Street View: Mapillary API + PhotoSphere Viewer
  • Maps: Leaflet + OpenStreetMap
  • Geographic Data: Nominatim API + Turf.js
  • Storage: Neon Postgres (panorama index) + Upstash Redis (leaderboards and game sessions)
  • UI Components: shadcn/ui

🎯 How to Play

  1. Enter your username
  2. Pick a region from the country/province/district tree
  3. View the 360° street panorama
  4. Place your guess on the map
  5. Earn points based on accuracy (closer = more points)
  6. Compete for the top 200 leaderboard spots!

📋 Development Notes

  • JavaScript Only: No TypeScript files
  • Individual Parameters: Functions use separate parameters, not object destructuring
  • Server-Side Security: Game coordinates never sent to client
  • Session Management: Automatic cleanup after 30 minutes

🤝 Contributing

This project follows specific development guidelines. Please read the Development Guidelines before contributing.

S
Description
GeoGuessr clone for Vietnamese locations — Mapillary panoramas, Turf.js boundaries, Upstash REST leaderboards
Readme Apache-2.0
14 MiB
0 Stars 1 Watchers 0 Forks
Languages
JavaScript 98.2%
CSS 1.8%