Skip to content
ghtomcatPublic

About

Open-source browser simulation engine. Any vehicle is a JSON file. Any mission is a JSON file.

Resources

Code of conduct

Stars

9 stars

Watchers

0 watching

Forks

Repository files navigation

OpenSim

Open-source browser-based simulation engine. Any vehicle is a JSON file. Any mission is a JSON file.

OpenSim PFD — ILS Approach LSZH

Born 05:32, Sunday 15 March 2026, Zürich. Built with Claude Code.


Realism as respect.

Every aircraft modeled here carried a human being. Every engine sound is calibrated from real recordings. Every mission is set on the right day, over the right place, with the right names.

We do not take sides in history. A nineteen-year-old climbing into a Zero over the Pacific deserves the same accuracy and respect as the one climbing into a Corsair. OpenSim honors duty. Not victory. Not ideology. Duty.

→ MANIFEST.md · CODE_OF_CONDUCT.md


Who it is for

Spotters — open the live radar, watch real flights within 1000nm, color-coded by destination. Click any aircraft and fly it at its current position, altitude, and heading.

Historians — load a mission from 1918, 1942, or 1956. Read the classified briefing document. Hear the crew in the right language. Fly the aircraft with the right physics.

Warbird buffs — the R-2800 Double Wasp fires 18 cylinders in two rows. The DB 601 startup takes 71 seconds from cold. Open the radiator flap too late and the coolant boils; spring a coolant leak and the engine seizes. Every number came from a POH or technical manual. If you've stood next to a running radial at an airshow, you'll know immediately whether it's right.

Space nerds — fly the Falcon 9 Demo-2 from T-3:00 with real webcast audio. Watch stage separation. Track the booster back to LZ-1, or out to the droneship. Fly a 590 km orbit. Deorbit, reentry, splashdown. Apollo 8 to the Moon, Apollo 13 home again, Starship IFT-12 and IFT-13. The physics are real. SpaceX, Apollo, V-2, Vostok, H3 — every program that ever put something into orbit deserves a mission here. Scott Manley would check the Isp. Everyday Astronaut would check the fairing. Check them.

PPL students — circuits at LSZF and LSZG. Full checklists. GPWS callouts. Emergency procedures. Scored debrief: alignment, speed, touchdown point. Engine failure scenarios with virtual ATC Mayday acknowledgement. Real weather via live METAR. No instructor needed to run a session.

Airline pilots-to-be — gate to gate on real SIDs, STARs and approaches. LNAV and VNAV fly the route, the ND draws it, the MCDU and kneeboard brief it — including the missed approach. EGPWS watches the terrain.

Makers — build a Dragon capsule mockup with a table saw, a Bambu A1, and four screens. Wire an ESP32 to a physical altimeter. Add a 6-DOF motion platform. The WebSocket data stream is open.

Anyone with a browser — no install. No login. No fee. Works on a laptop, tablet, or Raspberry Pi.


What it is

OpenSim is not a game. It is a modular simulation engine that runs entirely in the browser with zero dependencies and no build step.

  • Real aerodynamic physics — lift, drag, thrust, weight from first principles. Not kinematic approximations.
  • Procedural sound — engine sounds synthesised from physics. No samples. Wind rises with airspeed. The DB 601 fires 12 cylinders. The NK-12 turboprop beats at 3.8Hz.
  • Historically accurate comm chain — every voice passes through the correct radio equipment for its era. VHF aviation, NASA S-band, Soviet VHF, SpaceX IP backbone. Pre-recorded voices, archival recordings, or TTS — all through the same chain.
  • Real terrain — Mapbox Terrain-RGB tiles (Copernicus DEM, 30m resolution) projected onto a flat-earth pinhole camera. Mountain silhouettes, elevation-based colour, atmospheric haze, space skybox with stars. 60 fps on M2. A default public token is included — replace it with your own free token in display/terrain.js if you're running a public deployment.
  • 3D wireframe aircraft at 60 fps — flat-shaded painter's algorithm in pure Canvas 2D. Back-face culling, depth sorting, light-direction shading. No WebGL. No Three.js. No dependencies. Chase cam · side cam · wing view · plume cam · booster cam. For Falcon 9: engine plumes, LOX vent clouds, grid fins, S2 Merlin Vacuum bell, landing legs that deploy.
  • Any aircraft — envelope, performance, handling, sound, crew language, checklists in one JSON file
  • Any mission — weather, ATC clearances, classified briefing documents, scripted failures, crew voices in one JSON file
  • Data-driven airports — runways, taxiways, gates and terminals derived from OSM + OurAirports. Fly an approach into an airport the sim has never seen and the ground environment is already there.
  • Gate-to-gate — pushback, ATC taxi clearances over the taxiway graph, vacate detection, gate assignment, and VDGS docking guidance — both directions of the ground phase.
  • Real navigation — SIDs, STARs and approaches from FAA CIFP / X-Plane nav data, airways, navaids. One route (core/route.js) feeds the briefing, the ND, the MCDU and the LNAV/VNAV autopilot.
  • EGPWS + CFIT — terrain collision from the Mapbox DEM, reactive and predictive terrain warnings, sink-rate callouts, terrain display on the ND.
  • Data-driven cockpit views — each aircraft JSON lists the zones it has: overhead, left, centre, right, pedestal. An airliner has all five; a fighter has its two side consoles; a light aircraft has the pedestal.
  • Aircraft systems — fuel, electrical, hydraulics, battery state of charge, a generic engine-cooling heat balance (liquid or air-cooled, driven by real outside-air temperature), autobrake, speed brakes, parking brake.
  • Live radar — real flights via OpenSky Network, color-coded by destination, route lines to arrival airport, 150/400/1000nm range
  • Runs anywhere — laptop, tablet, Raspberry Pi, custom cockpit panels

