A free, browser-based viewer and player for humanoid robot motion. Load a robot via URDF or MJCF (.xml) with STL meshes and play back .npz or .pkl motion trajectories — everything runs client-side, no server, no upload, no install.
Search keywords: npz viewer · npz player · pkl viewer · urdf viewer · mjcf viewer · urdf motion player · humanoid motion viewer · Unitree G1 viewer · Isaac Lab npz · GMR pkl · AMASS viewer · mocap viewer
- Any robot — drag-and-drop URDF or MJCF (
.xml) + STL meshes (Unitree G1, H1, custom humanoids, GMR/MuJoCo models) - NPZ playback — body-pose trajectories (
body_pos_w,body_quat_w) from Isaac Lab / BeyondMimic - PKL playback — GMR/MuJoCo-style files with
root_pos,root_rot,dof_pos; built-in forward kinematics handles the DoF → body-pose conversion - Cross-format joint mapping — PKL slots are mapped to URDF joints by name, so files saved against an MJCF whose joint set differs from the URDF (extra/zero-padded slots) still play correctly
- Zero install — single HTML file, runs entirely in the browser via Three.js
- Playback controls — play/pause, timeline scrubbing, speed (0.25x–2x), frame stepping
- Camera follow — auto-track the robot root body
- Trajectory trail — toggle a ground-plane trace of the root path
- Multi-motion — load many motion files at once, switch with
[/] - Type filter — sidebar tabs to show All / NPZ / PKL
- Data annotation — review motions one by one, mark each keep/discard (
Y/N), and export a CSV of all labels
- Open the live demo or
index.htmllocally - Drag a robot folder (containing a
.urdfor.xml+.stlmeshes) into the window - Drag one or more
.npzor.pklmotion files into the window - Use the playback bar to control visualization
| Key | Action |
|---|---|
Space |
Play / Pause |
← → |
Step frame backward / forward |
[ ] |
Previous / next motion |
Y / N |
Label current motion keep / discard (auto-advances to next) |
A ready-to-use example is included in demo/:
| Asset | Description |
|---|---|
demo/unitree_g1/ |
Unitree G1 humanoid — URDF + 35 STL meshes |
demo/dance1_subject2.npz |
Dance motion (131s, 6574 frames @ 50fps, 30 bodies) |
Clone the repo, then drag demo/unitree_g1/ and demo/dance1_subject2.npz into the viewer.
Body-pose trajectories in the NumPy .npz convention from whole_body_tracking / Isaac Lab.
Required keys:
| Key | Shape | Description |
|---|---|---|
fps |
(1,) |
Playback frame rate, e.g. [50] |
body_pos_w |
(N, num_bodies, 3) |
World-frame body positions |
body_quat_w |
(N, num_bodies, 4) |
World-frame body orientations (wxyz) |
Optional keys: joint_pos, joint_vel, body_lin_vel_w, body_ang_vel_w.
N = frame count. num_bodies must match the robot description's BFS body count (fixed joints collapsed into parent). Both uncompressed and deflate-raw-compressed NPZ files are supported.
GMR / MuJoCo-style Python pickles (protocol 4). The parser is a small subset that handles dict-of-ndarray payloads.
Required keys:
| Key | Shape | Description |
|---|---|---|
fps |
scalar | Playback frame rate |
root_pos |
(N, 3) |
Root world position |
root_rot |
(N, 4) |
Root world rotation (xyzw, MuJoCo convention) |
dof_pos |
(N, num_dof) |
Per-joint angles in MJCF body-tree DFS order |
Body poses are computed in the browser via forward kinematics walking the URDF/MJCF chain. Both C-contiguous and Fortran-order numpy arrays are handled. PKL slots are matched to URDF joints by name when the save format includes extra (zero-padded) joints not present in the loaded robot — see PKL_JOINT_PRESETS in index.html for the supported presets.
- URDF with
<visual>meshes pointing to.stlfiles, or MJCF (<mujoco>root) with<asset><mesh file="..."/>entries - Meshes are resolved by filename only (e.g.
package://foo/bar/pelvis.STLmatchespelvis.stl) - Binary STL only
- Description file and meshes can be in subdirectories — drag the top-level folder
- Motion data uses Z-up (Isaac Sim / MuJoCo convention)
- The viewer converts to Y-up for rendering automatically
- NPZ quaternions are wxyz, PKL
root_rotis xyzw, both handled internally
Single HTML file, no build step needed.
GitHub Pages: Fork this repo → Settings → Pages → deploy from main branch.
Local: Open index.html directly in a browser, or serve with any static server:
python -m http.server 8000