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.html loaded 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 RunTrackingService foreground 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 integerValue as 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

Share this project:

Updates

Submission history