Inspiration
I wanted to get people off their couches and outside — but existing fitness apps felt like solo experiences. What if your city was a game board? What if the streets you run every day could become yours? That idea — combined with a personal challenge to build a full production app using only my phone — became TurfWar.
What it does
TurfWar is a real-time GPS territory claiming game. You go outside, run or walk a closed loop around any area, and when you complete it — that zone is claimed as your territory. Other players can steal it by running the same area. A live leaderboard ranks everyone by total territory owned in m².
Key features:
- 🗺️ GPS loop tracking — close a loop to claim the enclosed area
- 🏃 Live run stats — distance, time, pace, m² in real-time
- 🔔 Steal alerts — get notified when someone takes your turf
- 📊 Global leaderboard — compete with players worldwide
- 🌙 Dark + light theme, offline-capable map
How we built it
The entire app was built on a phone — no PC, no Android Studio, no Gradle.
- Sketchware Pro — visual Android IDE on phone, used for the app shell and Java bridge
- Vanilla HTML/CSS/JS — the entire UI and game logic lives in a single
index.htmlloaded in a WebView - Leaflet.js + OpenStreetMap — map rendering with custom dark theme
- Turf.js — GPS polygon math for territory area calculation
- Firebase Firestore — real-time territory sync across all players
- Firebase Auth — email/password authentication
- Termux — Git, file management, APK signing — all from terminal on phone
- Claude AI — senior developer and debugging partner throughout the build
Challenges we ran into
- Splash screen hang —
boot().then(clearTimeout)was killing the only safety net before Firebase resolved on slow networks - Notification stacking — Android kept creating new notifications instead of updating one; solved by building a
RunTrackingServiceforeground service with a fixed notification ID and OS-native chronometer - WebView layout bugs — navbar floated mid-screen due to flex height not filling in Android WebView; fixed with
position:fixed; bottom:0 - Firestore integer parsing — REST API returns
integerValueas a string"42"not a number;getInt()silently returned 0 every time - GPS first point bug — the very first coordinate was silently dropped because path push was inside
if(last)block - No PC debugging — every bug had to be reproduced, diagnosed and fixed live on device
Accomplishments that we're proud of
- Built a complete, production-quality Android app entirely on a phone
- Live multiplayer territory system working in real-time across devices
- Persistent foreground run notification with a smooth OS-native timer — no flicker, no stacking
- Shipped to GitHub with a full release, README, and MIT license — all from Termux
- Proved that mobile-first development is real
What we learned
- Android WebView has deep quirks that desktop browsers don't — flex layout, script loading, and geolocation all behave differently
- Firebase REST API is not identical to the SDK — subtle differences in how integers and timestamps are returned
- Building without a PC forces you to think more carefully before writing code — there's no hot reload safety net
- A great debugging partner (Claude AI) can replace a lot of tooling
What's next for TurfWar
- ✅ Fix Google Sign-In with native Android OAuth flow
- 🏆 Team mode — claim territory as a squad
- 💬 In-app chat for rival territory disputes
- 📱 Play Store public release
- 🌍 City-wide leaderboards by region
Built With
- android
- firebase
- firestore
- gps
- html/css
- java
- javascript
- leaflet.js
- openstreetmap
- pro
- sketchware
- termux
- turf.js
- webview
Log in or sign up for Devpost to join the conversation.