simulo.Scenario
The interactive simulation contract — a sim that runs without a training loop.
A scenario builds a scene and then reacts to the simulation clock: on_step
fires every physics step, for as long as the scenario runs (until the job is
cancelled or the sim is shut down). Use it for demos, teleoperation, data
capture, or any “just simulate” workload — there is no policy, no reward, and
no episode lifecycle.
Structural mirror of simulo.scenario.Scenario, the abstract base your
scenario subclasses on the worker.
Real usage, trimmed from the shipped scene app — a Scenario is the same lifecycle as a Task without training: build the scene once, then drive it every step yourself:
class SceneScenario(simulo.Scenario): def build(self, scene: simulo.Scene) -> None: self.robot = simulo.Robot(asset=cartpole, initial_pose=simulo.Pose.identity()) scene.add(self.robot, at="/World/Robot")
def on_start(self) -> None: self._cart_dof_idx = self.robot.find_joints("slider_to_cart")
def on_step(self) -> None: # efforts: one row per environment, built from a per-env phase offset. self.robot.set_joint_effort_target(efforts)Run it end to end with simulo.run(SceneScenario, device="cuda", headless=True, max_steps=1000, num_envs=4) — see simulo.run.
build()
Section titled “build()”Scenario.build(scene: SceneProtocol) -> NonePopulate scene with the world — robots, objects, lights, terrain.
Called once, before simulation starts.
on_start()
Section titled “on_start()”Scenario.on_start() -> NoneOne-time hook after the sim is live — cache handles, set initial poses.
on_step()
Section titled “on_step()”Scenario.on_step() -> NoneCalled once per physics step while the scenario runs.
on_shutdown()
Section titled “on_shutdown()”Scenario.on_shutdown() -> NoneCalled once when the scenario stops — flush files, release resources.
Declared as:
@runtime_checkableclass ScenarioProtocol(Protocol)