OMEN Scenario JSON Schema

Multi-vehicle engagement scripting for the --scenario flag.


Usage

# By short name (resolves to assets/scenarios/<name>.json)
./deadeye --omen --scenario f16_snowflake_dogfight

# By full path
./deadeye --omen --scenario /path/to/my_scenario.json

The --scenario flag implies --omen --cot automatically.


Top-Level Structure

{
  "name": "string (required)",
  "description": "string (optional)",
  "origin": { ... },
  "sim_duration_sec": 90,
  "vehicles": [ ... ],
  "events": [ ... ]
}
Field Type Required Description
name string yes Scenario identifier
description string no Human-readable description
origin object yes WGS84 origin for the NED frame
sim_duration_sec number no Total simulation time (for UI scrub bar)
vehicles array yes List of vehicle definitions
events array no Time-triggered events (missile launches, etc.)

Origin

"origin": {
  "lat": 34.51,
  "lon": -110.08,
  "alt_ft": 15000
}
Field Type Required Description
lat number yes Latitude in decimal degrees
lon number yes Longitude in decimal degrees
alt_ft number yes Altitude MSL in feet (defines NED zero)

All vehicle positions are relative to this origin in NED coordinates (feet).


Vehicles

{
  "id": "blue-1",
  "callsign": "VIPER01",
  "affiliation": "friendly",
  "ownship": true,
  "airframe": "src/omen/dynamics/airframes/F16_SL.json",
  "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
  "initial": {
    "north_ft": 0,
    "east_ft": -30380,
    "alt_ft": 15000,
    "heading_deg": 90,
    "speed_kt": 400
  },
  "evasion": {
    "type": "hard_break_roll",
    "break_turn_deg": 90,
    "break_duration_sec": 3.0,
    "barrel_roll_duration_sec": 2.0
  }
}
Field Type Required Description
id string yes Unique identifier (referenced by events)
callsign string yes CoT callsign shown on map
affiliation string yes "friendly", "hostile", "neutral", or "unknown"
ownship boolean yes Exactly one vehicle must be true (drives HUD + camera)
airframe string yes Path to airframe JSON (relative to project root)
autopilot string yes Path to autopilot JSON
mission string no Path to mission JSON (waypoint route, etc.). If omitted, uses null mission (holds initial state)
initial object yes Initial NED state
evasion object no Defensive maneuver definition
formation object no Formation station-keeping definition (follows a leader)

Initial State

Field Type Required Description
north_ft number yes North position relative to origin (ft)
east_ft number yes East position relative to origin (ft)
alt_ft number yes Altitude above origin (ft)
heading_deg number yes Initial heading (degrees true)
speed_kt number yes Initial airspeed (knots)

Evasion

Triggered automatically when a missile is launched at this vehicle.

Field Type Required Description
type string yes "hard_break_roll" (only supported type currently)
break_turn_deg number no Break turn magnitude (default: 90°)
break_duration_sec number no Duration of the break turn (default: 3.0s)
barrel_roll_duration_sec number no Duration of the barrel roll (default: 2.0s)

Evasion state machine: IDLE → BREAK (hard turn) → ROLL (barrel roll) → RECOVERED

Formation

Maintains a fixed offset relative to a leader vehicle. The offset is in the leader's body frame (rotated by the leader's heading each frame so the wingman turns with the leader).

"formation": {
  "leader": "blue-1",
  "offset_north_ft": 0,
  "offset_east_ft": 500,
  "offset_alt_ft": 0
}
Field Type Required Description
leader string yes Vehicle id of the formation leader
offset_north_ft number no Body-frame offset: ahead of leader (ft, default 0)
offset_east_ft number no Body-frame offset: right of leader (ft, default 0)
offset_alt_ft number no Altitude above leader (ft, default 0)

Common formations:

The wingman's guidance automatically tracks the leader's heading and airspeed. When the leader turns, the wingman follows. The leader can fly any mission type (waypoint, hold, scripted).


Events

{
  "time_sec": 5.0,
  "type": "launch_missile",
  "launcher": "blue-1",
  "target": "red-1",
  "weapon": "src/omen/dynamics/airframes/AIM9X.json",
  "autopilot": "assets/autopilots/pronav_AIM9X.json",
  "callsign": "AIM9X-1"
}
Field Type Required Description
time_sec number yes Minimum simulation time before the event can fire
type string yes Event type (currently only "launch_missile")
launcher string yes Vehicle id that launches the weapon
target string yes Vehicle id being targeted
weapon string yes Airframe JSON for the weapon
autopilot string yes Autopilot JSON for the weapon
callsign string yes CoT callsign for the weapon track
condition object no Conditional trigger (event fires when BOTH time_sec has elapsed AND condition is met)

