Documentation Index
Fetch the complete documentation index at: https://dadd.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Register a callback that runs before mj_step every physics frame. This is the primary hook for writing control logic.
Signature
useBeforePhysicsStep(
callback: (model: MujocoModel, data: MujocoData) => void
): void
Usage
Setting Actuator Controls
useBeforePhysicsStep((model, data) => {
// Sinusoidal control on the first actuator
data.ctrl[0] = Math.sin(data.time * 2.0);
});
Applying Forces
useBeforePhysicsStep((model, data) => {
// Push body 3 upward
// xfrc_applied layout: 6 per body [torque(3), force(3)]
const offset = 3 * 6;
data.xfrc_applied[offset + 3] = 0; // fx
data.xfrc_applied[offset + 4] = 0; // fy
data.xfrc_applied[offset + 5] = 10; // fz (upward)
});
PD Controller
function PDController({ jointIndex, target, kp, kd }) {
useBeforePhysicsStep((model, data) => {
const q = data.qpos[jointIndex];
const dq = data.qvel[jointIndex];
data.ctrl[jointIndex] = kp * (target - q) - kd * dq;
});
return null;
}
Execution Order
1. Provider zeros qfrc_applied
2. → Your useBeforePhysicsStep callbacks run here ←
3. IK solving (if enabled)
4. mj_step
5. useAfterPhysicsStep callbacks
Composability
Multiple useBeforePhysicsStep hooks compose correctly. Each callback adds to the simulation state rather than overwriting:
// Component A: gravity compensation
useBeforePhysicsStep((model, data) => {
for (let i = 0; i < model.nv; i++) {
data.qfrc_applied[i] += data.qfrc_bias[i];
}
});
// Component B: custom control
useBeforePhysicsStep((model, data) => {
data.ctrl[0] = computeControl();
});
Both run each frame. Since the provider zeros qfrc_applied at the start, you should add to it (not assign).
Notes
- The callback receives the same model/data objects that
mj_step will use
- If using IK (via
IkGizmo), your before-step runs first, then IK may overwrite ctrl. Disable IK with api.setIkEnabled(false) when writing your own control.
- The callback is called at physics rate, not render rate. Multiple physics steps may run per render frame.