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.
Authoring a Scenario
Section titled “Authoring a Scenario”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.
Running a Scenario
Section titled “Running a Scenario”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.
What Scenarios are for
Section titled “What Scenarios are for”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:
simulo run app.py --viewstream --num-steps 3000 --num-envs 4simulo viewSee Recordings & Live Viewstream for how the live viewport works.
simulo create <name> --type scenario scaffolds this exact shape from
scratch — see Getting Started.