> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cadenzalabs.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Simulation & scenes

> Drive the simulator with Sim and build worlds with Scene.

`Sim` wraps MuJoCo physics for a robot, and `Scene` builds the world around it.
Together they're the engine under every other feature.

```mermaid theme={null}
flowchart LR
    SCENE[Scene] -->|compile → XML| XML[(MuJoCo model)]
    ROBOT["robot XML (go1/g1)"] --> XML
    XML --> SIM[Sim]
    SIM -->|run commands| PHYS[Physics step loop]
    PHYS -->|disturbance engine| PHYS
    PHYS --> STATE["get_state() · sensors · raycasts"]
    STATE -->|closed loop| SIM
```

## `Sim`

`Sim` is the simulator handle for a robot. Build it, then run commands.

```python theme={null}
import cadenza_lab as cadenza

sim = cadenza.Sim(robot="go1", disturbance=0.3)
sim.run(["walk_forward", "turn_left", "sit"])
state = sim.get_state()      # dict: pose, velocity, contacts, …
```

```python theme={null}
Sim(robot="go1", xml_path=None, disturbance=None,
    disturbance_seed=None, scene=None)
```

| Param         | Description                                                         |
| ------------- | ------------------------------------------------------------------- |
| `robot`       | `"go1"` or `"g1"`.                                                  |
| `xml_path`    | Override the MuJoCo model XML.                                      |
| `disturbance` | Perturbation level (`0.0`–`1.0`), with optional `disturbance_seed`. |
| `scene`       | A `Scene` to load (see below).                                      |

**Methods**

| Method                                          | Description                                                                                             |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `run(commands, ...)`                            | Execute a command string or list. Retries up to `max_retries` (default 3).                              |
| `run_reactive(memory_fn, vla_fn, goal_fn, ...)` | Closed-loop control: at each step, `goal_fn`/`vla_fn` decide the next action from memory + observation. |
| `get_state()`                                   | Return the current world state as a dict.                                                               |

## `Scene`

`Scene` builds a static world by adding primitives. Builder methods return the
scene, so they chain. Pass it to `Sim` or `GymAdapter`.

```python theme={null}
scene = (
    cadenza.Scene()
      .add_box(position=[-1.3, 0.2, 0.08], size=[0.18, 0.18, 0.08])
      .add_slope(position=[-2.0, 0.0, 0.0], size=[1.0, 1.0, 0.1], angle_deg=15)
      .add_sphere(position=[-2.8, 0.0, 0.1], radius=0.12, rgba=[1, 0.2, 0.2, 1])
)
sim = cadenza.Sim(robot="go1", scene=scene)
```

**Builder methods** (all `fixed=True`, optional `rgba`):

| Method           | Signature                                                                                                               |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `add_box`        | `add_box(position, size, *, fixed=True, rgba=None)`                                                                     |
| `add_slope`      | `add_slope(position, size, angle_deg, *, axis=(0,1,0), fixed=True, rgba=None)`                                          |
| `add_sphere`     | `add_sphere(position, radius, *, fixed=True, rgba=None)`                                                                |
| `snake`          | `snake(*, start_x, step_x, count, snake_y=0.4, z=None, box_size=(0.07,0.07,0.07), rgba=...)`. A row of staggered boxes. |
| `snake_on_slope` | Same, laid over a slope.                                                                                                |
| `clear()`        | Remove all added geometry.                                                                                              |
| `compile()`      | Finalize the scene (called automatically when loaded).                                                                  |

<Note>
  Cadenza's forward direction is **−X**. Positions and sizes are in MuJoCo world
  units (meters). `size` is half-extents for boxes/slopes.
</Note>

### `fixed` vs. dynamic objects

`fixed=True` (default) welds the object to the world. `fixed=False` wraps it in a
body with a free joint, so it falls under gravity and the robot can shove it.

```python theme={null}
scene.add_box(position=[-1.0, 0, 0.1], size=[0.1, 0.1, 0.1], fixed=False)  # kickable
```

### State & sensing

`Sim.get_state()` returns a dict the closed-loop helpers and modalities read from:

| Key                                          | Meaning                                                            |
| -------------------------------------------- | ------------------------------------------------------------------ |
| `pos`, `yaw`, `roll`, `pitch`, `body_height` | Base pose.                                                         |
| `foot_contacts`                              | Per-foot ground contact (0/1).                                     |
| `terrain_ahead`                              | Downward raycasts: `max_step_up`, ground heights ahead.            |
| `obstacles_ahead`                            | Forward raycasts: nearest hit left/center/right (`min_m`, `side`). |

## Demo: build a world and read it back

```python theme={null}
"""demo_scene.py: compile a scene, read terrain/obstacle sensing (headless)."""
import cadenza_lab as cadenza

scene = (
    cadenza.Scene()
      .add_box(position=[-1.3, 0.2, 0.08], size=[0.18, 0.18, 0.08])
      .add_slope(position=[-2.4, 0.0, 0.0], size=[0.8, 0.6, 0.05], angle_deg=12)
      .add_sphere(position=[-2.9, -0.3, 0.12], radius=0.12, rgba=[1, 0.2, 0.2, 1])
)

sim = cadenza.Sim(robot="go1", scene=scene, disturbance=0.2, disturbance_seed=0)
state = sim.get_state()
print("body height:", round(state["body_height"], 3))
print("obstacle ahead (min m):", state["obstacles_ahead"]["min_m"])
print("max step-up ahead:", round(state["terrain_ahead"]["max_step_up"], 3))

# To watch it instead of inspecting it (opens a viewer window):
# cadenza.view(robot="go1", scene=scene)
```

```bash theme={null}
python demo_scene.py
```
