A location-based mobile app that reveals an interactive fog-of-war map as you explore the real world. Built with React Native and Expo, FogBound combines gaming mechanics with exploration to encourage outdoor discovery.
- Overview
- Features
- Demo
- Tech Stack
- Installation
- Running the App
- Backend Setup
- Project Architecture
- Development
- Troubleshooting
FogBound creates a persistent fog-of-war overlay on a map that clears as you physically visit locations. The app tracks your movement using GPS, divides the world into grid cells, and stores visited cells locally using SQLite. Points of interest (POIs) are hidden until discovered, creating an exploration-based experience.
- Fog-of-War System: Real-time fog overlay that clears as you explore
- Deterministic Grid System: 200m Web Mercator cells with consistent coordinates
- Persistent Storage: SQLite database for offline-first visited cell tracking
- POI Discovery: Hidden points of interest revealed as you explore
- Daily Mystery POIs: Time-limited discoverable locations
- Background Tracking: Continuous location tracking even when app is backgrounded
- Performance Optimized: Adaptive LOD system, LRU caching, and viewport-based rendering
- Cross-Platform: Works on iOS, Android, and Web
Demo video and live deployment links will be added here:
- Video Demo: [Coming Soon]
- Live Demo: [Coming Soon]
Frontend
- React Native 0.81.5
- Expo SDK 54
- TypeScript 5.9
- Expo Router (file-based routing)
- React Native Maps
- Expo SQLite
- Zustand (state management)
- React Native Skia (shader-based fog rendering)
Backend
- Node.js 20+
- Express.js
- TypeScript
- MongoDB (optional, currently using in-memory storage)
- Zod (validation)
Key Libraries
- expo-location: GPS tracking and geofencing
- expo-task-manager: Background location updates
- expo-secure-store: Secure credential storage
- Node.js 20 or higher
- npm or yarn package manager
- Expo Go app on your phone:
- For iOS development: macOS with Xcode
- For Android development: Android Studio
- Clone the repository:
git clone https://github.com/seamushinz/FogBound.git
cd FogBound- Install frontend dependencies:
npm install- Start the Expo development server:
npm start- Scan the QR code with:
- iOS: Camera app (will open in Expo Go)
- Android: Expo Go app
npx expo run:iosnpm run androidnpm run webNote: Location features are limited in web browsers and simulators. For full experience, use a physical device.
The backend is optional for basic functionality (local-only mode). To enable cloud sync:
- Navigate to backend directory:
cd backend- Install dependencies:
npm install- Create environment file:
cp .env.example .env- Start development server:
npm run devServer runs on http://localhost:3000 by default.
For persistent cloud storage:
-
Create a MongoDB Atlas cluster at mongodb.com/cloud/atlas
-
Create a database named
fogboundwith collections for cells and user data -
Update
.envwith your MongoDB connection string:
MONGODB_URI=mongodb+srv://<username>:<password>@<cluster-url>/fogbound?retryWrites=true&w=majority
Replace <username>, <password>, and <cluster-url> with your actual MongoDB credentials.
- Update
backend/src/app.tsto use MongoCellRepo instead of InMemoryCellRepo
GET /health- Health checkPOST /cells/sync- Upload cell visit data (requires auth)GET /cells/bbox- Retrieve cells in bounding box (requires auth)
See backend/README.md for detailed API documentation.
FogBound/
├── app/ # Expo Router screens and navigation
│ ├── (tabs)/ # Tab-based navigation screens
│ │ ├── index.tsx # Main map screen with fog overlay
│ │ ├── history.tsx # User history and statistics
│ │ ├── account.tsx # User account management
│ │ └── debug.tsx # Debug tools and settings
│ ├── auth.tsx # Authentication screen
│ └── _layout.tsx # Root layout and navigation
├── components/ # Reusable UI components
│ ├── FogOverlay.tsx # Polygon-based fog rendering
│ ├── FogShaderOverlay.tsx # Skia shader-based fog rendering
│ └── ui/ # UI components
├── db/ # SQLite database operations
│ ├── cellDatabase.ts # Visited cell CRUD operations
│ ├── pois.ts # POI storage and queries
│ └── dailyMysteryPois.ts # Daily mystery POI tracking
├── services/ # External service integrations
│ ├── overpass.ts # OpenStreetMap POI fetching
│ └── LocationTask.ts # Background location tracking
├── utils/ # Utility functions and helpers
│ ├── mercator.ts # Web Mercator coordinate conversion
│ ├── grid.ts # Grid cell calculations
│ ├── locationTracker.ts # Location update handling
│ └── poiVisibility.ts # POI classification logic
├── store/ # Global state management (Zustand)
├── assets/ # Images, fonts, and static assets
├── backend/ # REST API server
│ ├── src/
│ │ ├── routes/ # API route handlers
│ │ ├── middleware/ # Auth and error handling
│ │ └── repositories/ # Data access layer
│ └── package.json
└── package.json
FogBound uses a deterministic grid-based fog-of-war system:
- Web Mercator Grid: Fixed 200m rectangular cells aligned consistently across zoom levels
- SQLite Storage: Persistent visited cell tracking with x/y coordinates
- Viewport Rendering: Only renders visible cells plus padding (never the whole world)
- Performance Optimization:
- Level-of-Detail (LOD) system with adaptive cell grouping
- LRU caching with quantized keys
- Rectangle merging to reduce polygon count
- Adaptive padding based on zoom level
- Throttled fog refresh during panning
See FOG_SYSTEM.md for detailed technical documentation.
Frontend
npm start- Start Expo development servernpm run ios- Run on iOS simulator (macOS only)npm run android- Run on Android emulatornpm run web- Run in web browser
Backend
npm run dev- Start development server with hot reloadnpm run build- Compile TypeScript to JavaScriptnpm start- Run compiled production servernpm run lint- Type-check without emitting files
Create a .env file in the backend directory:
PORT=3000
# MONGODB_URI=mongodb+srv://... # OptionalThe app requires location permissions to function:
- iOS: "Allow While Using App" or "Allow Always" for background tracking
- Android: Location permission with background access
Permissions are requested on first app launch.
- Check that location permissions are granted
- Verify database initialization in console logs
- Ensure you're testing on a physical device (simulators have limited GPS)
- Check that FogOverlay component is inside MapView
- Reduce
maxPolygonsprop on FogOverlay component - Increase
CELL_SIZE_Minutils/grid.tsfor coarser grid - Check device frame rate in React Native profiler
- Verify backend server is running on correct port
- Check firewall settings allow connections
- Update frontend API endpoint configuration
- For MongoDB: verify connection string and network access
- Clear Expo cache:
npx expo start -c - Reinstall dependencies:
rm -rf node_modules && npm install - For iOS:
cd ios && pod install(if using bare workflow) - For Android: Clean gradle cache
- Ensure location permissions are granted in device settings
- Check that device location services are enabled
- For iOS: Verify location permission strings in app.json
- For Android: Check background location permission is granted
This project was developed as part of a hackathon. Contributions are welcome through pull requests.
- Follow existing code structure and conventions
- Keep components focused and reusable
- Document complex logic with comments
- Test on both iOS and Android when possible
- Use TypeScript for type safety
MIT
- Built with Expo and React Native
- POI data from OpenStreetMap via Overpass API
- Map tiles from react-native-maps default providers