20+ VR/AR controller components supporting major headsets and platforms including Oculus, HTC Vive, Windows Mixed Reality, and hand tracking.
Generic hand tracking and controller management.
interface HandControlsComponent {
hand: 'left' | 'right'; // Which hand to track
handModelStyle: 'lowPoly' | 'highPoly' | 'toon'; // Hand model style
color: string; // Hand model color
handModelSrc: string; // Custom hand model URL
}Usage Examples:
<a-entity hand-controls="hand: left; handModelStyle: lowPoly; color: #ffcccc"></a-entity>
<a-entity hand-controls="hand: right; handModelStyle: highPoly"></a-entity>Base component for all tracked controller types.
interface TrackedControlsComponent {
controller: number; // Controller index
id: string; // Controller ID pattern to match
hand: 'left' | 'right'; // Controller hand
idPrefix: string; // Controller ID prefix
orientationOffset: string; // Orientation offset "x y z"
positional: boolean; // Enable positional tracking
rotationOffset: string; // Rotation offset "x y z"
armModel: boolean; // Enable arm model for 3DOF controllers
}Oculus Rift and Quest Touch controller support.
interface OculusTouchControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model (default: true)
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Usage Examples:
<a-entity oculus-touch-controls="hand: left"></a-entity>
<a-entity oculus-touch-controls="hand: right; model: false"></a-entity>
<!-- Button and axis events -->
<a-entity
oculus-touch-controls="hand: right"
listeners="
triggerdown: onTriggerDown;
triggerup: onTriggerUp;
gripdown: onGripDown;
thumbstickmoved: onThumbstickMoved;
xbuttondown: onXButtonDown;
ybuttondown: onYButtonDown;
">
</a-entity>HTC Vive controller and wand support.
interface ViveControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Usage Examples:
<a-entity vive-controls="hand: left"></a-entity>
<a-entity vive-controls="hand: right"></a-entity>
<!-- Vive controller events -->
<a-entity
vive-controls="hand: right"
listeners="
triggerdown: onTriggerDown;
trackpaddown: onTrackpadDown;
trackpadtouchstart: onTrackpadTouchStart;
menudown: onMenuDown;
gripdown: onGripDown;
">
</a-entity>Windows Mixed Reality motion controller support.
interface WindowsMotionControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
hideDisconnected: boolean; // Hide when disconnected
}Usage Examples:
<a-entity windows-motion-controls="hand: left"></a-entity>
<a-entity windows-motion-controls="hand: right; hideDisconnected: true"></a-entity>Mobile VR headset controller support.
Google Daydream controller support.
interface DaydreamControlsComponent {
hand: 'left' | 'right'; // Controller hand (default: 'right')
model: boolean; // Show controller model
armModel: boolean; // Enable arm model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Samsung Gear VR controller support.
interface GearVRControlsComponent {
hand: 'left' | 'right'; // Controller hand (default: 'right')
model: boolean; // Show controller model
armModel: boolean; // Enable arm model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Oculus Go controller support.
interface OculusGoControlsComponent {
hand: 'left' | 'right'; // Controller hand (default: 'right')
model: boolean; // Show controller model
armModel: boolean; // Enable arm model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Usage Examples:
<!-- Mobile VR controllers -->
<a-entity daydream-controls="hand: right; armModel: true"></a-entity>
<a-entity gearvr-controls="hand: right; model: true"></a-entity>
<a-entity oculus-go-controls="hand: right"></a-entity>Valve Index Knuckles controller support with finger tracking.
interface ValveIndexControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Magic Leap One controller support.
interface MagicLeapControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}HP Reverb and other HP Mixed Reality controller support.
interface HPMixedRealityControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
hideDisconnected: boolean; // Hide when disconnected
}Usage Examples:
<a-entity valve-index-controls="hand: left"></a-entity>
<a-entity valve-index-controls="hand: right"></a-entity>
<a-entity magicleap-controls="hand: right"></a-entity>
<a-entity hp-mixed-reality-controls="hand: left"></a-entity>
<a-entity hp-mixed-reality-controls="hand: right"></a-entity>Fallback component for unknown or generic tracked controllers.
interface GenericTrackedControllerControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
orientationOffset: string; // Orientation offset
rotationOffset: string; // Rotation offset
}Native hand tracking support for devices with hand tracking capabilities.
interface HandTrackingControlsComponent {
hand: 'left' | 'right'; // Which hand to track
modelStyle: 'mesh' | 'dots' | 'boxes'; // Hand visualization style
modelColor: string; // Hand model color
}Usage Examples:
<a-entity hand-tracking-controls="hand: left; modelStyle: mesh"></a-entity>
<a-entity hand-tracking-controls="hand: right; modelStyle: dots; modelColor: #ff6666"></a-entity>Laser pointer interaction for VR controllers.
interface LaserControlsComponent {
hand: 'left' | 'right'; // Controller hand
model: boolean; // Show controller model
defaultModel: boolean; // Use default model
defaultModelColor: string; // Default model color
defaultModelOpacity: number; // Default model opacity
}Usage Examples:
<a-entity laser-controls="hand: right"></a-entity>
<a-entity laser-controls="hand: left; defaultModelColor: red"></a-entity>
<!-- With raycaster for interaction -->
<a-entity
laser-controls="hand: right"
raycaster="objects: .clickable; showLine: true">
</a-entity>All controller components emit standardized events for button presses, axis changes, and connection status.
// Button press events (fired when button is pressed down)
interface ButtonDownEvents {
'triggerdown': CustomEvent; // Primary trigger
'gripdown': CustomEvent; // Grip/squeeze button
'trackpaddown': CustomEvent; // Trackpad click
'thumbstickdown': CustomEvent; // Thumbstick click
'menudown': CustomEvent; // Menu button
'systemdown': CustomEvent; // System button
}
// Button release events (fired when button is released)
interface ButtonUpEvents {
'triggerup': CustomEvent;
'gripup': CustomEvent;
'trackpadup': CustomEvent;
'thumbstickup': CustomEvent;
'menuup': CustomEvent;
'systemup': CustomEvent;
}
// Touch events (for touch-sensitive buttons)
interface TouchEvents {
'trackpadtouchstart': CustomEvent;
'trackpadtouchend': CustomEvent;
'thumbsticktouchstart': CustomEvent;
'thumbsticktouchend': CustomEvent;
}// Axis movement events
interface AxisEvents {
'trackpadmoved': CustomEvent<{ x: number; y: number }>; // Trackpad axis
'thumbstickmoved': CustomEvent<{ x: number; y: number }>; // Thumbstick axis
'triggerchanged': CustomEvent<{ value: number }>; // Trigger value (0-1)
'gripchanged': CustomEvent<{ value: number }>; // Grip value (0-1)
}// Controller connection events
interface ConnectionEvents {
'controllerconnected': CustomEvent; // Controller connected
'controllerdisconnected': CustomEvent; // Controller disconnected
}// Oculus Touch specific events
interface OculusTouchEvents {
// Left controller
'xbuttondown': CustomEvent; // X button
'xbuttonup': CustomEvent;
'ybuttondown': CustomEvent; // Y button
'ybuttonup': CustomEvent;
// Right controller
'abuttondown': CustomEvent; // A button
'abuttonup': CustomEvent;
'bbuttondown': CustomEvent; // B button
'bbuttonup': CustomEvent;
// Touch events
'xbuttontouchstart': CustomEvent;
'xbuttontouchend': CustomEvent;
'ybuttontouchstart': CustomEvent;
'ybuttontouchend': CustomEvent;
'abuttontouchstart': CustomEvent;
'abuttontouchend': CustomEvent;
'bbuttontouchstart': CustomEvent;
'bbuttontouchend': CustomEvent;
}// Vive controller specific events
interface ViveControllerEvents {
'trackpaddown': CustomEvent; // Trackpad click
'trackpadup': CustomEvent;
'trackpadtouchstart': CustomEvent; // Trackpad touch
'trackpadtouchend': CustomEvent;
'trackpadmoved': CustomEvent<{ x: number; y: number }>;
'menudown': CustomEvent; // Menu button
'menuup': CustomEvent;
}<a-scene>
<!-- VR camera rig -->
<a-entity id="cameraRig" position="0 1.6 3">
<a-camera look-controls wasd-controls></a-camera>
<!-- Oculus Touch controllers -->
<a-entity oculus-touch-controls="hand: left" id="leftController"></a-entity>
<a-entity oculus-touch-controls="hand: right" id="rightController"></a-entity>
<!-- Vive controllers (alternative) -->
<!-- <a-entity vive-controls="hand: left"></a-entity> -->
<!-- <a-entity vive-controls="hand: right"></a-entity> -->
</a-entity>
<!-- Scene content -->
<a-box class="clickable" position="0 0.5 -3" color="red"></a-box>
</a-scene><a-entity
id="rightController"
oculus-touch-controls="hand: right"
raycaster="objects: .clickable; showLine: true">
</a-entity>
<script>
const rightController = document.querySelector('#rightController');
// Button press handlers
rightController.addEventListener('triggerdown', function(evt) {
console.log('Trigger pressed');
// Perform action like shooting or grabbing
});
rightController.addEventListener('abuttondown', function(evt) {
console.log('A button pressed');
// Toggle menu or perform secondary action
});
rightController.addEventListener('thumbstickmoved', function(evt) {
const { x, y } = evt.detail;
console.log('Thumbstick moved:', x, y);
// Use for locomotion or navigation
});
// Interaction events from raycaster
rightController.addEventListener('raycaster-intersection', function(evt) {
const intersectedEl = evt.detail.els[0];
console.log('Pointing at:', intersectedEl);
intersectedEl.setAttribute('material', 'color', 'blue');
});
rightController.addEventListener('raycaster-intersection-cleared', function(evt) {
const clearedEl = evt.detail.clearedEls[0];
if (clearedEl) {
clearedEl.setAttribute('material', 'color', 'red');
}
});
</script><a-scene>
<!-- Hand tracking entities -->
<a-entity
hand-tracking-controls="hand: left"
id="leftHand">
</a-entity>
<a-entity
hand-tracking-controls="hand: right"
id="rightHand">
</a-entity>
<!-- Interactable objects -->
<a-box
class="grabbable"
position="0 1 -2"
grabbable>
</a-box>
</a-scene>
<script>
// Hand tracking events
document.querySelector('#rightHand').addEventListener('pinchstarted', function(evt) {
console.log('Pinch gesture started');
});
document.querySelector('#rightHand').addEventListener('pinchended', function(evt) {
console.log('Pinch gesture ended');
});
</script><a-entity
id="rightLaser"
laser-controls="hand: right"
raycaster="objects: .clickable; showLine: true; lineColor: red; lineOpacity: 0.75">
</a-entity>
<!-- Clickable objects -->
<a-box class="clickable" position="-2 1 -3" color="blue"></a-box>
<a-sphere class="clickable" position="0 1 -3" color="green"></a-sphere>
<a-cylinder class="clickable" position="2 1 -3" color="yellow"></a-cylinder>
<script>
const laser = document.querySelector('#rightLaser');
laser.addEventListener('triggerdown', function(evt) {
// Get the intersected element
const raycaster = laser.components.raycaster;
const intersection = raycaster.intersectedEls[0];
if (intersection) {
// Animate clicked object
intersection.setAttribute('animation', {
property: 'scale',
to: '1.2 1.2 1.2',
dur: 200,
dir: 'alternate',
loop: 1
});
}
});
</script>