Quick start

# Any static server works
python3 -m http.server 8080
open http://localhost:8080

No build step. No framework. No dependencies. Open index.html and fly.

First time? → docs/quickstart.md — the screens you'll see, a first flight to watch, a first takeoff of your own.


Controls

Key Action
↑ / ↓ Pitch up / down (ignored while the autopilot is engaged)
← / → Roll left / right · nosewheel steering on the ground
+ / − Throttle — thrust lever ±10% on turbofans, ±5 kt otherwise
t / T Trim nose up / nose down
z COM swap: active ↔ standby
E Engine start (cold-start aircraft)
Q Engine cutoff · fuel selector cycle (manual aircraft)
H Carburettor heat toggle
B Brakes (hold)
s Speed brake: RET → ARM → FULL
f / F Flaps extend / retract
g Gear toggle (squat switch: no gear-up on the ground)
1–5 Situation presets (disabled during active missions)
F1–F4 Thrust detents (aircraft-specific)
k Kneeboard (briefings + checklists)
n Mini map (heading, track made good, wind)
v Cycle view: instruments / combined / outside
c Cycle outside camera: cockpit fwd → chase → side → plume cam → booster cam → ship cam
o · l · m · r · d Cockpit views: overhead · left · centre · right · pedestal (where the aircraft has them)
Tab Cycle display mode
p Pause
x Audio on/off
j Jump — warp straight to the next mission event
r Cycle role: PF → PM → INSTRUCTOR (aircraft without a right console)
Space PTT (push to talk)
w / W Time warp — rockets + glass cockpits: 1× → 2× → 5× → 10× → 100× → next event (W steps back)
Esc Back to the mission selector
Ctrl+Shift+L Download flight telemetry (JSONL; CSV for rockets)
Ctrl+Shift+B Download the black box

G1000 (C172): Click any switch in the left panel to toggle it. Click the COM1 frequency in the PFD top bar to show/hide the COM panel.

Gamepad: Logitech Extreme 3D Pro out of the box. axes[0]=roll · axes[1]=pitch · axes[2]=rudder · axes[5]=throttle · buttons[1]=flaps · buttons[2]=gear


Aircraft included

Atmosphere

Aircraft Engine Notes
Airbus A350-900 Rolls-Royce Trent XWB HB-IFA, autopilot, FMGS
Airbus A340-300 CFM56-5C4 × 4 Edelweiss HB-JME — data-driven from airport-planning DWG
Boeing 777-300ER GE90-115B Singapore 9V-SWY — data-driven, stepped GE90 core nozzle
Boeing 737-800 CFM56-7B G-DOCB
Boeing 737 MAX 9 CFM LEAP-1B N932AK, scimitar winglets
Airbus A220-300 Pratt & Whitney PW1500G airBaltic livery, Airbus-style PFD/ND/ECAM
Embraer E190-E2 Pratt & Whitney PW1900G Helvetic Airways, E-Jets glass cockpit
Cessna 172S Skyhawk Lycoming IO-360 · 180hp G1000 glass cockpit, cold-dark startup, grass strip
Robin DR400/140B Dauphin Lycoming O-320 · 160hp Flugschule Grenchen checklists
Pipistrel Velis Electro HB-SYC Pipistrel E-811 · 57.6 kW EPSI panel, battery SOC management, Grenchen
Vought F4U-1A Corsair Pratt & Whitney R-2800 · 2000hp Bent-wing bird, Pacific theatre
Messerschmitt Bf 109 E-4 Daimler-Benz DB 601 · 1175hp AudioWorklet 12-cylinder impulse model, radiator flap + coolant temp
MiG-15 'Fagot' Klimov VK-1 Centrifugal compressor intake, splitter vane
Avro 504K Le Rhône 9J · 110hp Gyroscopic precession, rotary blip switch
Tupolev Tu-95MS Bear H Kuznetsov NK-12MV × 4 · 44740kW Russian crew voices, contra-rotation LFO
Antonov An-225 Mriya ZMKB Progress D-18T × 6 · 1 377 kN Ukrainian crew voices, 500 t, Hostomel 2022

Orbit

