useTrajectoryPlayer hook for prop-driven control.
Usage
Props
TrajectoryFrame[] | number[][]
required
Trajectory data. Accepts
TrajectoryFrame[] from useTrajectoryRecorder directly, or number[][] where each inner array is one frame of joint positions.number
default:"30"
Playback frame rate.
number
default:"1.0"
Speed multiplier.
0.5 = half speed, 2 = double speed.boolean
default:"false"
Loop playback when reaching the end.
boolean
Declarative play/pause control.
"kinematic" | "physics"
default:"kinematic"
Playback mode.
kinematic pauses physics and drives qpos directly. physics keeps the simulation running and applies ctrl values from the trajectory.({ frameIndex, frame }) => void
Called each time a new frame is displayed. Synced to the R3F render loop via
useFrame for precise timing.() => void
Called when playback reaches the end (non-looping only).
({ state }) => void
Called on every state transition (
idle, playing, paused, completed).How It Works
- When
playingbecomestrue, playback starts (in kinematic mode, the simulation is paused) - Each render frame, the component advances the trajectory index based on elapsed time,
fps, andspeed - The current frame’s qpos values are written to
data.qpos(kinematic) or ctrl todata.ctrl(physics) mj_forwardis called to update positions without stepping physics (kinematic mode only)- When playback reaches the end,
onCompletefires and state transitions tocompleted - The
onFramecallback is synced to R3F’suseFrameloop, ensuring it fires in lockstep with rendering
Notes
- In kinematic mode, the simulation’s previous pause state is restored on completion
- Accepts
TrajectoryFrame[]directly fromuseTrajectoryRecorder— no format conversion needed - For hook-based control with
play()/pause()/seek(), seeuseTrajectoryPlayer