SkyTrack - Real-Time Global Aircraft Tracking
SkyTrack is an interactive web application that visualizes real-time aircraft tracking data from around the world. Built as a HackTheBurgh 2025 project, it combines a stunning 3D globe interface with detailed 2D map views to explore live air traffic patterns and aircraft positions.
Overview
The application consists of three main views:
- Landing Screen - Animated welcome screen with 3D globe
- Globe View - Interactive 3D globe where users select a country
- Map View 2D - Detailed 2D map showing real-time aircraft positions for the selected country
The project demonstrates chaos theory concepts by allowing users to adjust a "radar sensitivity" slider, which progressively reveals more aircraft and triggers simulated international conflicts as sensitivity increases.
Architecture
Frontend (React + TypeScript + Three.js)
The frontend is built as a single-page React application using:
- React 18 with TypeScript for type safety
- Vite as the build tool and development server
- React Three Fiber (@react-three/fiber) for 3D rendering
- Three.js for 3D graphics (wrapped by React Three Fiber)
- shadcn/ui components built on Radix UI
- Tailwind CSS for styling
- TanStack Query for data fetching and caching
- React Router for routing
Key Components
LandingScreen.tsx
The initial welcome screen featuring:
- Animated starfield background using React Three Fiber's
Starscomponent - 3D spinning globe in the background with country borders
- CRT scanlines and radar sweep effects
- Floating particles animation
- Information cards about chaos theory and simulation concepts
- Smooth transitions to the globe selection view
Globe.tsx
The interactive 3D globe for country selection:
- Renders a 3D Earth sphere with country borders as 3D lines
- Displays major capital cities as glowing markers
- Interactive orbit controls (drag to rotate, scroll to zoom)
- Hover detection for country highlighting
- Click detection to select countries
- Random country selection button
- Conversion from TopoJSON data (from
/public/countries.json) to GeoJSON - Real-time rotation animation
- Starfield background matching the landing screen aesthetic
Key Features:
- Uses spherical coordinate math to convert lat/lng to 3D vectors
- Creates mesh geometries for country regions to enable click detection
- Calculates country centroids to place selection markers
- Handles both Polygon and MultiPolygon geometries from GeoJSON
MapView2D.tsx
The main game/simulation view showing aircraft tracking:
- 2D SVG-based map rendering of the selected country
- Real-time aircraft position visualization
- Radar Sensitivity Slider - Core interaction that controls aircraft visibility
- Conflict simulation system that triggers as sensitivity increases
- Aircraft information panels on selection
- Threat dashboard with statistics
- Timer system (10-minute countdown)
- Conflict history tracking with visualizations
- Position trail tracking for sensitivity slider changes
Key Mechanics:
- Aircraft Filtering: Based on sensitivity slider value (0.02-0.03 range)
- Below 0.02: No aircraft visible
- 0.02-0.03: Gradual reveal (scaled from 0% to 100% of aircraft)
- Above 0.03: All aircraft visible (chaos mode)
- Conflict Generation: Random conflicts between countries trigger as sensitivity increases
- Chain Reactions: Conflicts can cascade into other countries
- Visual Feedback: Explosion effects, error messages, threat indicators
Index.tsx
Main page component that orchestrates the application flow:
- Manages state transitions between landing → globe → map views
- Handles country selection callbacks
- Displays help dialog
- Manages game over/restart logic
Backend (Express + TypeScript)
The backend is an Express.js REST API server that acts as a proxy to the OpenSky Network API.
Server Architecture
server/src/
├── index.ts # Express app setup and server initialization
├── config/config.ts # Configuration management (env vars, defaults)
├── routes/aircraft.ts # API route handlers for /api/aircraft
├── services/
│ └── opensky-client.ts # OpenSky API client with OAuth2/Basic auth
├── middleware/
│ └── cache.ts # In-memory caching system
├── types/
│ └── aircraft.ts # TypeScript type definitions
└── utils/
└── geospatial.ts # Distance, bearing, bounding box calculations
API Endpoints
GET /api/aircraft
Fetches live aircraft state data from OpenSky Network.
Query Parameters (optional bounding box filter):
lamin- Minimum latitudelamax- Maximum latitudelomin- Minimum longitudelomax- Maximum longitude
Response Format:
{
"success": true,
"count": 1234,
"data": [
{
"icao24": "abc123",
"callsign": "UAL123",
"originCountry": "United States",
"latitude": 51.5074,
"longitude": -0.1278,
"barometricAltitude": 10000,
"geometricAltitude": 10100,
"velocity": 250.5,
"heading": 45.2,
"verticalRate": 5.0,
"onGround": false,
"timePosition": 1234567890,
"lastContact": 1234567890,
"squawk": "1234",
"spi": false,
"positionSource": 0
}
],
"timestamp": 1234567890123
}
GET /api/aircraft/health
Health check endpoint.
Key Backend Features
OpenSky API Integration
- Supports both OAuth2 (preferred) and Basic Auth authentication
- Handles bounding box filtering for regional aircraft queries
- 10-second timeout on API requests
- Comprehensive error handling
Caching System
- In-memory cache to reduce API calls
- Configurable TTL (default: 10 seconds)
- Cache keys based on bounding box parameters
- Automatic cleanup of expired entries
- Max 100 entries with FIFO eviction
Geospatial Utilities
- Great-circle distance calculations
- Bearing calculations
- Bounding box operations
Data Flow
Country Selection Flow:
User clicks country on Globe → Index.tsx receives callback → Calculates country bounding box → Transitions to MapView2DAircraft Data Fetching:
MapView2D mounts with selectedCountry → Loads countries.json → Finds selected country geometry → calculateBoundingBox() → buildAircraftApiUrl() → Fetch /api/aircraft?lamin=...&lamax=... → Backend checks cache → If miss, fetches from OpenSky API → Returns aircraft array → Frontend filters by sensitivity → Renders aircraft on mapReal-time Updates:
- Aircraft data is fetched once when country is selected
- Sensitivity slider controls which aircraft are visible
- No automatic refresh (data is static per session)
Utilities
src/lib/country-bounds.ts
Helper functions for working with country geometries:
calculateBoundingBox()- Converts GeoJSON geometry to lat/lng bounding box with 1-degree bufferbuildAircraftApiUrl()- Constructs API URL with bounding box query parameters
Static Assets
/public/countries.json- TopoJSON data for world countries/public/aircraft-positions.json- Fallback/example aircraft data/public/war-simulation.json- Simulation configuration data
Technologies Used
Frontend Dependencies
- React 18.3.1 - UI framework
- TypeScript 5.8.3 - Type safety
- Vite 5.4.19 - Build tool and dev server
- @react-three/fiber 8.18.0 - React renderer for Three.js
- @react-three/drei 9.122.0 - Useful helpers for React Three Fiber
- three 0.160.1 - 3D graphics library
- topojson-client 3.1.0 - Convert TopoJSON to GeoJSON
- react-router-dom 6.30.1 - Client-side routing
- @tanstack/react-query 5.83.0 - Data fetching and caching
- tailwindcss 3.4.17 - Utility-first CSS
- shadcn/ui components - UI component library
- lucide-react - Icon library
- sonner - Toast notifications
Backend Dependencies
- express 4.21.1 - Web framework
- cors 2.8.5 - CORS middleware
- typescript 5.8.3 - Type safety
- tsx 4.19.2 - TypeScript execution (for running server)
Setup and Installation
Prerequisites
- Node.js 18+ and npm
- (Optional) OpenSky Network account credentials for higher rate limits
Installation
Clone the repository:
git clone <repository-url> cd globe-of-warInstall dependencies:
npm install(Optional) Configure OpenSky API credentials:
cp credentials.json.example credentials.json # Edit credentials.json with your OpenSky username/password or clientId/clientSecret
Alternatively, set environment variables:
export OPENSKY_USERNAME=your_username
export OPENSKY_PASSWORD=your_password
# Or for OAuth2:
export OPENSKY_CLIENT_ID=your_client_id
export OPENSKY_CLIENT_SECRET=your_client_secret
Running the Application
You need to run both the frontend and backend servers:
Terminal 1 - Frontend (Vite dev server):
npm run dev
Frontend runs on http://localhost:8080
Terminal 2 - Backend (Express API server):
npm run dev:server
Backend runs on http://localhost:3001
The Vite dev server is configured to proxy /api/* requests to the backend server automatically.
Production Build
Build the frontend:
npm run build
The built files will be in the dist/ directory.
Run the backend in production mode:
npm run server
Configuration
Backend Configuration
Environment variables (all optional):
PORT- Server port (default: 3001)HOST- Server host (default: localhost)CACHE_ENABLED- Enable caching (default: true)CACHE_TTL- Cache time-to-live in seconds (default: 10)OPENSKY_USERNAME/OPENSKY_PASSWORD- Basic Auth credentialsOPENSKY_CLIENT_ID/OPENSKY_CLIENT_SECRET- OAuth2 credentials
See server/src/config/config.ts for full configuration options.
Frontend Configuration
Vite proxy configuration is in vite.config.ts:
- Frontend dev server: port 8080
- API proxy target:
http://localhost:3001
How It Works - Technical Deep Dive
3D Globe Rendering
The globe uses spherical coordinate mathematics to convert geographic coordinates (latitude/longitude) to 3D Cartesian coordinates:
function latLngToVector3(lat: number, lng: number, radius: number) {
const phi = (90 - lat) * (Math.PI / 180); // Polar angle
const theta = (lng + 180) * (Math.PI / 180); // Azimuthal angle
const x = -(radius * Math.sin(phi) * Math.cos(theta));
const y = radius * Math.cos(phi);
const z = radius * Math.sin(phi) * Math.sin(theta);
return new THREE.Vector3(x, y, z);
}
Country borders are rendered as 3D Line components, and invisible mesh geometries are used for click detection.
Aircraft Visualization
In MapView2D, aircraft are positioned on an SVG map:
- Country boundaries are rendered as SVG paths from GeoJSON coordinates
- Aircraft positions are calculated relative to the SVG viewBox
- Aircraft icons rotate based on heading (if available)
- Color coding: cyan for aircraft, red for conflicts
Chaos Theory Simulation
The "radar sensitivity" slider represents the core chaos theory concept:
- Low sensitivity (0.00-0.02): World appears peaceful, no aircraft visible
- Medium sensitivity (0.02-0.03): Gradual reveal of aircraft, initial conflicts
- High sensitivity (0.03+): Complete visibility, chaos mode with cascading conflicts
As sensitivity increases:
- More aircraft become visible
- Random conflicts are generated between countries
- Conflicts can trigger chain reactions
- Visual feedback (explosions, error messages) intensifies
- Threat dashboard shows escalating statistics
Project Structure
globe-of-war/
├── src/ # Frontend source code
│ ├── components/
│ │ ├── Globe.tsx # 3D globe component
│ │ ├── LandingScreen.tsx # Landing page
│ │ ├── MapView2D.tsx # Main 2D map view
│ │ └── ui/ # shadcn/ui components
│ ├── pages/
│ │ ├── Index.tsx # Main page router
│ │ └── NotFound.tsx # 404 page
│ ├── lib/
│ │ ├── country-bounds.ts # Bounding box utilities
│ │ └── utils.ts # General utilities
│ ├── hooks/ # Custom React hooks
│ ├── App.tsx # Root component
│ └── main.tsx # Entry point
├── server/ # Backend source code
│ ├── src/
│ │ ├── index.ts # Server entry point
│ │ ├── config/ # Configuration
│ │ ├── routes/ # API routes
│ │ ├── services/ # Business logic
│ │ ├── middleware/ # Express middleware
│ │ ├── types/ # TypeScript types
│ │ └── utils/ # Utility functions
│ └── README.md # Backend documentation
├── public/ # Static assets
│ ├── countries.json # TopoJSON country data
│ └── aircraft-positions.json # Example aircraft data
├── package.json # Dependencies and scripts
├── vite.config.ts # Vite configuration
└── tailwind.config.ts # Tailwind CSS configuration
Development Notes
- The application uses React Three Fiber for 3D rendering, which provides a React-friendly wrapper around Three.js
- Country data is in TopoJSON format for efficient storage and must be converted to GeoJSON for rendering
- The OpenSky API has rate limits: ~10 requests/second for unauthenticated users, higher limits with authentication
- Aircraft data is cached for 10 seconds to reduce API calls
- The MapView2D component is quite large (2600+ lines) and handles all simulation logic
Future Enhancements
Potential improvements:
- Real-time aircraft position updates (WebSocket integration)
- Historical flight path visualization
- More detailed aircraft information panels
- Export conflict data/history
- Multiple country selection and comparison
- Performance optimizations for rendering thousands of aircraft
License
Created for HackTheBurgh 2025 by WLDN x Builder's Brew
Acknowledgments
- OpenSky Network - Provides the real-time aircraft tracking data
- React Three Fiber - Makes 3D rendering in React accessible
- shadcn/ui - Beautiful, accessible UI components
- TopoJSON - Efficient geographic data format
Log in or sign up for Devpost to join the conversation.