Drop a voice. Discover a moment.
Live: https://echomap.live
EchoMap is a location-based social app built during TreeLine Hacks. Users can leave short, ephemeral audio notes at real-world coordinates, and nearby people can discover them on a live map when they move within range.
- Drop an echo at your current GPS location
- Discover nearby echoes within a 500 meter radius
- Play back generated audio, or fall back to browser speech for text-only echoes
- Auto-expire echoes after 24 hours
- Sync auth with Clerk and real-time data with Convex
- Visualize everything in a map-first Next.js interface powered by Mapbox
Echo discovery is built around geohash spatial indexing instead of checking every row in the database.
- A user's latitude and longitude are encoded into a geohash.
- Each echo is stored with that geohash and indexed in Convex.
- Nearby lookup queries the current cell plus surrounding cells.
- Results are refined with the Haversine formula to keep the final radius accurate.
That keeps nearby discovery fast while still returning exact distance-filtered results.
- Next.js 16 + React 19 + TypeScript
- Tailwind CSS 4 + Framer Motion
- Convex for database, file storage, realtime queries, actions, and cron jobs
- Clerk for authentication
- Mapbox GL via
react-map-gl - Google Cloud Text-to-Speech for generated audio
- OpenNext + Cloudflare for deployment
npm installCreate echomap/.env.local with the values your environment needs:
NEXT_PUBLIC_CONVEX_URL=
NEXT_PUBLIC_MAPBOX_TOKEN=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
CLERK_JWT_ISSUER_DOMAIN=
# Optional for generated MP3 audio. Without this, echoes are saved as text-only
# and played back with the browser speech synthesis fallback.
GOOGLE_APPLICATION_CREDENTIALS_JSON=Notes:
CLERK_JWT_ISSUER_DOMAINis required byconvex/auth.config.tsGOOGLE_APPLICATION_CREDENTIALS_JSONshould contain the full JSON service account payload on one line- If
NEXT_PUBLIC_MAPBOX_TOKENorNEXT_PUBLIC_CONVEX_URLis missing, the UI shows a configuration screen instead of the map
npx convex devnpm run devThen open http://localhost:3000.
npm run dev- start the Next.js dev servernpm run build- create a production buildnpm run start- run the production build locallynpm run lint- run ESLintnpm run test:location- run the location helper smoke testnpm run seed- seed demo users and demo echoes into Convexnpm run preview- build and preview the Cloudflare deployment locallynpm run deploy- build and deploy with OpenNext for Cloudflarenpm run upload- upload the OpenNext build artifactsnpm run cf-typegen- generate Wrangler environment types
You can seed a small demo dataset centered around San Francisco:
npm run seedThis creates demo users plus multiple demo echoes so the map is not empty during demos.
If you want to seed the production deployment instead of the currently configured local/dev deployment, run:
npx convex run --prod convex/seed:seedDataImportant:
- The seed flow uses the internal Google TTS path and expects
GOOGLE_APPLICATION_CREDENTIALS_JSONto be configured - User-created echoes gracefully fall back to text-only mode when Google TTS is unavailable
npm run seedtargets the current Convex deployment from your local env configuration
echomap/
|- app/
| |- components/
| | |- EchoMap.tsx # Main map UI and nearby echo experience
| | |- DropEchoModal.tsx # Echo creation flow
| | '- echoMapLocation.ts # Location request helper
| |- layout.tsx # App shell and metadata
| '- page.tsx # Client entrypoint
|- convex/
| |- echoes.ts # Echo queries and mutations
| |- tts.ts # Google TTS action and upload flow
| |- schema.ts # Convex data model
| |- cleanup.ts # Expired echo cleanup job
| |- crons.ts # Scheduled background jobs
| '- users.ts # Clerk-to-Convex user sync
|- lib/
| '- geohash.ts # Spatial indexing and distance utilities
|- scripts/
| '- test-echo-map-location.js
|- open-next.config.ts
|- wrangler.jsonc
and package config files
- Echoes are discoverable only when a user is physically nearby
- Each echo expires 24 hours after creation
- Nearby results are distance-sorted
- Audio is stored in Convex file storage
- Cleanup jobs remove expired echoes and stale TTS quota reservations
The project is set up for Cloudflare via OpenNext and is live at https://echomap.live.
npm run preview
npm run deployRelevant files:
open-next.config.tswrangler.jsoncmiddleware.ts
Production notes:
- The custom domain is managed through Cloudflare DNS
NEXT_PUBLIC_*values must be available to the Cloudflare build so Next.js can inline them correctly
EchoMap was built to show a map-first social product with a clear algorithms angle: real-world discovery powered by geohash indexing instead of naive full-database distance scans.