Conditional Events

Events can optionally include a condition block. When present, the event fires only when both time_sec has elapsed AND the condition is satisfied. Without a condition, the event fires purely on time.

{
  "time_sec": 0,
  "type": "launch_missile",
  "condition": {
    "type": "range_lt",
    "vehicle_a": "blue-1",
    "vehicle_b": "red-1",
    "value_ft": 30000
  },
  "launcher": "blue-1",
  "target": "red-1",
  "weapon": "src/omen/dynamics/airframes/AIM9X.json",
  "autopilot": "assets/autopilots/pronav_AIM9X.json",
  "callsign": "AIM9X-1"
}
Field Type Required Description
type string yes Condition type (see table below)
vehicle_a string yes* First vehicle id (*required for all condition types)
vehicle_b string yes* Second vehicle id (*required for range conditions)
value_ft number yes Threshold value (feet for altitude/range, seconds for time_after)

Condition Types

Type Description
range_lt Fires when 3D range between vehicle_a and vehicle_b is less than value_ft
range_gt Fires when 3D range between vehicle_a and vehicle_b is greater than value_ft
alt_below Fires when vehicle_a's altitude (above origin) drops below value_ft
alt_above Fires when vehicle_a's altitude (above origin) rises above value_ft
time_after Fires when simulation time exceeds value_ft seconds (redundant with time_sec but explicit)

Event Types

Type Description
launch_missile Spawns a new 6DOF missile from the launcher's position, guided by ProNav toward the target. If the target has an evasion block, it triggers automatically.

Available Airframes

Name Path Type Notes
F-16C src/omen/dynamics/airframes/F16_SL.json stevens_lewis_f16 Supersonic fighter, relaxed static stability
GTM T2 src/omen/dynamics/airframes/GTM_T2.json gtm_t2 Generic Transport Model (subsonic)
AIM-9X src/omen/dynamics/airframes/AIM9X.json missile Short-range air-to-air missile
Simple Arrow src/omen/dynamics/airframes/simple_arrow.json gtm_t2 + plugin SDK v2 reference vehicle

Available Autopilots

Name Path Best For
GTM Cascade PID assets/autopilots/cascade_pid_GTM_T2.json GTM transport
F-16 Cascade PID assets/autopilots/cascade_pid_F16.json F-16 (alt hold)
F-16 Hdg Hold assets/autopilots/cascade_pid_F16_hdg_hold.json F-16 (heading + alt)
AIM-9X ProNav assets/autopilots/pronav_AIM9X.json Missile intercept

Example: Two F-16s Head-On Merge

{
  "name": "f16_snowflake_dogfight",
  "description": "Two F-16s head-on at 10 nm, Blue launches AIM-9X at t=5s",
  "origin": { "lat": 34.51, "lon": -110.08, "alt_ft": 15000 },
  "sim_duration_sec": 90,
  "vehicles": [
    {
      "id": "blue-1", "callsign": "VIPER01", "affiliation": "friendly",
      "ownship": true,
      "airframe": "src/omen/dynamics/airframes/F16_SL.json",
      "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
      "initial": { "north_ft": 0, "east_ft": -30380, "alt_ft": 15000,
                   "heading_deg": 90, "speed_kt": 400 }
    },
    {
      "id": "red-1", "callsign": "BANDIT01", "affiliation": "hostile",
      "ownship": false,
      "airframe": "src/omen/dynamics/airframes/F16_SL.json",
      "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
      "initial": { "north_ft": 0, "east_ft": 30380, "alt_ft": 15000,
                   "heading_deg": 270, "speed_kt": 400 },
      "evasion": { "type": "hard_break_roll", "break_turn_deg": 90 }
    }
  ],
  "events": [
    {
      "time_sec": 5.0, "type": "launch_missile",
      "launcher": "blue-1", "target": "red-1",
      "weapon": "src/omen/dynamics/airframes/AIM9X.json",
      "autopilot": "assets/autopilots/pronav_AIM9X.json",
      "callsign": "AIM9X-1"
    }
  ]
}

Example: Formation Flight

