Skip to content

Time Runners

A time runner is a fixed-rate clock. It steps at a set frequency, measured in hertz, and drives the callbacks and subsystems bound to it. A runner at 50 Hz steps every 20 ms, and each of its steps has a fixed ts of 0.02 seconds.

In short

Runners do not run on separate clocks. They share one timeline, and where their steps coincide they run together as a shared step, interleaved by phase. Each script callback is bound to one runner and one phase, with a priority within that phase, all set per scene in Settings → Scene → Scripts.

The default runners

A scene can hold up to eight runners. A new scene starts with two:

Runner Frequency Step Default load
Robot (Runner 0) 50 Hz 20 ms Every script callback, subsystem, physics engine and recorder
Capture (Runner 1) 30 Hz 33.3 ms Empty, available for work that runs at a different rate

Because everything starts on Robot, the lifecycle callbacks enabled by default, OnUpdate and OnLateUpdate, both run at 50 Hz. The Sync Point System is the one exception: by default it uses a 10 Hz runner of its own. See Sync points.

What decides when a callback runs

Three settings position each callback, alongside the scene-wide time mode:

Setting What it decides
Runner How often the callback runs. The runner's frequency is its step rate.
Phase Where in the step the callback runs. Phases always run in the same order.
Priority Where in its phase the callback runs, among the other systems in that phase. Lower runs first.

Every step runs the five phases in order:

graph LR
    A(Acquisition) --> B(Control) --> C(Physics) --> D(Validation) --> E(Export)

The Time Manager page lists what the engine itself runs in each phase.

The priority is the Internal Phase Priority field on the Scripts page, under each callback's Execution Phase. OnUpdate starts at -200, so it runs before the robot controllers (0) in the Control phase and they use the targets it has just set. The other callbacks start at 0. Order within a phase lists the defaults.

A shared timeline

The engine advances every runner along one timeline.

When two or more runners land on a boundary at the same moment, they run together as a shared step.

The Robot and Capture runners share a boundary every 100 ms, a rate of 10 Hz. One full cycle looks like this:

graph LR
    T0["0 ms<br/>Robot + Capture"]:::shared --> T1["20 ms<br/>Robot"] --> T2["33 ms<br/>Capture"] --> T3["40 ms<br/>Robot"] --> T4["60 ms<br/>Robot"] --> T5["67 ms<br/>Capture"] --> T6["80 ms<br/>Robot"] --> T7["100 ms<br/>Robot + Capture"]:::shared
    classDef shared fill:#f5503d,stroke:#f5503d,color:#ffffff;

The red boundaries are shared steps, where both runners fire together. On every other boundary a single runner fires alone.

Interleaving on a shared step

On a shared step the callbacks do not run one whole runner after another. They interleave by phase. Each phase runs that phase's callbacks from every stepping runner before the next phase begins.

A shared step with a controller on Robot and the data recorder on Capture

  1. Acquisition runs the Capture runner's data recorder, which records the state at the start of the step.
  2. Control runs Robot's OnUpdate, which writes new commands.
  3. Physics steps the simulation with those commands.
  4. Validation runs Robot's OnLateUpdate.

The data and video recorders run in the Acquisition phase by default, so they capture the state the controller is about to react to, before it writes new commands. Their runner and phase are set on the General tab of Settings → Scene → Recorder.

ts is always the runner's own step

Each callback receives its own runner's step as ts. A Robot callback receives 0.02 seconds and a Capture callback receives about 0.0333 seconds, even when they run on the same shared step.

Time mode

The time mode sets how the shared timeline advances relative to the wall clock. Choose it with Scene Time Mode on Settings → Scene → Time Runners.

Option How it advances Suitable for
Game Realtime (Non-Deterministic) Follows the real-time clock and skips simulation time under load. Games and demos where real-time pacing matters more than reproducibility
Sim Realtime (Deterministic Capped) (default) Deterministically, never ahead of real time. Slows down rather than skipping steps under load. Interactive simulation, robotics, data collection
Sim High Perf. (Deterministic Uncapped) Deterministically, as fast as the hardware allows, without tracking real time. Training, batch data generation, benchmarks

In Sim High Perf., the extra Disable Viewport Rendering option skips drawing the viewport while the simulation runs, for runs where only the data output matters.

Determinism

New scenes start in Sim Realtime, a deterministic mode, so runs are reproducible by default. A deterministic mode produces the same sequence of steps regardless of frame rate, which matters for reproducible simulation and data collection.

Configuring runners

Runners are configured per scene, in the Scene group of the Settings panel. Open it from Edit → Settings; the Settings page describes the panel.

Settings page Purpose
Time Runners Scene Time Mode, and one row per runner (Runner 0: Robot and so on) with its name and frequency (0.01 to 1000 Hz). Add Time Runner adds a runner at 60 Hz, up to eight. The last runner cannot be removed.
Scripts Turn each lifecycle callback on or off (Enable OnUpdate Scripts and so on), and choose its runner (OnUpdate Scripts TimeRunner), Execution Phase and Internal Phase Priority. Also holds Enable Free Step Update Scripts.
Subsystems Bind the engine's own systems, such as the robot controllers, animation and audio.
Physics Turn Box2D, Jolt and MuJoCo on or off and choose the runner each one uses.
Recorder Choose the runner and phase of the data, video and lidar recorders.
Execution Order Shows every enabled system grouped by phase and sorted by priority, with its runner and frequency.

Binding a callback to a runner at a different frequency changes how often it runs, with no code change. The ts it receives always matches its runner's step.

Where to go next