Vehicle Notes
Falcon 1 27 000 kg, 2-stage, RatSat payload, Omelek Island
Falcon 9 v1.0 333 400 kg, 9 Merlins, expendable — no grid fins, no landing legs
Falcon 9 Block 5 549 054 kg, RTLS booster recovery, grid fins, landing legs, MECO→SECO→Keplerian orbit
Falcon 9 Block 5 (590 km) Tuned for 590 km near-circular insertion, droneship (ASDS) booster recovery — Inspiration5
Starship / Super Heavy Full stack, Raptor sea-level + vacuum, engine skirt
Saturn V Apollo lunar stack, F-1 first stage, translunar injection, LM

Lab

Vehicle Notes
SO-101 Robot Arm 6-DOF arm visualisation
Yertle Quadruped Dog 12-joint quadruped visualisation

Data-driven airliners

Airliners here are not shaped by eye. Manufacturers publish airport-planning drawings (DWG) so airports can lay out gates and taxiways — every fuselage station, wing root, gear track and engine position dimensioned to the millimetre. OpenSim reads those numbers.

Each airliner JSON carries a dimensions block of real measurements, and the wireframe geometry is derived from it:

  • fuselage diameter sets the model scale
  • the wing-to-body fairing is a flat-bottomed super-ellipse from its DWG cross-section
  • landing gear from track / wheelbase / strut lengths
  • wing position from its root station — move it and the engines, pylons and flap-track fairings follow
  • the engine nacelle is a parametric builder — fan-cowl ratio, nacelle profile, stepped core nozzle — so a GE90 reads differently from a CFM56
  • cockpit windows as explicit polygons matched to the type

Truth in, truth out. Accuracy is intrinsic, and a wrong number shows up as a visibly wrong shape. The A340-300 HB-JME (Edelweiss) is the reference build; the 777-300ER and A350 follow the same method.


Data-driven airports

The same idea, one level up: an airport is not modelled by hand either. ICAO Annex 14 standardises how every airport is laid out — and the open data already maps it. So the entire ground environment is derived, not drawn:

  • runways from OurAirports (CC0) — thresholds, true bearing, width
  • taxiways from OpenStreetMap (ODbL) become a navigable graph — shared nodes are vertices, each way carries its designator (A, B, C…)
  • stands / gates from OSM aeroway=parking_position — the painted lead-in line gives the stop point and the nose-in heading for free
  • terminals + aprons from OSM aeroway=terminal footprints, extruded to wireframe massing
  • jet bridges reach from each gate to the nearest terminal wall; VDGS units, taxiway signs and lead-in lines all fall out of the geometry

Run scripts/build-*.py once to bundle a new airport's OSM data. Then you can fly an approach into an airport the sim has never seen — München, say — and the runway, your taxi-in route, the assigned gate, the VDGS and the taxiway signs are all there, because the standardisation is the model. The drawing is the compression; the sim decompresses it.


Gate-to-gate flying

One taxiway graph powers the entire ground phase, in both directions.

Departure — request pushback at your stand; a tug walks the aircraft back onto the taxiway. Ground gives a taxi clearance routed over the graph — "taxi to holding point runway 22 via Foxtrot, November" — the green route draws on the map, you hold short of and cross runways on request, then line up and go.

Arrival — after touchdown, vacate detection latches once you turn off the runway and slow to taxi speed. That unlocks the REQUEST → Taxi to gate call. Ground assigns a gate from the arrival dock (random within the dock, or a fixed stand) and reads the full clearance — "taxi to stand E27 via Foxtrot, Delta" — which lands on the kneeboard scratchpad while the green route leads you in. At the stand a VDGS shows your aircraft type, an azimuth dot tracking your offset from the lead-in centreline, the closing distance, and STOP at the parking line. ENG MASTER OFF and the turbofan coasts down by inertia to a descending spool-down whine.

Autobrake (LO/MED/MAX) is armed from pushbuttons on the centre panel and disarms when you touch the brakes. Brake-to-Vacate, the jet-bridge connect and brake temperature are the next links in the chain.


Missions included

Fly tab

Mission Aircraft Era What
ILS Approach LSZH RWY 28 A350 Modern San Francisco → Zürich, live METAR, ATC clearances, approach brief
Takeoff · Genève → München E190 Modern Cold start at gate 10, pushback, taxi to RWY 22 — then the first arrival at a brand-new airport: gate-to-gate into EDDM, VDGS docking
Cruise · Warsaw → Rīga A220 Modern FL350 inbound EVRA, live METAR, Air Baltic crew voices
Dock E · Zürich A340 Modern Edelweiss at a Dock E gate, engine start, pushback off the midfield satellite, taxi out
ILS Approach LEMD RWY 32L 737 MAX 9 Modern Final into Madrid Barajas, data-driven gate-to-gate (temporary — the EGLL 27L approach returns)
Bozeman → Anchorage 737 MAX 9 Modern Alaska, cold start at gate B7, depart over the Bridgers and the Rockies (temporary ILS 15 approach)
Singapore → London 777-300ER Modern Singapore Airlines at Changi, evening departure out over the Strait
Cross-Country LSZG→LSGN C172 PPL Cold-dark startup, Schnupperflug route, live METAR
VFR Pattern LSZF C172 PPL Grass strip Speck-Fehraltorf, circuits, kneeboard
VFR Circuit LSZG Robin DR400 PPL Grenchen, Flugschule checklists, live METAR
Electric Circuit HB-SYC Velis Electro PPL/Electric EPSI panel, battery SOC, no magnetos
Airshow Ground Run Bf 109 E-4 2025 DB 601 startup, D-FEML at Hahnweide
Patrol — Marne 1918 Avro 504K 1918 WWI rotary engine, Le Rhône blip switch
Operation Wolfskopf Bf 109 E-4 1942 Arctic, scripted engine failure, NIFLHEIM
The Wasp · Bougainville F4U-1A Corsair 1943 Pacific patrol, R-2800, ARC-5 radio
No Bomber Lost · Rabaul F4U-1A Corsair 1943 Ground attack, Rabaul harbour
Przechwycenie · Dęblin MiG-15 1955 Polish interceptor. Twelve years ago a Spitfire. Today a red fifteen
Aufklärungsflug Nordmeer Tu-95MS Bear H 1956 Olenya AB, Soviet ATC, Cold War dossier
Mriya — Die letzte Reise An-225 2022 Hostomel, Ukrainian ATC, 3 February 2022

