smooviz-robotics
v0.0.4
Published
A library for visualizing robotics motion data from MuJoCo XML models
Maintainers
Readme
smooviz-robotics
A powerful library for visualizing robotics motion data from MuJoCo XML models. Works with both React applications and vanilla JavaScript.
Features
- Parse MuJoCo XML robot models
- Build 3D robot visualizations using Three.js
- Animate robots with motion data
- Multiple distribution formats:
- ESM/CJS modules for bundlers (Webpack, Vite, etc.)
- UMD bundle for vanilla HTML/JavaScript
- TypeScript type definitions included
- Framework agnostic core with optional React components
Installation
For React Projects
npm install smooviz-robotics react react-dom threeor with yarn:
yarn add smooviz-robotics react react-dom threeFor Vanilla JavaScript
Download the UMD bundle or use a CDN:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="path/to/smooviz-robotics.umd.js"></script>Usage
React Component (Quickest Start)
The simplest way to get started - just render the component and use the built-in configuration dialog:
import { RobotVisualizer } from 'smooviz-robotics';
function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
{/* Shows configuration dialog for model and data selection */}
<RobotVisualizer />
</div>
);
}Or skip the dialog and go straight to visualization:
import { RobotVisualizer } from 'smooviz-robotics';
function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<RobotVisualizer
modelName="unitree_g1"
dataUrl="/unitree_g1/example.json"
/>
</div>
);
}React with Core API (Custom Implementation)
import { useEffect, useRef } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import {
parseMuJoCoXML,
buildRobotFromModel,
applyJointAngles
} from 'smooviz-robotics/core';
function CustomRobotViewer() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!containerRef.current) return;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
containerRef.current.appendChild(renderer.domElement);
// Set up lights and camera
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 10, 7);
scene.add(directionalLight);
camera.position.set(2, 2, 2);
const controls = new OrbitControls(camera, renderer.domElement);
// Load and visualize robot
async function loadRobot() {
const model = await parseMuJoCoXML('/path/to/robot.xml');
const robot = await buildRobotFromModel(model, '/path/to/meshes');
scene.add(robot.robot);
// Load motion data and animate
const response = await fetch('/path/to/motion.json');
const motionData = await response.json();
let frame = 0;
setInterval(() => {
applyJointAngles(robot, motionData.dof_pos[frame]);
frame = (frame + 1) % motionData.dof_pos.length;
}, 1000 / motionData.fps);
}
loadRobot();
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
return () => {
renderer.dispose();
containerRef.current?.removeChild(renderer.domElement);
};
}, []);
return <div ref={containerRef} />;
}Vanilla JavaScript/HTML
<!DOCTYPE html>
<html>
<head>
<title>Robot Viewer</title>
<style>
body { margin: 0; overflow: hidden; }
#container { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="container"></div>
<!-- Load Three.js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/STLLoader.js"></script>
<!-- Load smooviz-robotics -->
<script src="smooviz-robotics.umd.js"></script>
<script>
const { parseMuJoCoXML, buildRobotFromModel, applyJointAngles } = SmoovizRobotics;
// Set up Three.js scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('container').appendChild(renderer.domElement);
// Add lights
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(5, 10, 7);
scene.add(light);
// Camera controls
camera.position.set(2, 2, 2);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
// Load robot
let robotStructure;
let motionData;
let frame = 0;
async function loadRobot() {
const model = await parseMuJoCoXML('/path/to/robot.xml');
robotStructure = await buildRobotFromModel(model, '/path/to/meshes');
// Convert from Z-up to Y-up coordinate system
const rotation = new THREE.Quaternion();
rotation.setFromAxisAngle(new THREE.Vector3(1, 0, 0), -Math.PI / 2);
robotStructure.robot.quaternion.copy(rotation);
scene.add(robotStructure.robot);
// Load motion data
const response = await fetch('/path/to/motion.json');
motionData = await response.json();
// Start animation
setInterval(() => {
applyJointAngles(robotStructure, motionData.dof_pos[frame]);
frame = (frame + 1) % motionData.dof_pos.length;
}, 1000 / motionData.fps);
}
loadRobot();
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>API Reference
Core Library (smooviz-robotics/core)
parseMuJoCoXML(xmlUrl: string): Promise<MuJoCoModel>
Parses a MuJoCo XML file and returns a structured model.
Parameters:
xmlUrl- URL or path to the MuJoCo XML file
Returns:
- Promise that resolves to a
MuJoCoModelcontaining the robot structure
buildRobotFromModel(model: MuJoCoModel, meshBaseUrl: string): Promise<RobotStructure>
Builds a Three.js scene graph from a parsed MuJoCo model.
Parameters:
model- The parsed MuJoCo modelmeshBaseUrl- Base URL for loading mesh files (STL)
Returns:
- Promise that resolves to a
RobotStructurecontaining the Three.js robot and joint mappings
applyJointAngles(robotStructure: RobotStructure, jointAngles: number[]): void
Applies joint angles to the robot for animation.
Parameters:
robotStructure- The robot structure frombuildRobotFromModeljointAngles- Array of joint angles in radians
Utility Functions
getAllJoints(body: MuJoCoBody): MuJoCoJoint[]- Get all joints in orderfindBodyByName(body: MuJoCoBody, name: string): MuJoCoBody | null- Find a specific bodybuildBodyMap(rootBody: MuJoCoBody): Map<string, MuJoCoBody>- Create name-to-body lookup
React Component (smooviz-robotics/react)
<RobotVisualizer />
A complete React component for visualizing robot motion.
Props:
modelName?: 'unitree_g1' | 'unitree_h1_2'(optional) - Robot model to loaddataUrl?: string(optional) - URL to the motion data JSON file
Configuration Dialog:
When both props are omitted, the component displays a configuration dialog allowing users to:
- Select a robot model from available options
- Specify a motion data file path
Relative paths in dataUrl are resolved from the model directory. For example, if modelName="unitree_g1" and dataUrl="example.json", the component will load /unitree_g1/example.json.
Examples:
// Show configuration dialog
<RobotVisualizer />
// Direct visualization with specific model and data
<RobotVisualizer
modelName="unitree_g1"
dataUrl="/unitree_g1/example.json"
/>
// Use relative path for data (resolves to /unitree_g1/example.json)
<RobotVisualizer
modelName="unitree_g1"
dataUrl="example.json"
/>Types
The library exports comprehensive TypeScript types:
import type {
MuJoCoModel,
MuJoCoBody,
MuJoCoJoint,
MuJoCoGeom,
MuJoCoScene,
RobotStructure,
JointInfo
} from 'smooviz-robotics';Motion Data Format
The library expects motion data in the following JSON format:
{
"dof_pos": [[/* joint angles for frame 0 */], [/* frame 1 */], ...],
"root_pos": [[x, y, z], ...],
"root_ori": [[x, y, z, w], ...],
"fps": 30
}dof_pos- 2D array of joint angles (radians) for each frameroot_pos- Root position [x, y, z] for each frameroot_ori- Root orientation quaternion [x, y, z, w] for each framefps- Playback frame rate
MuJoCo XML Format
The library supports standard MuJoCo XML format with:
<worldbody>- Robot hierarchy<asset>- Mesh and material definitions<include>- Modular file composition- Scene settings (lights, ground, camera)
Examples and Assets
Examples
See the examples/ directory for complete working examples:
react-example.tsx- React usage with custom implementationvanilla-js-example.html- Vanilla JavaScript usage
Included Assets
The library includes example robot models and motion data in the public/ directory:
public/unitree_g1/- Unitree G1 humanoid robot modelscene.xml- MuJoCo scene configurationcustom.xml- Robot model definitionexample.json- Example dancing motion datameshes/- STL mesh files for robot partsconfig.yaml- Robot configuration
These assets are included when you install the package and can be used for testing and development.
License
Apache-2.0
Contributing
Contributions welcome! Please open an issue or submit a pull request.
