Basic Movement And Teleportation In VR With A-Frame

Michael McAnally
4 min readDec 7, 2020


A-Frame. That’s what I use to do WebXR in a browser.

Problem is with all the VR headsets out there it is hard to write code that works for everyone’s hand controllers. In Android that would be called fragmentation.

Also, it looks like it will be some time before we can get rid of hand controllers all together and start using hand tracking, much like in Minority Report.

So here is what works for me:

<!-- nav-mesh: protecting us from running thru things  -->
<a-entity id="navmesh-Hello" gltf-model="assets/gltf/AdvHelloWorldnavmesh.gltf" visible="false" nav-mesh=""></a-entity>
<!-- Basic movement and teleportation -->
<a-entity id="cameraRig" movement-controls="constrainToNavMesh: true;" navigator="cameraRig: #cameraRig; cameraHead: #head; collisionEntities: .collision; ignoreEntities: .clickable" position="0 0 0" rotation="0 0 0">
<!-- camera -->
<a-entity id="head" camera="active: true" position="0 1.6 0" look-controls="pointerLockEnabled: true; reverseMouseDrag: true" ></a-entity>
<!-- Left Controller -->
<a-entity id="leftHand" hand-controls="hand: left; handModelStyle: lowPoly; color: #15ACCF" teleport-controls="cameraRig: #cameraRig; teleportOrigin: #head; button: trigger; curveShootingSpeed: 18; landingMaxAngle: 60" visible="true"></a-entity>
<!-- Right Controller -->
<a-entity id="rightHand" hand-controls="hand: right; handModelStyle: lowPoly; color: #15ACCF" laser-controls raycaster="showLine: true; far: 10; interval: 0; objects: .clickable, a-link;" line="color: #7cfc00; opacity: 0.5" visible="true"></a-entity>

A Navmesh is used to stop us from running through things in VR while moving around. It’s one of the last things you’ll generate for your scene. So let’s skip ahead. Until then just comment out the navmesh entity and change constrainToNavMesh: true; to constrainToNavMesh: false; in the movement-controls on the cameraRig entity. You can switch back later after you have created your Navmesh.

Movement and teleportation, that’s what we are mostly concerned about. If you’re like me, and you don’t have a large play area for VR, then you are going to want to move around mostly with your hand controllers.

So two concepts here, the Camera Rig and the Camera. Finally the Left Controller and the Right Controller. Notice in the example above the Left and Right Controllers are nested entities within the Camera, which is within the Camera Rig. Ordered layout is important here.

On the Right Hand Controller we have hand-controls and a laser-controls activated by the trigger button common to most controllers.

On the Left Hand Controller we have hand-controls again and a teleport-controls, again activated by the trigger button.

We use movement-controls to move the Camera Rig around, which in turn moves the Camera around, activated by the toggle sticks or touch pads on your controllers, sometimes right or sometimes left.

This also allows for movement on the Desktop with the WASD keys or the arrow keys. This is nice for those who do not have a VR Headset to try out the experience.

Of course you’ll need the corresponding JavaScript component libraries to make this work in your HTML:

So that’s it. By adding the above section of HTML to the A-Frame scene you will have movement and teleportation.

PLEASE NOTE: Some of my older code included parameters for specific types of controllers, HTC Vive, Windows Mixed Reality (WMR) and Oculus Touch.

tracked-controls vive-controls="hand: left" oculus-touch-controls="hand: left" windows-motion-controls="hand: left"

These are no longer necessary. Remove them. Tracked-controls is redundant and the other controller types are included already in hand-controls. I will be updating my code example shortly.


If you enjoyed this tip, please clap me up. Visit my VR blog at:



Michael McAnally

Temporary gathering of sentient stardust. Free thinker. Evolving human. Writer, coder, and artist.