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
- Acquisition runs the Capture runner's data recorder, which records the state at the start of the step.
- Control runs Robot's
OnUpdate, which writes new commands. - Physics steps the simulation with those commands.
- 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¶
- Entity Lifecycle: which callbacks exist and which are enabled by default.
- The Time Manager: the engine-wide view of runners and phases.
- Recording with the Observer: recording data from scripts.