Skip to content

Scenarios

A simulo.Scenario is the other half of the platform: a plain simulation you script, rather than train. No Task, no reward, no trainer — you build a scene and drive it with your own control law, exactly the code you’d write to animate or test a robot deterministically. See Scene, Robot & World for what simulo.Robot, simulo.Terrain, and simulo.World mean and how per_environment works.

from __future__ import annotations
import math
import simulo
cartpole = simulo.Asset.from_registry("simulo/robot/cartpole:v1")
class SweepScenario(simulo.Scenario):
def build(self, scene: simulo.Scene) -> None:
scene.add(simulo.Terrain.plane(name="ground"), at="/World/Ground", per_environment=False)
self.robot = simulo.Robot(
asset=cartpole,
initial_pose=simulo.Pose.identity(),
)
scene.add(self.robot, at="/World/Robot")
self.step_count = 0
def on_start(self) -> None:
self._cart_idx = self.robot.find_joints("slider_to_cart")
def on_step(self) -> None:
self.step_count += 1
effort = 5.0 * math.sin(2.0 * math.pi * self.step_count / 120.0)
self.robot.set_joint_effort_target([[effort]])
def on_shutdown(self) -> None:
print(f"shut down after {self.step_count} steps")

The lifecycle is deliberately small:

Method Called
build(scene) Once, to declare the scene.
on_start() Once, after the runtime is live.
on_step() Every physics step — this is where you script behavior.
on_shutdown() Once, at teardown.

Like Task, simulo.Scenario is a lean, torch-free class on your machine and the real scenario runtime on the cloud worker — the same class authors lean and runs heavy, with no code changes.

A Scenario runs inside an @app.job body via simulo.run — no second import. Like every other name on simulo.*, it resolves mode-aware: a lean, inert stand-in on your machine (the job body is read at submit time, never executed) and the real scenario runtime on the cloud worker:

@app.job(system=simulo.SystemType.TIER_1, timeout=30 * 60)
def simulate(num_steps: int = 1000, num_envs: int = 4) -> dict:
simulo.run(
SweepScenario,
device="cuda",
headless=True,
max_steps=num_steps,
num_envs=num_envs,
env_spacing=2.0,
)
return {"steps": num_steps, "num_envs": num_envs}

With num_envs > 1, the robot you declare in build() is automatically replicated across every environment — useful for visually comparing several runs of the same scripted behavior side by side.

Scenarios are the app to reach for when you want to watch a simulation rather than train a policy: smoke-testing a new robot asset, scripting a demo, or driving a deterministic control law for visualization. Submit one with --viewstream and open the live viewport:

Terminal window
simulo run app.py --viewstream --num-steps 3000 --num-envs 4
simulo view

See Recordings & Live Viewstream for how the live viewport works.

simulo create <name> --type scenario scaffolds this exact shape from scratch — see Getting Started.