mirror of
https://github.com/tiennm99/vngeoguessr.git
synced 2026-10-15 00:18:04 +00:00
Reconcile every doc with the shipped code. All six described a flat five-city model, and features.md, tech-stack.md, game-flow.md and project-structure.md still documented the dart-throw over /images?bbox= that the prebuilt panorama indexes replaced. project-overview.md gains a Coverage note that classifies absent coverage into its three causes -- not yet added, no street imagery, missing from the boundary -- because a note that only says "partial" teaches maintainers to ignore real gaps. Cu Chi is named as the one instance of the third, which is the only one that is a defect. A context hook had been denying access to src/app/debug/coverage/page.js, so this also lands the two items earlier phases recorded as undeliverable: the api/debug/city-coverage -> region-coverage rename, and the page's migration from a flat city list to RegionSelect. With its last caller gone, game.js drops CITIES, cities, cityNames, cityCenters and cityBboxes; getCityIndex, indexedCities and fetchCityPanorama take names that match what they now take. Selecting a district with no boundary returned a 400 and left the previous region's panorama count and outline on screen beside the error, so Ho Chi Minh's 184,938 read as Cu Chi's. The error path now clears everything derived from the previous region, and a null boundary removes the outline rather than skipping the redraw. Two plan-time claims did not survive contact with the code and the docs follow the code: VN scores like any other node rather than being a zero-scoring exploration mode, and the fan-out credits two levels when a panorama falls outside every district outline.
3.7 KiB
3.7 KiB
Game Features
Location Coverage
- Three-level region tree: Vietnam → five provinces → 61 districts and towns,
generated into
src/data/regions/and traversed throughsrc/lib/regions.js - Play at any level: the whole country, one province, or one district
- Pre-2025-merger boundaries: Da Lat sits under Lam Dong, Duc Hoa under Long An
- Partial by design: see the Coverage note in project-overview.md for the three distinct reasons a region can be unavailable
Street View System
- Prebuilt panorama indexes: each province ships a list of Mapillary panorama
ids, their coordinates, and the district each falls in, built offline by
scripts/build-pano-index.mjsandscripts/assign-pano-districts.mjs - Mapillary vector tiles: the index is built from the z14
imagelayer, not from/images?bbox=search, which returns HTTP 500 in exactly the dense districts the game wants to play. See the header ofsrc/lib/mapillary.js - Runtime cost is one lookup:
fetchPanoramaByIdresolves a chosen id in ~230ms; a couple of alternates are tried in case an image was deleted upstream - Country draws pick a province first, uniformly, so Vietnam rounds are not 97% Ha Noi and Ho Chi Minh by panorama count
- Panoramas only: non-panoramic images are filtered out when the index is built, so every indexed point is a panorama. The flag itself is not stored
- Thumbnail display:
thumb_2048_url, falling back tothumb_original_url
Interactive Maps
- Leaflet Integration: OpenStreetMap-based interactive mapping
- Click-to-Place: Intuitive guess marker placement
Anti-Cheat Security
- Redis Session Management: target coordinates stored server-side in Redis
- Server-resolved region: the district a panorama sits in is decided at
session creation and never sent to the client; a
regionCodein the guess request body is ignored - UUID Session IDs: unique session identifiers using uuid v4
- 30-minute Expiry: automatic Redis session cleanup
- Single-use sessions: the session is claimed with an atomic
DELbefore any score is written, so a replayed or concurrent submit scores exactly once - Server-side Calculations: all distance and scoring computed server-side using Turf.js
Scoring System
Distance-based points (0-5 scale):
- 0-50m: 5 points
- 50m-100m: 4 points
- 100m-200m: 3 points
- 200m-500m: 2 points
- 500m-1km: 1 point
- 1km+: 0 points
Leaderboards
- Rollup fan-out: one guess credits the district its panorama sat in, then that district's province, then Vietnam — three score boards and three distance boards. A panorama that fell outside every district outline credits two levels instead of three; no province currently has such a panorama
- Score Leaderboards: accumulated points, one entry per user per board
- Distance Leaderboards: best-distance records, multiple entries per user
- Existing scores preserved: Vietnam keeps the pre-existing
leaderboard:vietnam/distance:vietnamkeys rather than starting a newleaderboard:city:vn.HN,DNandTPHCMkept their codes, so their boards carried over untouched. Only two codes moved — Da Lat's board was backfilled into Lam Dong's and Duc Hoa's into Long An's byscripts/migrate-leaderboards.mjs, which copies rather than moves. No score was reset - Redis Sorted Sets: persistent leaderboard data using ZADD/ZRANGE
- Top 200 Entries: automatic trimming per leaderboard
- Real-time Ranking: rank calculated with ZREVRANK/ZRANK
- Persistent Storage: no expiration on leaderboard data
The leaderboard:city: / distance:city: key prefix is kept deliberately —
renaming it would orphan every score already recorded under it.