Skip to main content

SceneConfig

Every simulation starts with a SceneConfig object that tells mujoco-react what to load and how to configure it:
import type { SceneConfig } from "mujoco-react";

const config: SceneConfig = {
  src: "https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/",
  sceneFile: "scene.xml",
  numArmJoints: 7,
  tcpSiteName: "tcp",
  gripperActuatorName: "gripper",
  homeJoints: [1.707, -1.754, 0.003, -2.702, 0.003, 0.951, 2.490],
};

Required Fields

FieldTypeDescription
srcstringBase URL for model files (e.g. 'https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/')
sceneFilestringEntry MJCF file to load (e.g. 'scene.xml')

Optional Fields

FieldTypeDefaultDescription
numArmJointsnumber7Number of arm joints for IK
tcpSiteNamestring'tcp'MuJoCo site name for IK target
gripperActuatorNamestring'gripper'Actuator name for gripper control
homeJointsnumber[]Joint positions applied on reset
sceneObjectsSceneObject[]Dynamic objects injected into scene
xmlPatchesXmlPatch[]XML transformations before compilation
onReset(model, data) => voidCustom logic run after each reset

Model Sources

DeepMind Menagerie

Models from MuJoCo Menagerie can be loaded by pointing src at the raw GitHub URL for the model directory:
// Loads from: raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/scene.xml
const config: SceneConfig = {
  src: "https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/",
  sceneFile: "scene.xml",
};
Available models include franka_emika_panda, universal_robots_ur5e, kuka_iiwa_14, robotiq_2f85, and many more.

Custom Server

Point src to any HTTP server hosting MJCF files:
const config: SceneConfig = {
  src: "https://my-server.com/models/my_robot/",
  sceneFile: "scene.xml",
};
// Fetches: https://my-server.com/models/my_robot/scene.xml

GitHub Repositories

Use raw GitHub URLs for models hosted in your own repos:
const config: SceneConfig = {
  src: "https://raw.githubusercontent.com/myorg/myrepo/main/my_robot/",
  sceneFile: "robot.xml",
};

Scene Objects

Inject dynamic objects (boxes, spheres, cylinders) into the scene without modifying MJCF files:
const config: SceneConfig = {
  src: "https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/",
  sceneFile: "scene.xml",
  sceneObjects: [
    {
      name: "red_cube",
      type: "box",
      size: [0.025, 0.025, 0.025],
      position: [0.5, 0.0, 0.025],
      rgba: [1, 0, 0, 1],
      mass: 0.1,
      freejoint: true,
    },
    {
      name: "blue_sphere",
      type: "sphere",
      size: [0.02, 0, 0],
      position: [0.4, 0.1, 0.02],
      rgba: [0, 0, 1, 1],
      mass: 0.05,
      freejoint: true,
    },
  ],
};

SceneObject Fields

FieldTypeDefaultDescription
namestringrequiredUnique body/geom name
type'box' | 'sphere' | 'cylinder'requiredGeom type
size[number, number, number]requiredGeom size (MuJoCo semantics)
position[number, number, number]requiredInitial world position
rgba[number, number, number, number]requiredColor (0-1 range)
massnumberBody mass in kg
freejointbooleanAdd a free joint (6-DOF)
frictionstringMuJoCo friction spec
solrefstringMuJoCo solver reference
solimpstringMuJoCo solver impedance
condimnumberContact dimensionality
Objects are injected into </worldbody> before the model is compiled.

XML Patching

For more advanced model customization, use xmlPatches to transform the MJCF XML before it reaches MuJoCo:
const config: SceneConfig = {
  src: "https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/",
  sceneFile: "scene.xml",
  xmlPatches: [
    // Replace a value in the XML
    {
      target: "scene.xml",
      replace: ["timestep=\"0.002\"", "timestep=\"0.001\""],
    },
    // Inject XML after a specific tag
    {
      target: "scene.xml",
      inject: "<body name=\"table\" pos=\"0.5 0 0\"><geom type=\"box\" size=\"0.3 0.3 0.01\" rgba=\"0.6 0.4 0.2 1\"/></body>",
      injectAfter: "<worldbody>",
    },
  ],
};

XmlPatch Fields

FieldTypeDescription
targetstringFilename to patch
replace[string, string][search, replacement] string substitution
injectstringXML string to inject
injectAfterstringInsert inject after this string

Reset Callback

Run custom logic after each simulation reset (e.g., randomize object positions for domain randomization):
const config: SceneConfig = {
  src: "https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/franka_emika_panda/",
  sceneFile: "scene.xml",
  sceneObjects: [
    { name: "cube", type: "box", size: [0.025, 0.025, 0.025],
      position: [0.5, 0, 0.025], rgba: [1, 0, 0, 1],
      mass: 0.1, freejoint: true },
  ],
  onReset: (model, data) => {
    // Randomize cube position on each reset
    const bodyId = 1; // or use findBodyByName
    const qposAdr = model.jnt_qposadr[0];
    data.qpos[qposAdr + 0] = 0.4 + Math.random() * 0.2; // x
    data.qpos[qposAdr + 1] = -0.1 + Math.random() * 0.2; // y
    data.qpos[qposAdr + 2] = 0.025; // z
  },
};

Runtime Scene Loading

Swap the entire model at runtime without remounting:
const { api } = useMujoco();

async function switchRobot() {
  await api.loadScene({
    src: "https://raw.githubusercontent.com/google-deepmind/mujoco_menagerie/main/universal_robots_ur5e/",
    sceneFile: "scene.xml",
  });
}