---
title: Customizing Environments
description: Practical recipes for configuring episode length, cameras, colors, spawn regions, rewards, and more.
---

Every SO101-Nexus environment accepts a typed config object that controls its behavior. Configs are classes from `so101_nexus` and can be passed to `gymnasium.make` via the `config` keyword.

## Change Episode Length

Shorter episodes speed up training on simple tasks. Longer episodes give the agent more time for multi-step tasks. Episode length is `max_episode_steps`, passed at make time (not on the config), the same way for every env on both backends.

```python
import gymnasium as gym
import so101_nexus.mujoco
import so101_nexus.warp
from so101_nexus import TouchConfig

config = TouchConfig()

# MuJoCo (single env): applied via the TimeLimit wrapper
env = gym.make("MuJoCoTouch-v1", config=config, max_episode_steps=256)

# Warp (batched): forwarded to the vector env, which truncates internally
envs = gym.make_vec("WarpTouch-v1", num_envs=4, device="cuda", config=config, max_episode_steps=256)
```

## Add Camera Observations

Include camera images by adding a camera component to the `observations` list. The observation becomes a dictionary with a `"state"` key (flat vector) plus one key per camera.

```python
import gymnasium as gym
import so101_nexus.mujoco
from so101_nexus import (
    PickConfig, EndEffectorPose, GraspState, ObjectPose, ObjectOffset, WristCamera,
)

config = PickConfig(observations=[
    EndEffectorPose(),
    GraspState(),
    ObjectPose(),
    ObjectOffset(),
    WristCamera(width=224, height=224),
])
env = gym.make("MuJoCoPickLift-v1", config=config, render_mode="rgb_array")
obs, _ = env.reset()
print(obs["state"].shape)         # (18,): flat state vector
print(obs["wrist_camera"].shape)  # (224, 224, 3): camera image
```

For Warp, use the same observation config and create a batched vector env. Do not rely on `render_mode` for pixels; camera components are the image source.

```python
import so101_nexus.warp

envs = gym.make_vec("WarpPickLift-v1", num_envs=1024, device="cuda", config=config)
obs, _ = envs.reset()
print(obs["wrist_camera"].shape)  # (1024, 224, 224, 3)
```

You can also add an overhead camera, or both:

```python
from so101_nexus import OverheadCamera

config = PickConfig(observations=[
    EndEffectorPose(),
    GraspState(),
    ObjectPose(),
    ObjectOffset(),
    WristCamera(width=224, height=224),
    OverheadCamera(width=224, height=224),
])
```

## Visual Observation Mode

For vision-based policies, use `obs_mode="visual"` to signal that the policy should not rely on privileged simulator state. This mode requires at least one camera component in the observations list.

```python
from so101_nexus import PickConfig, JointPositions, WristCamera

config = PickConfig(
    obs_mode="visual",
    observations=[JointPositions(), WristCamera(width=224, height=224)],
)
env = gym.make("MuJoCoPickLift-v1", config=config)
obs, info = env.reset()

obs["state"]              # (6,) joint positions only
obs["wrist_camera"]       # (224, 224, 3) camera image
```

## Domain Randomization

Randomize colors and spawn positions to improve sim-to-real transfer. Color fields accept a single color name or a list -- when a list is provided, the environment samples uniformly at each reset.

```python
from so101_nexus import PickConfig

config = PickConfig(
    # Randomize visual appearance
    ground_colors=["gray", "white", "black"],
    robot_colors=["yellow", "orange"],
    # Tighten the spawn region
    spawn_min_radius=0.20,
    spawn_max_radius=0.30,
    spawn_angle_half_range_deg=60.0,
)
env = gym.make("MuJoCoPickLift-v1", config=config)
```

Available colors: `red`, `orange`, `yellow`, `green`, `blue`, `purple`, `black`, `white`, `gray`.

## Reset Settling

By default, environments advance 5 no-op frames after reset before returning
the first observation. This skips the unstable first frames after contacts and
controllers initialize. Set `reset_settle_frames=0` when you need to inspect
the raw reset state.

```python
import gymnasium as gym
from so101_nexus import PickConfig

config = PickConfig(reset_settle_frames=0)
env = gym.make("MuJoCoPickLift-v1", config=config)
```

## Tune Rewards

Reward is composed of four weighted components: `reaching` (progress toward the object), `grasping` (gripper contact), `task_objective` (the primary goal like lifting), and `completion_bonus` (one-time success reward). The four weights must sum to 1.0. Optional penalty terms are applied separately.

```python
from so101_nexus import RewardConfig, PickConfig

reward = RewardConfig(
    reaching=0.20,
    grasping=0.20,
    task_objective=0.50,
    completion_bonus=0.10,
    action_delta_penalty=0.025,
    energy_penalty=0.025,
)
config = PickConfig(reward=reward)
env = gym.make("MuJoCoPickLift-v1", config=config)
```

## Configure Pick Tasks

`PickConfig` extends `EnvironmentConfig` with object and distractor settings. Use it for PickLift environments.

```python
from so101_nexus import PickConfig, CubeObject, YCBObject

config = PickConfig(
    objects=[
        CubeObject(color="blue"),
        YCBObject(model_id="058_golf_ball"),
        YCBObject(model_id="011_banana"),
    ],
    n_distractors=1,
    lift_threshold=0.06,
    min_object_separation=0.04,
    ground_colors=["gray", "white"],
)
env = gym.make("MuJoCoPickLift-v1", config=config, render_mode="human")
```

When multiple objects are provided, the environment selects one as the target at each reset.

## Configure Pick-and-Place Tasks

`PickAndPlaceConfig` controls the cube and target disc appearance. Use it for PickAndPlace environments.

```python
from so101_nexus import PickAndPlaceConfig

config = PickAndPlaceConfig(
    cube_colors=["red", "green", "blue"],
    target_colors="purple",
    min_cube_target_separation=0.05,
)
env = gym.make("MuJoCoPickAndPlace-v1", config=config, render_mode="human")
```

## All Parameters

See the [Configs API reference](/docs/api/configs) for the full list of parameters on `EnvironmentConfig`, `PickConfig`, `PickAndPlaceConfig`, `TouchConfig`, `LookAtConfig`, `MoveConfig`, `RewardConfig`, `RenderConfig`, and `RobotConfig`.
