Skip to content

Quick start ​

Get started with radarcontrol.io in 5 minutes. Want background on ATC concepts first? See the Learn ATC guides.

Your first script ​

When you open radarcontrol.io, you'll see the default script already loaded. Here's what it does:

javascript
onSpawn((aircraft) => {
  log(`${aircraft.cs} (${aircraft.type}) at FL${aircraft.altFL}`);

  // Set up handover at exit
  aircraft.over(aircraft.plan.exitPoint, (ac) => {
    ac.handover();
  });
});

This code:

  1. Logs when each overflight aircraft spawns from entry points
  2. Sets up automatic handover when aircraft reach their exit point

Note: Aircraft spawn from two sources: entry points (overflights at cruise altitude) and airports (departures). Overflights trigger onSpawn, while departures trigger onDepartureControllable when they reach 10,000ft and become controllable.

Loading your script ​

Press Ctrl+Enter or click "Load Script" to run your code.

Basic traffic management ​

Let's add some actual traffic management. Replace the default script with this:

javascript
// Handle overflights entering from entry points
onSpawn((aircraft) => {
  // Climb to cruise altitude
  aircraft.climb(fl(aircraft.plan.cruiseFL));

  // Set cruise speed
  aircraft.speed(420);

  // Direct to exit point
  aircraft.direct(aircraft.plan.exitPoint);

  // Auto-handover at exit
  aircraft.over(aircraft.plan.exitPoint, (ac) => {
    ac.handover();
  });
});

// Handle departures when they become controllable at 10,000ft
onDepartureControllable((aircraft) => {
  log(`${aircraft.cs} checking in`);

  // Give climb clearance
  aircraft.climb(fl(aircraft.plan.cruiseFL));
  aircraft.speed(420);

  // Route to exit
  aircraft.direct(aircraft.plan.exitPoint);

  aircraft.over(aircraft.plan.exitPoint, (ac) => {
    ac.handover();
  });
});

onTick(({ traffic }) => {
  const flights = traffic.all();

  // Maintain spacing with speed control
  for (let i = 0; i < flights.length - 1; i++) {
    const lead = flights[i];
    const trail = flights[i + 1];

    const dist = distance(trail.pos, lead.pos);

    if (dist < 8) {
      // Too close - slow down
      trail.speed(Math.max(lead.targetIASKts - 30, 320));
    }
  }
});

Load it and watch the sim handle traffic on its own.

Understanding the code ​

onSpawn() ​

Called when overflight aircraft enter your sector from entry points (already at cruise altitude). Use it for initial clearances:

javascript
onSpawn((aircraft) => {
  // aircraft has properties: cs, type, altFL, plan, etc.
  // aircraft has methods: climb(), speed(), direct(), etc.
});

onDepartureControllable() ​

Called when departure aircraft reach 10,000ft and become controllable. Departures spawn from airports and are uncontrollable during initial climb-out:

javascript
onDepartureControllable((aircraft) => {
  // Departure just checked in - give climb clearance
  aircraft.climb(fl(aircraft.plan.cruiseFL));
  aircraft.speed(420);
});

onTick() ​

Called every ~0.5 seconds. Use it for continuous management:

javascript
onTick(({ traffic, time, weather, fixes }) => {
  // Access all aircraft: traffic.all()
  // Get specific aircraft: traffic.byCallsign("AAL123")
});

Aircraft control methods ​

Control aircraft using method chaining:

javascript
aircraft
  .climb(fl(350))      // Climb to FL350
  .speed(420)          // Speed 420 knots
  .direct("KMART");    // Direct to KMART

Common patterns ​

Vertical separation ​

javascript
onTick(({ traffic }) => {
  const flights = traffic.all();

  for (let i = 0; i < flights.length - 1; i++) {
    const a = flights[i];
    const b = flights[i + 1];

    const lateral = distance(a.pos, b.pos);
    const vertical = Math.abs(a.altFt - b.altFt);

    // If lateral separation is tight, ensure vertical
    if (lateral < 5 && vertical < 1000) {
      a.climb(a.altFt + 2000);
    }
  }
});

Conflict resolution ​

javascript
onConflict((pair) => {
  const acA = traffic.byCallsign(pair.a);
  const acB = traffic.byCallsign(pair.b);

  if (acA && acB) {
    // Climb the higher aircraft
    if (acA.altFt > acB.altFt) {
      acA.climb(acA.altFt + 2000);
    } else {
      acB.climb(acB.altFt + 2000);
    }
  }
});

Waypoint actions ​

javascript
onSpawn((aircraft) => {
  // Descend before reaching waypoint
  aircraft.before("KMART", 30, (ac) => {
    ac.descend(fl(240));
  });

  // Change speed at waypoint
  aircraft.over("MERGE", (ac) => {
    ac.speed(320);
  });

  // Ensure altitude constraint
  aircraft.reach("EXIT").altitude(fl(240));
});

Debugging ​

Use log() to output messages to the activity panel:

javascript
log(`${aircraft.cs} is at FL${aircraft.altFL}`);
log(`Distance: ${dist.toFixed(1)}nm`);
log(`Conflict between ${pair.a} and ${pair.b}`);

The activity panel at the bottom shows all your log messages and errors.

Interactive mode ​

Want to take direct control of aircraft? Switch to Interactive mode using the tabs at the top!

In Interactive mode, you can:

  • Click aircraft to select them
  • Type instructions like AAL123 cfl200 s400 dr KMART
  • Use buttons for quick altitude, speed, and routing instructions
  • Control aircraft just like a real air traffic controller!

Tip: Hover the Spawn button for the traffic intensity slider - 0% (no auto-spawn) to 100% (max traffic rate).

Watch for readback errors

Just like in real ATC, pilots occasionally make readback errors. Listen carefully to what they read back - if a pilot reads back the wrong altitude or heading, you'll need to correct them!

See the Interactive Instructions reference for all available instructions.

Next steps ​