trackball
v1.3.1
Published
The RAW library to add a virtual Trackball to your DOM
Maintainers
Readme
Trackball.js - 3D Trackballs for your Website
Trackball.js is a small JavaScript library on top of Quaternion.js that enables natural, free 3D rotation of DOM elements via CSS transforms. The library does not style your DOM – it just handles user input and gives you a quaternion that you apply to your object.
If you are interested in the math behind this library or want to see a demo, take a look at the derivation of the trackball.
Example
The usage of Trackball.js is pretty straightforward. Create a scene that should handle the input and put a object with 3D transforms in it:
<div id="scene">
<div id="object">
<div class="side"></div>
<!-- ... -->
</div>
</div>Basic styles:
<style>
#scene {
width: 400px;
height: 400px;
touch-action: none; /* important for touch */
perspective: 500px;
position: relative;
}
#object {
width: 200px;
height: 200px;
margin: 100px;
transform-style: preserve-3d;
box-sizing: border-box;
}
.side {
width: 200px;
height: 200px;
position: absolute;
pointer-events: none;
box-sizing: border-box;
}
</style>Usage:
<script src="/path/to/quaternion.min.js"></script>
<script src="/path/to/trackball.min.js"></script>
<script>
const obj = document.getElementById('object');
const tb = new Trackball({
scene: '#scene',
q: new Quaternion(), // initial rotation
inertia: true, // enable inertia (defaults shown below)
limitAxis: null, // 'x' | 'y' | null
onDraw(q) {
// apply q (Quaternion) to your view matrix / object here
// e.g., shader uniform from q.toMatrix4() if your lib supports it
obj.style.transform = q.toCSSTransform();
}
});
</script>Limit interaction to a bounding box inside the scene:
const bbox = document.getElementById('object');
const tb = new Trackball({
scene: '#scene',
activeArea: () => bbox.getBoundingClientRect(),
areaPolicy: 'start-inside', // start inside, keep rotating if pointer leaves
inertia: { damping: 0.93 },
onDraw(q) { obj.style.transform = q.toCSSTransform(); }
});Programmatic rotation (when idle):
const tick = () => {
if (!tb.inertiaID && !tb.drag) {
tb.rotate(Quaternion.fromAxisAngle([0,1,0], Math.PI/180));
}
requestAnimationFrame(tick);
};
requestAnimationFrame(tick);Installation
You can install Trackball.js via npm:
npm install trackballOr with yarn:
yarn add trackballAlternatively, download or clone the repository:
git clone https://github.com/rawify/Trackball.jsUsage
Include the trackball.min.js file in your project:
<script src="path/to/trackball.min.js"></script>
<script>
const cm = new Trackball();
...
</script>Or in a Node.js project:
const Trackball = require('trackball');or
import Trackball from "trackball";API
new Trackball(options)
Required
scene: HTMLElement | string– host element or CSS selector that receives interaction.
Common
q: Quaternion(default:Quaternion.ONE) – initial orientation.onDraw(q)– called every time orientation changes.onStart(q)– called when a drag/press starts.onEnd(q)– called on release, or when inertia finishes.enabled: boolean(default:true) – enable/disable interaction.limitAxis: 'x'|'y'|null(default:null) – lock one axis if desired.invertX: boolean(default:false) – invert X motion.invertY: boolean(default:false) – invert Y motion.speed: number(default:1) – motion multiplier.ballsize: number(default:0.75) – relative ball radius (fraction of the active rect’s larger side).border: number(default:0.5) – rounded-arcball rim amount (0 = pure sphere, 0.5 = pleasant rim).
Active area
activeArea: HTMLElement | string | DOMRect | () => DOMRect | {left,top,width,height}(default:null) – restricts interaction.areaPolicy: 'inside-only'|'start-inside'|'always'(default:'inside-only') – update rules vs. the active box.
Pointer options
usePointerCapture: boolean(default:true) – improves robustness while dragging.passiveMove: boolean(default:true) – passivepointermovelistener.
Inertia
inertia: boolean | { damping?: number, maxStep?: number, minVelocity?: number, timeDiv?: number }- If
true, uses defaults below. - Defaults:
{ damping: 0.93, maxStep: 0.2, minVelocity: 1e-3, timeDiv: 50 }
- If
Methods
rotate(by: Quaternion)– multiply current orientation byby(only when not dragging and no inertia).setQuaternion(q: Quaternion)– replace orientation immediately.setActiveArea(area)– change the active area at runtime.setEnabled(boolean)– enable/disable interaction.dispose()– remove listeners and stop inertia.
Notes
- Trackball.js only computes the quaternion. Apply it to your object any way you like, e.g.
q.toCSSTransform(). - To restrict to a sub-rect of the scene, provide
activeArea(element, selector, rect, or function).
Coding Style
As every library I publish, Trackball.js is also built to be as small as possible after compressing it with Google Closure Compiler in advanced mode. Thus the coding style orientates a little on maxing-out the compression rate. Please make sure you keep this style if you plan to extend the library.
Building the library
After cloning the Git repository run:
npm install
npm run buildRun a test
Testing the source against the shipped test suite is as easy as
npm run testCopyright and Licensing
Copyright (c) 2025, Robert Eisele Licensed under the MIT license.