{
  "name": "f16_formation",
  "description": "Two F-16s in echelon right formation on a waypoint route",
  "origin": { "lat": 34.51, "lon": -110.08, "alt_ft": 15000 },
  "sim_duration_sec": 300,
  "vehicles": [
    {
      "id": "blue-1", "callsign": "VIPER01", "affiliation": "friendly",
      "ownship": true,
      "airframe": "src/omen/dynamics/airframes/F16_SL.json",
      "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
      "mission": "assets/missions/f16_formation_leader_route.json",
      "initial": { "north_ft": 0, "east_ft": 0, "alt_ft": 15000,
                   "heading_deg": 0, "speed_kt": 400 }
    },
    {
      "id": "blue-2", "callsign": "VIPER02", "affiliation": "friendly",
      "ownship": false,
      "airframe": "src/omen/dynamics/airframes/F16_SL.json",
      "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
      "initial": { "north_ft": 0, "east_ft": 500, "alt_ft": 15000,
                   "heading_deg": 0, "speed_kt": 400 },
      "formation": { "leader": "blue-1",
                     "offset_north_ft": 0, "offset_east_ft": 500, "offset_alt_ft": 0 }
    }
  ],
  "events": []
}

Example: Conditional Missile Launch (Range-Based)

{
  "name": "range_triggered_launch",
  "description": "AIM-9X launches when Blue and Red close to within 30,000 ft",
  "origin": { "lat": 34.51, "lon": -110.08, "alt_ft": 15000 },
  "sim_duration_sec": 90,
  "vehicles": [
    {
      "id": "blue-1", "callsign": "VIPER01", "affiliation": "friendly",
      "ownship": true,
      "airframe": "src/omen/dynamics/airframes/F16_SL.json",
      "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
      "initial": { "north_ft": 0, "east_ft": -50000, "alt_ft": 15000,
                   "heading_deg": 90, "speed_kt": 400 }
    },
    {
      "id": "red-1", "callsign": "BANDIT01", "affiliation": "hostile",
      "ownship": false,
      "airframe": "src/omen/dynamics/airframes/F16_SL.json",
      "autopilot": "assets/autopilots/cascade_pid_F16_hdg_hold.json",
      "initial": { "north_ft": 0, "east_ft": 50000, "alt_ft": 15000,
                   "heading_deg": 270, "speed_kt": 400 },
      "evasion": { "type": "hard_break_roll" }
    }
  ],
  "events": [
    {
      "time_sec": 0,
      "type": "launch_missile",
      "condition": {
        "type": "range_lt",
        "vehicle_a": "blue-1",
        "vehicle_b": "red-1",
        "value_ft": 30000
      },
      "launcher": "blue-1",
      "target": "red-1",
      "weapon": "src/omen/dynamics/airframes/AIM9X.json",
      "autopilot": "assets/autopilots/pronav_AIM9X.json",
      "callsign": "AIM9X-1"
    }
  ]
}

Notes

Wind

Each vehicle has a wind field for simple constant wind (optional):

"wind": {
  "speed_kt": 20,
  "from_deg": 270
}

This sets a steady-state wind using meteorological convention (direction wind blows FROM). For high-fidelity turbulence, gusts, and wind shear, use the full MIL-F-8785C Von Karman model in src/world/std_wind.h (StdWind::WindModel_t) which supports light/moderate/severe turbulence intensity levels, altitude-dependent scale lengths, discrete wind shear, and the NRL HWM14 horizontal wind model.

Vignette event stream

A --vignette run publishes one record per thing that happens and, when asked, appends each to a JSONL file: one complete JSON object per line, no line breaks inside it. This is what the on-screen log reads, what the sound bridge keys off, and what an external scorer subscribes to; the field set below is fixed.

Field Type Meaning
kind string spawn, lase, fire, impact, hit, miss, kill, call_for_fire, reload, withdraw, run_end
t_sec number Simulation time of the event, seconds from the start of the run
unit string The unit the event belongs to (the shooter, the spotter, the unit placed)
target string The target, where there is one; otherwise ""
round string The round type, where there is one; otherwise ""
ecef_m [x, y, z] Where it happened, ECEF meters (the truth)
lat_deg, lon_deg, alt_m numbers The same place geodetic, so a reader need not convert
range_m number Shooter-to-target range at the time, where it applies
tof_sec number The round's time of flight, where it applies
ph, pk numbers The probabilities the shot was taken under (0 when the table is unset)

Fields that do not apply to a kind are present with their zero values, so every line has every field. Example:

{"alt_m":712,"ecef_m":[-2400000,-4500000,3600000],"kind":"fire","lat_deg":35.33,"lon_deg":-116.47,"ph":0.88,"pk":0.8,"range_m":1850,"round":"m829","t_sec":12.25,"target":"R1","tof_sec":1.32,"unit":"A11"}