Story missions (Wolfskopf) run with a fixed scenario and skip the scenario chooser.

Orbit tab

Mission Vehicle Year What
Apollo 8 — First to the Moon Saturn V 1968 Borman, Lovell, Anders. TLI, first crewed lunar orbit, Earthrise
Apollo 13 — Houston, We've Had a Problem Saturn V 1970 Oxygen tank explosion at 56 h. The LM becomes a lifeboat, free return home
Falcon 1 — Omelek Island Falcon 1 2008 First privately funded orbital rocket. 2-stage gravity turn, RatSat to LEO
CRS-1 — Engine Out Falcon 9 v1.0 2012 Engine failure at T+79s. Vehicle reaches orbit on 8 engines. Lofted ascent, no recovery
Crew Dragon Demo-2 Falcon 9 Block 5 2020 Behnken + Hurley. First crewed Dragon. Orbit-targeting guidance, boostback to LZ-1. Full webcast audio
IFT-12 — Starship V3 Debut Starship 2026 S39 / B19. One Raptor out on the ship, guidance extends the burn. Indian Ocean splashdown
IFT-13 — First Mechazilla Ship Catch Starship 2026 S40 / B20. Booster catch at Starbase, one orbit, reentry, ship catch attempt
Inspiration5 — Commander Leutwyler Falcon 9 Block 5 2030 Four civilians. 590 km orbit. Booster lands on the droneship. 3-day mission. Deorbit → reentry → splashdown

Lab tab

Mission Vehicle What
H2D · GPS Autonomy Test Markus' Demonstrator GPS autonomy
Workspace · Familiarisation SO-101 Robot Arm Arm visualisation, hardware-in-the-loop to an ESP32 via server/robot_bridge.js
Dog Lab · Visualisation Yertle Quadruped Dog Joint-by-joint visualisation

Live radar

Press Near me to fetch real flights via OpenSky Network. No account needed.

  • Range: 150nm (local) · 400nm (regional) · 1000nm (intercontinental)
  • Color coding: each destination airport gets a color. All flights going there share it.
  • Routes: callsign lookup via adsbdb.com — LSZH → JFK, ORD → EDDM
  • Click: spawn the sim at that aircraft's current position, altitude, and heading.

Physics model

OpenSim uses a real aerodynamic force balance — point-mass wind axes:

L = q × S × CL(α, flaps)
D = q × S × (CD₀(flaps) + k × CL²)
T = throttle × Tmax × ρ/ρ₀ × enginePower
W = mass × g

dv/dt  = (T·cos(α) − D − W·sin(γ)) / m
dγ/dt  = (L − W·cos(γ)) / (m·v) − 0.4·γ + trim × 0.0015

ISA density: ρ = 1.225 × (1 − 2.2558e⁻⁵ × alt_m)^4.2559

Angular inertia — PD controller with momentum (τ_roll = 0.18s, τ_pitch = 0.30s). Stall — high-alpha snap + energy stall (progressive sink at low speed). Gyroscopic precession — rotary engines precess when pitch or roll rate changes.


Rocket + orbital physics

Point-mass gravity turn, programmed FPA profile, extended ISA through 140 km. Thrust interpolated sea-level ↔ vacuum.

Orbit-targeting guidance — the upper stage steers to a target orbit and cuts off on velocity, not on a clock. Callouts fire on events, not timestamps. tools/booster-descent-sim.mjs simulates ascent and booster descent offline and reports each mission's reachability.

Staging — cold-staged vehicles show a visible separation gap during the coast (hot-stagers and the Saturn V don't). Upper-stage thrust spools up. Dragon separates from Stage 2 with drift and a Draco ΔV.

Orbital propagation — Velocity Verlet integrator in ECEF. Energy conserved < 0.01% over 30 minutes. Dragon / Stage 2 propagate independently after separation.

Deorbit + reentry — retrograde ΔV at deorbitT, drag below 140 km, drogue at 5 500 m, mains at 1 800 m, terminal ~6 m/s.

Booster recovery — flip → boostback → coast → entry burn → glide → landing burn, engine-first. Single engine proportional throttle v²/2h. Grid fins deploy after separation; 3D landing legs deploy over 5 s and cast a ground shadow. Two recovery modes, set per vehicle in the JSON:

  • RTLS — boostback to the landing zone (Demo-2 → LZ-1).
  • ASDS — no boostback; the booster lands on a droneship at the real landing point (Inspiration5). Predictive landing guidance, and a ship cam (mode 6) that shows the full booster coming down onto the deck.

The booster cam (mode 5) auto-activates during boostback, entry burn, landing burn, and landing, then restores the previous camera.

Time warp — w steps 1× → 2× → 5× → 10× → 100× → next mission event; j jumps straight to the next event. A 3-day Inspiration5 orbit passes in minutes.


G1000 glass cockpit (C172)

The Cessna 172 uses a three-zone canvas layout matching the real G1000 NXi installation:

┌─────────────┬───────────────────────┬───────────────────────┐
│ Switch panel│       PFD             │       MFD             │
│  (14%)      │  attitude · tapes     │  engine strip         │
│             │  HSI · ILS · COM      │  EGT/CHT/OIL · fuel  │
│  MASTER     │                       │  map overlay          │
│  AVIONICS   ├───────────────────────┴───────────────────────┤
│  FUEL PUMP  │   Analog backup: ASI · AI · ALT               │
│  MAGNETO    │   (always powered — vacuum / standby)         │
│  LIGHTS     │                                               │
└─────────────┴───────────────────────────────────────────────┘

Cold-dark startup sequence:

  1. MASTER BAT → ON
  2. AVIONICS → ON (powers both screens)
  3. FUEL PUMP → ON (boost pump audible)
  4. MAGNETO → click to cycle: OFF → R → L → BOTH → START
  5. START fires the engine lifecycle — whirr → catch → idle → running
  6. MAGNETO snaps back to BOTH when engine catches
  7. FUEL PUMP → OFF after engine running

COM panel: click the COM1 frequency in the PFD top bar to show/hide the full COM + transponder panel. Real mission frequencies from the mission JSON. Appears on the right side of the screen.


Sound

All engine sound is synthesised. No samples.

Layer How
DB 601 / IO-360 / Le Rhône AudioWorklet impulse model — cylinders fire at individual crankshaft angles
Lycoming startup lifecycle Electric starter whirr → catch → idle → running (3-phase, ~8s)
Fuel boost pump Dual sawtooth 241/256 Hz + bandpass noise 370 Hz + 11 Hz LFO, fade in/out
NK-12 turboprop 3.8Hz LFO contra-rotation beat + slewTime 1.8s
GTF / HBF / LBF Oscillator harmonics, engine-specific filter and gain
Wind White noise → bandpass, gain ∝ speed²
Ground creak Lowpass rumble, WoW × speed
Coolant hiss Rises as enginePower drops
Carb ice / heat Power reduction as ice builds; restoration on heat ON

See docs/db601-synthesis.md for the full DB 601 physical impulse model.


Audio chain — historically accurate comm

Every voice in a mission passes through the correct radio equipment for its era. The voice source and the comm chain are decoupled:

[voice source]           [commProfile chain]
ElevenLabs MP3      ──►  bandpass + presence boost
Archival recording  ──►  noise floor + crackle
H4n Pro WAV         ──►  carrier hum + squelch tail  ──►  speakers
Web Speech TTS      ──►
                    ↑
          environment bleed
          (engine tap from sound.js)

commProfile presets

Profile Era Character
vhf-aviation Standard ATC 118–137 MHz Bandpass 350–3400 Hz, presence boost, squelch tail
tower-quiet Ground station TX Cleaner — quiet room, good equipment
sband-apollo NASA S-band MSFN More hiss — 380 000 km signal path
vhf-vostok Soviet VHF 1961 Narrow, harsh, heavy noise floor
ip-spacex SpaceX IP backbone Near-phone quality, minimal processing

Environment bleed

Cockpit profiles tap the live engine output and mix it into received comms. A Bf 109 pilot hears ATC with DB 601 underneath. A Dragon crew hears CAPCOM with Merlin rumble during ascent.

Voice sources

Three tiers, all through the same chain:

  • ElevenLabs MP3 — pre-generated character voices (e.g. Ukrainian ATC: Olena voice)
  • Archival recording — real mission audio. NASA audio is public domain. SpaceX webcasts.
  • Own recording — Zoom H4n Pro, 24-bit WAV. For Inspiration5: Markus, Lydia, Pradeep, and MS2 record their own lines. The actual crew, in the actual simulator, years before launch.

Mission JSON

{
  "commProfile": "vhf-aviation",
  "atcClearances": [
    { "t": 5, "audio": "audio/hostomel/atc_olena.mp3" },
    { "t": 8, "text": "Мрія, запуск двигунів дозволено.", "voice": "atc" }
  ]
}

If an audio: file is missing, the mission falls back to TTS automatically.

See docs/audio-chain.md for full documentation including spectral analysis results.


Crew voices (TTS)

Five independent voices, each with distinct character:

Voice key Role Character
crew CDR (Pilot Flying) Daniel — calm, authoritative
pm PLT (Pilot Monitoring) Karen — professional, precise
atc CAPCOM / ATC Gordon — official radio
narrator Webcast host (John) Natural pace, technical
narrator2 Webcast host (Lauren) Enthusiastic, human moments

Crew language set per aircraft via "crewLang": "ru-RU". Every utterance — GPWS, PM callouts, ATC clearances — in that language.

Named rocket events: supersonic · maxq · ceco · meco · stagesep · seco · orbit · booster_flip · booster_boostback · booster_landing · deorbit · blackout · signal · drogue · mains · splashdown


Hardware ecosystem

OpenSim streams live sim state over WebSocket from a Raspberry Pi hub. Any device on the network can consume it.

Physical cockpit mockup — four screens, four seats, each a browser tab. Build the frame from wood and 3D-printed panels. FabLab Winti has the tools. The software is already there.

6-DOF motion platform — G-force, pitch, roll, vertical acceleration are computed every tick. Publish the WebSocket format, makers wire their platform to the data stream. MaxQ pushes you back. Stage sep: weightlessness.

Physical instruments — ESP32 reads WebSocket state keys (S.alt, S.spd, S.hdg...) and drives stepper motors. 3D print the bezels, wire the needles. Altimeter, airspeed, VSI, RPM — all physical, all driven by the same physics engine.

The software is the platform. The hardware is the expression. MIT open source means anyone can build.


Structure

core/
  state.js                    — single source of truth, all sim state
  loop.js                     — rAF loop + tickSim(dt), the one simulation step (the test API's simStep runs it too)
  physics.js                  — aerodynamic force balance, ground roll, brakes/autobrake, CFIT, cooling
  thrust.js                   — engine thrust models
  rocket.js                   — gravity turn, orbit-targeting guidance, staging, RTLS/ASDS, propagator, reentry
  mission.js                  — loads aircraft + mission JSON, live METAR fetch
  lifecycle.js                — mission reset registry: modules register their reset, loadMission runs them
  random.js                   — simulation random numbers (turbulence), seeded in test mode
  vocab.js                    — the names data and code share (triggers, panels, engine sounds, …); typos throw
  schema/                     — data schemas for missions, catalog, aircraft; checked by npm test and at load
  mission-start.js            — named mission start positions (gates, runways)
  catalog.js                  — mission picker catalogue, loaded from missions/catalog.json
  aircraft-config.js          — aircraft JSON → derived config
  route.js                    — buildFullRoute: SID + airways + STAR + approach — one route for every consumer
  airway-graph.js             — en-route airway network
  lnav.js · vnav.js           — lateral + vertical navigation, leg sequencing
  managed-speed.js · fma.js   — managed speed targets, flight-mode annunciation logic
  baro.js                     — barometric altimeter / QNH
  taxi-graph.js               — taxiway network graph + routing, derived from OSM
  pushback.js                 — pushback path
  fuel.js · electrical.js · hydraulics.js · battery.js — aircraft systems
  failures.js                 — scripted failure event processor
  crew.js                     — five voices, rocket events, GPWS/EGPWS, language-aware, radio dispatch
  radio.js                    — commProfile chain: createRadioChain(), playThroughChain()
  sound.js                    — procedural engine audio, startup lifecycle, engine bleed tap
  *-processor.js              — AudioWorklets: DB 605, Le Rhône, Lycoming, R-2800, radio crackle
  input.js                    — keyboard · mouse · Gamepad API
  liveflight.js               — live radar (OpenSky) → spawn into a real flight
  hil.js                      — hardware-in-the-loop bridge
  telemetry.js · blackbox.js  — flight recorder (2 Hz JSONL) + black box

app/
  session.js                  — mission session: listeners/timers a mission registers; stop() removes them (next mission, Esc/Back)

display/
  pfd.js · pfd_instruments.js — PFD + reusable instrument primitives (attitude, tape, HSI, FMA)
  panel_renderer.js           — drives Airbus PFD/ND/ECAM and E190 PFD/ND from panel JSON
  ecam.js · fma.js            — ECAM pages, FMA
  overhead.js · leftconsole.js · centerconsole.js · rightconsole.js · pedestal.js
                              — data-driven cockpit views (O / L / M / R / D)
  pushbutton.js               — generic Airbus pushbutton
  smooth.js                   — shared display-lag smoother (per-quantity time constant)
  g1000.js                    — Garmin G1000: PFD, MFD, engine strip, switch panel, backup gauges
  bf109.js · f4u1a.js · velis_epsi.js · clock.js — steam-gauge panels, EPSI, cockpit clock
  dragon.js · rocket_display.js · dsky.js · lm_display.js
                              — Dragon crew seats, SpaceX telemetry, Apollo DSKY + LM
  cislunar.js · earthrise.js  — cislunar trajectory view, Earthrise
  kneeboard.js                — briefings, checklists, scratchpad, approach + missed approach
  map.js                      — world map (rocket) + local mini-map + vehicle silhouettes
  terrain.js                  — 3D outside view: Terrain-RGB, day/night sky, stars, water, space
  terrain-color.js · night-lights.js — Blue Marble day colour, VIIRS night glow
  outside.js                  — 3D wireframe renderer: painter's algorithm, flat shading, Canvas 2D
  outside-*.js                — per-family geometry (warbirds, widebody, rocket, space) + draw helpers
  com.js                      — COM radio + transponder
  robot_arm.js · yertle_quadruped.js — Lab visualisations
  *-data.js                   — bundled data: runways, taxiways, stands, terminals, towers, navaids,
                                airways, procedures, satellites, windsocks
  svg/                        — vehicle silhouettes

panels/          — panel layout JSON: airbus-pfd/nd/ecam, e190-pfd/nd, g1000, dr400
aircraft/        — JSON vehicle definitions
missions/        — JSON mission definitions + catalog.json
audio/           — voice assets (not in git — generate locally, see docs/audio-chain.md)

docs/
  architecture.md       — how the pieces fit together
  url-routing.md        — mission URLs, deep links, browser history
  panel-system.md       — panel JSON + renderer
  creating-missions.md  — writing a mission
  keybindings.md        — full key reference
  db601-synthesis.md    — DB 601 physical impulse model, all parameters
  sound-calibration.md  — engine sound calibration
  audio-chain.md        — radio chain architecture, commProfile presets, pipeline

scripts/
  build-*.py            — bundle open data: runways, taxiways, stands, terminals, towers,
                          navaids, navdata, airways, CIFP procedures, satellites
  rescale-aircraft.py   — rescale aircraft geometry to real dimensions
  render-*.mjs          — offline engine synthesis (DB 601, R-2800) → WAV
  analyze-*.py          — spectrograms: DB 601 startup, R-2800, radio chain

tools/
  booster-descent-sim.mjs — ascent + booster descent simulation, guidance + reachability

tests/           — Node unit tests (*.test.mjs / *.test.js) + Playwright specs (*.spec.js)

server/
  hub.js          — WebSocket hub (Node.js, runs on Raspberry Pi)
  robot_bridge.js — hub ↔ SO-101 ESP32 bridge

Testing

npm install
npx playwright install chromium
npm test

npm test runs the Node unit tests first (tests/*.test.mjs, 113 tests, including a schema check of every mission, catalog entry and aircraft), then the Playwright browser specs (165 tests in 13 files), all headless: physics, fuel/engine/carb heat, thrust, sound synthesis and state machines, COM radio, FMA, managed speed, route building, VNAV, aircraft data, rocket staging and orbital mechanics. Runs are repeatable: in test mode simStep is the only clock and turbulence is seeded. Calibration specs run separately with npm run calibrate.

Running subsets, reading the output, the ?test=1 API, writing tests and the current known failures → docs/testing.md.


Add an aircraft

{
  "id": "your-aircraft",
  "name": "Your Aircraft",
  "crewLang": "de-DE",
  "envelope": { "cruiseSpd": 122, "maxSpd": 163 },
  "performance": {
    "mass": 1157, "wingArea": 16.2, "thrustMax": 1800,
    "CL_0": 0.2, "CL_alpha": 5.0, "CL_max": 1.9,
    "CD_0": 0.028, "inducedK": 0.055, "Vr": 55
  },
  "handling": { "rollRate": 30, "pitchRate": 5, "maxBank": 60 },
  "sound": { "engineType": "lycoming-o360" }
}

Add a mission

{
  "id": "your-mission",
  "aircraft": "aircraft/your-aircraft.json",
  "commProfile": "vhf-aviation",
  "weather": { "source": "live", "icao": "LSZH" },
  "initialState": { "lat": 47.39, "lon": 8.78, "alt": 1788, "spd": 0, "hdg": 260 },
  "departure": { "name": "Your Airfield", "elevation": 1788 },
  "atcClearances": [
    { "t": 10, "audio": "audio/your-mission/atc_line1.mp3" },
    { "t": 30, "text": "Radar contact.", "voice": "atc" }
  ],
  "failures": [
    { "trigger": { "type": "time", "t": 120 }, "type": "engine_power", "value": 0.0, "rampTime": 60 }
  ]
}

Telemetry

Every flight recorded automatically. Ctrl+Shift+L downloads JSONL (CSV for rockets); Ctrl+Shift+B downloads the black box.

{"t":48.6,"alt":1789,"spd":68.7,"vs":11,"pitch":9.06,"roll":0,"hdg":260,
 "enginePower":1,"flaps":0,"lat":47.385,"lon":8.776}

Feed to pandas, plot, debrief approaches, or stream to an AI co-pilot.


Training

OpenSim is a real training tool. Not a game with training features — a training tool that happens to run in a browser.

How it works

Every aviation mission has a scenario setup screen before you fly. Choose your conditions:

Scenario What happens
CLEAN Normal flight. Practice circuits, navigation, communication.
PARTIAL Engine degrades to 50% power after 60–300 seconds. Partial power emergency.
ROUGH Engine bang + 30% power. Forced landing required.
FAILURE Full engine failure. Glide, pick a field, land it.

Timing is random (60–300s) or fixed. You set it up, then forget it. The failure comes when it comes.

What gets scored

After every flight — including crashes — the debrief shows two blocks:

Emergency Response (if a failure occurred)

  • Survived
  • Best glide speed — did you pitch for 65kt within seconds of the failure?
  • Squawk 7700 — how many seconds after the failure?
  • 121.5 tuned — how many seconds after the failure?
  • Mayday called — did you key the mic?

Approach Data (every landing)

  • Runway alignment — heading deviation in degrees
  • Speed at touchdown — vs target approach speed
  • Touchdown point — distance from threshold

The priority order

Aviate → Navigate → Communicate

In an emergency: pitch for best glide first. Find a field. Then squawk 7700 — one knob, passive, radar sees you immediately. Then tune 121.5 and call Mayday.

When you tune 121.5 during an engine failure, virtual ATC responds:

"HB-CBX, Mayday acknowledged. Say position and souls on board."

That's the training. Do it enough times and the hands move before the brain catches up.

The kneeboard

Press K to open the kneeboard. Every aircraft has:

  • Departure briefing
  • Normal checklists (startup through shutdown)
  • Emergency checklists — engine failure, partial power, engine fire

In a C172 engine failure:

  1. Best glide — 65kt
  2. Field — select, into wind
  3. Fuel selector — BOTH
  4. Mixture — rich
  5. Carb heat — ON
  6. Throttle — full, then back to idle
  7. If no restart: Mayday on 121.5, squawk 7700

The philosophy

You don't rise to the occasion. You fall to your training.

Sim crashes are ones you walk away from. Run the engine failure scenario until the checklist runs itself. That's chair flying with feedback.

A 40-million-franc certified simulator trains the same reflex. OpenSim runs in a browser, costs nothing, and sends you a scored debrief.

For instructors

Send the student a URL the night before a lesson. Assign a scenario — ROUGH, fixed timing 120s. Student flies three circuits, gets three debriefs. They arrive having already run the emergency. Ground time becomes review, not introduction.

The debrief scores are honest. "Squawk 7700 — not set" is not an opinion. It happened, or it didn't.


Vision

  • PPL(A) training — circuits at LSZF and LSZG
  • Kitfox electric digital twin — the sim IS the avionics
  • Time machine — 1918 · 1942 · 1956 · Apollo 11 · Challenger · Demo-2
  • FabLab cockpits — anyone with a laser cutter and a Bambu A1 builds a Dragon capsule
  • Real crew training — Inspiration5 crew records their actual voices on an H4n Pro, years before launch
  • Ghost aircraft replay — record instructor flight as JSONL, student flies alongside
  • Hardware panels — RPi WebSocket bridge, ESP32 instruments, 6-DOF motion

Why

Because a 40-million-franc simulator should not be the only way to train crew. Because anyone on earth with a browser should be able to fly. Because the same URL that runs on a MacBook runs on a Raspberry Pi in a FabLab in Nairobi. Because somewhere in the permafrost near Titovka, a man is still waiting to be found.


Related projects

VotingTriad — Airbus-style envelope protection on three LilyGo T-CAN485 nodes (ESP32 + onboard CAN transceiver). BNO055 IMU + BMP390 barometer per node. Three nodes vote on vehicle state at 50 Hz: 3/3 → Normal Law · 2/3 → Degraded · 1/3 → Direct Law. CRSF parser for ExpressLRS at 420000 baud, RS485 fallback with time-division multiplexing if CAN goes down. Connects to OpenSim's HIL bridge over WebSocket — real RC sticks drive a simulated aircraft through the actual flight computer. An iron-bird rig on a breadboard.


Data sources

Geographic data, fetched live or bundled from open datasets:

  • OurAirports — runway thresholds, dimensions and designations (public domain). Bundled for mission airports in data/runways-data.js; regenerate with scripts/build-runways.py. Also navaids and airport frequencies (scripts/build-navaids.py, scripts/build-navdata.py).
  • OpenStreetMap — runways, taxiways, aprons, holding positions, parking stands, terminal footprints and control towers via the Overpass API (© OpenStreetMap contributors, ODbL).
  • FAA CIFP and X-Plane nav data — SIDs, STARs, approaches and airways for the mission airports (scripts/build-cifp.py, scripts/build-airways.py).
  • Mapbox — terrain elevation (Terrain-RGB / Copernicus DEM) and water polygons.
  • Natural Earth — 1:50m world coastlines for the briefing's route and SID/STAR charts (public domain). Bundled in data/coastlines.js; regenerate with scripts/build-coastlines.py.
  • NASA Blue Marble (day ground colour) and VIIRS / Black Marble 2016 (night lights) — public domain.

License

MIT © 2026 Markus Leutwyler Built with Claude Code by Anthropic.


Developed with Claude. Things happen there you could not imagine.

About

Open-source browser simulation engine. Any vehicle is a JSON file. Any mission is a JSON file.

Resources

Code of conduct

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages