A web-based training simulation for satellite ground station operations, built with TypeScript and vanilla JavaScript.
SignalRange simulates a commercial satellite ground station environment where operators learn to configure and troubleshoot RF equipment chains. The training scenarios are set at North Atlantic Teleport Services (NATS), a fictional satellite ground station facility in Vermont serving the TIDEMARK constellation.
Five scenarios (with three more coming in January) taking you from observation to independent operations at a commercial C-band ground station in Vermont. Progress from health checks and maintenance procedures through satellite handovers, acquisitions, and RF troubleshooting. See the scenario guide for details.
Campaign 1 is the beginning. Here's what's planned for 2026:
Complete the NATS campaign with advanced scenarios: rain fade compensation, full link budget analysis, and independent troubleshooting under time pressure.
Charlie transfers to NATS Europe. LEO satellite tracking, multi-contact mission planning, video feed decoding, and Ku-band operations.
Charlie's niece teaches you how to track satellites from your backyard. Software-defined radios, SatNOGS, circular polarization, GPS signal tracking, and DIY antenna setups.
Military counter-communications operations. SATCOM denial, redundant hardware management, multi-antenna coordination, X-band.
Someone is jamming allied satellites. Find them using geolocation and advanced RF techniques.
- 9m C-band Antenna - Pointing, tracking modes, polarization control
- LNB - Local oscillator, gain, thermal stabilization
- BUC - Block upconverter with mute control
- HPA - High power amplifier with safety interlocks
- IF Filter Bank - Bandwidth selection
- GPSDO - GPS-disciplined oscillator for frequency reference
- Spectrum Analyzer - Real-time RF visualization
- Receiver/Transmitter Modems - Signal demodulation and generation
- Node.js 24.x (see
.nvmrc; Volta picks it up automatically) - pnpm 10.x β
corepack enableornpm install -g pnpm@10
# 1. Clone the repository
git clone https://github.com/thkruz/SignalRange.git
cd SignalRange
# 2. Install dependencies
pnpm install
# 3. Set up environment variables
cp .env.example .env
# 4. Pull campaign assets from R2 (audio/images)
pnpm run r2:pull
# 5. Start the development server
pnpm run devNote:
src/privateis an optional, private git submodule (plans, design docs and internal notes). Contributors do not need it and the build never reads it. Clone without--recurse-submodules, or ignore the "permission denied" from that one submodule if you do.
The app will be available at http://localhost:3000 (or the port shown in terminal).
Copy .env.example to .env and configure:
| Variable | Required | Description |
|---|---|---|
PUBLIC_SUPABASE_URL |
For auth features | Your Supabase project URL |
PUBLIC_SUPABASE_ANON_KEY |
For auth features | Supabase anonymous/public key |
PUBLIC_USER_API_URL |
No | User API endpoint (has default) |
PUBLIC_ASSETS_BASE_URL |
No | Leave empty for local dev |
For local development without authentication features, the default .env.example values work out of the box.
Campaign assets (audio files, character images) are stored in Cloudflare R2 and not committed to the repository.
# Download assets from R2 (no authentication required)
pnpm run r2:pull
# Preview what would be downloaded
pnpm run r2:pull:dryAssets are downloaded to public/assets/campaigns/ and public/assets/characters/.
| Command | Description |
|---|---|
pnpm run dev |
Start the rspack dev server with hot reload |
pnpm run build |
Production build to dist/ |
pnpm run preview |
Preview production build with Wrangler |
pnpm run r2:pull |
Download campaign assets from R2 |
pnpm test |
Run the Vitest suite |
pnpm run typecheck |
Type-check with tsgo (TypeScript 7 native) |
pnpm run typecheck:tsc |
Same check on stock tsc, as a fallback |
pnpm run lint |
Lint and format-check with Biome |
pnpm run lint:fix |
Apply Biome's safe fixes |
pnpm run format |
Format with Biome |
Assets not loading?
Run pnpm run r2:pull to download campaign audio and images.
TypeScript errors?
Run pnpm run typecheck to see detailed type errors.
Port already in use?
The dev server defaults to port 3000. Check for other processes or modify rspack.config.mts.
Equipment and features can come from plugins: small git repositories that the engine compiles into its own bundle. The toolchain mirrors keeptrack-space's.
pnpm run plugin -- add https://github.com/thkruz/signal-range-plugin-example # install one
pnpm run plugin -- create my-dish # scaffold your own
pnpm run plugin -- dev signal-range-plugin-my-dish # boot with only it enabled
pnpm run plugin -- list # what is installedInstalled plugins are recorded in external-plugins.json and restored by
pnpm run plugin -- restore (the build runs this for you). Plugin antennas
appear in every sandbox's LOADOUT picker. See
docs/plugin-development-guide.md.
SignalRange is deployed on Cloudflare Workers with static assets. There are two environments:
| Environment | URL | Purpose |
|---|---|---|
| Production | https://app.signalrange.space | Live user-facing application |
| UAT | https://uat.signalrange.space | Pre-production testing and validation |
# Deploy to UAT (test changes first)
pnpm exec wrangler deploy --env uat
# Deploy to Production (after UAT validation)
pnpm exec wrangler deploy --env productionAlways deploy to UAT first to validate changes before promoting to production.
AGPLv3 - See LICENSE.md