How the CAD Viewer Handles URDF Robot Poses and Kinematics: A Technical Deep Dive

The CAD Viewer processes URDF files by parsing the XML into a JavaScript model, computing forward kinematics through hierarchical transform chains, and enabling interactive pose manipulation via a spherical picker interface.

The text-to-cad repository includes a sophisticated CAD Viewer that treats URDF robots as hierarchical kinematic chains. Understanding how this viewer handles URDF robot poses and kinematics reveals a three-stage pipeline: XML parsing, transform calculation, and interactive posing with smooth animation.

Parsing URDF XML into a JavaScript Model

The pipeline begins in viewer/packages/cadjs/src/lib/urdf/parseUrdf.js, where the raw XML is converted into a plain JavaScript description (urdfData). This object contains structured arrays of links, joints, visual meshes, and material definitions.

The parser validates the robot tree structure to ensure a single root link and no cyclic dependencies. It returns an object with three primary properties: links, joints, and namedMaterialColors. This normalized representation serves as the foundation for all subsequent kinematic calculations.

Computing Forward Kinematics and World Transforms

Once parsed, the viewer calculates the spatial relationship between every link using forward kinematics. The core implementation resides in viewer/packages/cadjs/src/lib/urdf/kinematics.js, specifically the solveUrdfLinkWorldTransforms function.

This function traverses the joint graph from root to children, accumulating transforms through a chain of operations:

  • translationTransform – applies the joint's positional offset
  • rotationTransformFromRpy – applies the joint's orientation (roll, pitch, yaw)
  • posedJointLocalTransform – rotates by the current joint angle (converting degrees to radians)

The module provides essential math utilities including multiplyTransforms, invertRigidTransform, and transformPoint for rigid body operations.

For mesh rendering, poseUrdfMeshData takes the raw geometry from URDF <mesh> tags and multiplies each vertex by the corresponding link's world transform, producing THREE.BufferGeometry ready for the scene.

Interactive Pose Picking and Joint Animation

User interaction with URDF robot poses happens through a spherical "pose picker" system implemented in viewer/packages/cadjs/src/lib/viewer/urdfPosePicker.js. When a user clicks the model, the viewer:

  1. Generates a translucent spherical grid via resolveUrdfPosePickerShell
  2. Casts a ray from camera NDC coordinates using intersectUrdfPosePickerShellAtNdc
  3. Maps the intersection point to spherical coordinates with urdfPosePickerCellForModelPoint
  4. Translates the selected cell into a target joint angle

Animation smoothing is handled by viewer/packages/cadjs/src/lib/urdf/jointAnimation.js, which exports URDF_JOINT_ANIMATION_DURATION_MS for timing and jointValueMapsClose for interpolation checks. The UI layer in viewer/src/client/components/workbench/UrdfFileSheet.js manages joint value state, while viewer/src/client/components/CadWorkspace.js orchestrates the animation loop.

Practical Implementation Examples

Loading a URDF and Computing Kinematic Data

import { parseUrdf } from 'cadjs/lib/urdf/parseUrdf.js';
import { solveUrdfLinkWorldTransforms, buildDefaultUrdfJointValues } from 'cadjs/lib/urdf/kinematics.js';

// xmlText contains the URDF file contents
const urdfData = parseUrdf(xmlText);
const defaultJointValues = buildDefaultUrdfJointValues(urdfData);

// Compute world transforms for the default pose
const linkWorldTransforms = solveUrdfLinkWorldTransforms(urdfData, defaultJointValues);

// Access a specific link's 4×4 column-major transform matrix
const baseLinkMatrix = linkWorldTransforms['base_link'];

Using the Spherical Pose Picker

import {
  resolveUrdfPosePickerShell,
  intersectUrdfPosePickerShellAtNdc,
  urdfPosePickerCellForModelPoint,
} from 'cadjs/lib/viewer/urdfPosePicker.js';

// runtime contains the THREE scene, camera, and model group
const picker = { center: [0, 0, 0] };
const ndc = { x: mouseNdcX, y: mouseNdcY };

// Find intersection point on the spherical shell
const hit = intersectUrdfPosePickerShellAtNdc(runtime, picker, ndc);
if (hit) {
  // Convert world point to spherical cell coordinates
  const cell = urdfPosePickerCellForModelPoint(runtime, picker, hit.point);
  
  // Map cell to joint angle (example: shoulder joint)
  const angleDeg = (cell.x / URDF_POSE_PICKER_SHELL_WIDTH_SEGMENTS) * 360;
  jointValuesByName['shoulder'] = angleDeg;
}

Animating Joint Value Changes

import { jointValueMapsClose, URDF_JOINT_ANIMATION_DURATION_MS } from 'cadjs/lib/urdf/jointAnimation.js';

function animateToPose(targetValues, currentValues) {
  const startTime = performance.now();
  
  const animate = (now) => {
    const t = Math.min((now - startTime) / URDF_JOINT_ANIMATION_DURATION_MS, 1);
    const interpolated = {};
    
    for (const name of Object.keys(targetValues)) {
      const startVal = currentValues[name] || 0;
      const endVal = targetValues[name];
      interpolated[name] = startVal + (endVal - startVal) * t;
    }
    
    updateJointValues(interpolated);
    
    if (!jointValueMapsClose(interpolated, targetValues)) {
      requestAnimationFrame(animate);
    }
  };
  
  requestAnimationFrame(animate);
}

Summary

  • Parse: parseUrdf.js converts XML to structured JavaScript objects with validated link/joint hierarchies
  • Transform: kinematics.js computes forward kinematics via solveUrdfLinkWorldTransforms, chaining translation, rotation, and joint angle transforms
  • Interact: urdfPosePicker.js provides spherical ray-casting to map screen coordinates to joint angles
  • Animate: jointAnimation.js supplies timing constants and interpolation helpers for smooth pose transitions
  • Orchestrate: CadWorkspace.js and UrdfFileSheet.js manage state and UI integration

Frequently Asked Questions

How does the viewer validate URDF structure during parsing?

The parseUrdf.js module validates that the robot definition contains a single root link and detects any cyclic dependencies in the joint graph. This ensures the kinematic chain forms a proper tree structure before attempting to solve transforms, preventing infinite loops during the traversal in solveUrdfLinkWorldTransforms.

What coordinate system does the viewer use for URDF transforms?

All transforms are stored as 4×4 column-major matrices in the world coordinate system. The kinematics.js file provides multiplyTransforms for composition and invertRigidTransform for inversion, maintaining consistency with standard 3D graphics conventions used by the underlying THREE.js rendering engine.

How does the spherical pose picker translate clicks into joint angles?

The system in urdfPosePicker.js creates a spherical shell around the robot model. When a user clicks, intersectUrdfPosePickerShellAtNdc performs ray-sphere intersection in normalized device coordinates. The hit point is converted to spherical coordinates via urdfPosePickerCellForModelPoint, which maps angular sectors to specific joint values based on the URDF joint limits and axis definitions.

Which component manages the animation loop for joint movements?

viewer/src/client/components/CadWorkspace.js drives the animation loop, while viewer/src/client/components/workbench/UrdfFileSheet.js handles the joint value state management. The actual interpolation logic uses jointValueMapsClose from jointAnimation.js to determine when the current values have reached their targets, using URDF_JOINT_ANIMATION_DURATION_MS to define the transition length.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →