3D Rotation Converter
2025-11-10
Introduction
There are multiple ways to represent 3D rotations: Quaternions, Euler angles, rotation matrices, axis-angle, MRP (Modified Rodrigues Parameters)... Each has its pros and cons, and the optimal representation varies by application.
When developing games in Unity, you use quaternions. For aerospace simulations, Euler angles. Reading academic papers, you encounter MRP. Converting between these representations by hand is tedious and error-prone.
That's why I built Attitude Converter — a browser-based tool for interactively converting between rotation representations.
Demo: https://attitude-converter.tompython.com/
Source Code: GitHub
Features
Supported Rotation Representations
- Quaternion: 4D unit vector. No gimbal lock, easy interpolation
- Euler Angles: Three angles. Intuitive but susceptible to gimbal lock
- MRP (Modified Rodrigues Parameters): 3D representation with shadow set to avoid singularities
- Axis-Angle: Rotation axis and angle
- Rotation Matrix: 3×3 orthogonal matrix
12 Euler Angle Sequences
From ZYX (Yaw-Pitch-Roll) common in aerospace to ZXZ (precession) in classical mechanics — all 12 Euler angle sequences are supported.
- Tait-Bryan angles: XYZ, XZY, YXZ, YZX, ZXY, ZYX
- Proper Euler angles: XYX, XZX, YXY, YZY, ZXZ, ZYZ
Gimbal Lock Detection
Gimbal lock is an inherent issue with Euler angles. When the second angle approaches ±90° (for Tait-Bryan angles), the tool automatically displays a warning.
MRP Shadow Set
MRP becomes numerically unstable when $|\sigma|^2 > 1$. In Auto Shadow mode, it automatically switches to the shadow set ($\sigma` = -\sigma/|\sigma|^2$), ensuring $|\sigma|^2 \leq 1$ at all times.
Interactive 3D View
A 3D view powered by React Three Fiber lets you visualize rotations. You can also drag the rotation rings to directly manipulate the orientation.
Tech Stack
Why Rust + WebAssembly?
Rotation calculations are primarily floating-point operations. JavaScript would perform adequately, but I chose Rust + WASM for several reasons:
- Type Safety: Sign errors and index mistakes are critical in rotation math. Rust's type system prevents many bugs
- Future Extensibility: Potential to add heavier computations like attitude estimation or Kalman filters
- Learning: A practical project to gain experience with Rust + WASM
Frontend
- Next.js 14: App Router, Static Export
- React Three Fiber: 3D visualization
- TypeScript: Type-safe UI development
Core Computation
- Rust: Rotation calculation logic
- wasm-bindgen: Bridge between Rust and JavaScript
- serde_json: Data serialization
Implementation Notes
wasm-opt and externref Issue
During development, I encountered an issue where WASM stopped working after wasm-opt optimization. The cause was a compatibility issue with the externref (Reference Types) feature. The solution was to disable wasm-opt:
[package.metadata.wasm-pack.profile.release]
wasm-opt = false
The performance impact is negligible for this application.
Loading WASM in Next.js
Getting Next.js's Webpack configuration to work well with WASM was tricky. The final approach was placing WASM files in the public/ directory and using dynamic imports:
const wasm = await import(/* webpackIgnore: true */ '/wasm/attitude_wasm.js');
await wasm.default(wasmBuffer);
Conclusion
Rotation representation conversion is needed in various fields: 3D graphics, robotics, aerospace, and more. I hope this tool helps improve productivity in such contexts.
Feature requests and bug reports are welcome via GitHub Issues.
Attitude Converter