Files
vngeoguessr/package.json
T
tiennm99 ab2c271c87 perf(mapillary): play from a prebuilt index instead of searching bboxes
Rounds took a measured 4.9s at the median and failed most of the time. A
40-window sample returned 6 hits, 1 empty window and 33 errors.

The cause was not our retry tuning. /images?bbox= counts the images
inside the box before applying the limit, so it returns HTTP 500 in
exactly the places worth playing: District 1 and central Ha Noi failed on
every attempt, and limit=1 on a 0.0004 degree window failed the same as
limit=50. Backing off does not clear it, and neither does shrinking the
window, so the whole dart-throw goes: the racing, the empty and error
budgets, the widening backoff, and the per-city delta they needed.

Coverage now comes from the vector tile API, which answers everywhere
the Graph API refuses, and is walked once offline into a per-city list of
panorama ids. A round is a single lookup by id, measured at 482ms median
across all five cities with no failures. Locations are deduplicated to
one per 33m so the file holds distinct places rather than repeat passes
down the same street.

Cities gain real outlines in place of rectangles. Vietnam merged its
provinces in mid-2025, so today's Ho Chi Minh City covers 36,566 km2 and
reaches Vung Tau; these are the pre-merger extents, rebuilt by unioning
the district-level units OpenStreetMap still serves as historic
boundaries. Da Nang is enabled now that every location is known to have
imagery. Cu Chi is absent from Ho Chi Minh: its old relation is gone from
OSM and only sub-communes remain, so the file records the gap.

The build script refuses to write when a tile is missing after retries.
tiles.mapillary.com allows 50,000 requests a day and a full rebuild costs
about 2,800, so a quota failure is plausible, and a partial index would
be indistinguishable from genuinely absent coverage.
2026-08-30 12:23:44 +07:00

59 lines
1.5 KiB
JSON

{
"name": "vngeoguessr",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "vitest run",
"test:watch": "vitest",
"test:integration": "vitest run --config vitest.integration.config.mjs",
"redis:up": "docker compose up -d --wait",
"redis:down": "docker compose down -v"
},
"dependencies": {
"@photo-sphere-viewer/core": "^5.14.3",
"@radix-ui/react-dialog": "^1.1.19",
"@radix-ui/react-label": "^2.1.11",
"@radix-ui/react-slot": "^1.3.0",
"@radix-ui/react-tabs": "^1.1.17",
"@turf/turf": "^7.2.0",
"@upstash/redis": "^1.38.0",
"@vercel/analytics": "^1.5.0",
"@vercel/speed-insights": "^1.2.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"leaflet": "^1.9.4",
"lucide-react": "^0.536.0",
"next": "15.5.18",
"react": "19.2.7",
"react-dom": "19.2.7",
"tailwind-merge": "^3.3.1",
"uuid": "^14.0.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.6",
"@mapbox/vector-tile": "^3.0.0",
"@tailwindcss/postcss": "^4.3.3",
"eslint": "^9.39.4",
"eslint-config-next": "15.4.6",
"pbf": "^5.1.2",
"tailwindcss": "^4.3.3",
"tw-animate-css": "^1.3.6",
"vitest": "^4.1.11"
},
"engines": {
"node": ">=24"
},
"overrides": {
"js-yaml": "^4.2.0",
"postcss": "^8.5.10"
},
"allowScripts": {
"sharp": true,
"unrs-resolver": true
}
}