diff --git a/src/components/virtual-gamepad-controls.css b/src/components/virtual-gamepad-controls.css
index d3e36e2fa243e0d9e35e693224cbd235420a0702..572e6169f6a29c911d0fa89e37382b10838da3c0 100644
--- a/src/components/virtual-gamepad-controls.css
+++ b/src/components/virtual-gamepad-controls.css
@@ -1,6 +1,6 @@
 :local(.touchZone) {
   position: absolute;
-  top: 0;
+  height: 20vh;
   bottom: 0;
 }
 
@@ -13,7 +13,3 @@
   left: 50%;
   right: 0;
 }
-
-:local(.touchZone) .nipple {
-  margin: 5vh 5vw;
-}
diff --git a/src/components/virtual-gamepad-controls.js b/src/components/virtual-gamepad-controls.js
index d70219bf1e6374fefc6d6daaeb9e8e10bfc27fb8..f92b7d4534f8e45e499edf6bcf1345f9e0f33374 100644
--- a/src/components/virtual-gamepad-controls.js
+++ b/src/components/virtual-gamepad-controls.js
@@ -16,29 +16,42 @@ AFRAME.registerComponent("virtual-gamepad-controls", {
 
     const leftStick = nipplejs.create({
       zone: leftTouchZone,
-      mode: "static",
       color: "white",
-      position: { left: "50px", bottom: "50px" }
+      fadeTime: 0
     });
 
     const rightStick = nipplejs.create({
       zone: rightTouchZone,
-      mode: "static",
       color: "white",
-      position: { right: "50px", bottom: "50px" }
+      fadeTime: 0
     });
 
-    this.onJoystickChanged = this.onJoystickChanged.bind(this);
+    this.onMoveJoystickChanged = this.onMoveJoystickChanged.bind(this);
+    this.onMoveJoystickEnd = this.onMoveJoystickEnd.bind(this);
+    this.onLookJoystickChanged = this.onLookJoystickChanged.bind(this);
+    this.onLookJoystickEnd = this.onLookJoystickEnd.bind(this);
 
-    rightStick.on("move end", this.onJoystickChanged);
-    leftStick.on("move end", this.onJoystickChanged);
+    leftStick.on("move", this.onMoveJoystickChanged);
+    leftStick.on("end", this.onMoveJoystickEnd);
+
+    rightStick.on("move", this.onLookJoystickChanged);
+    rightStick.on("end", this.onLookJoystickEnd);
 
     this.leftTouchZone = leftTouchZone;
     this.rightTouchZone = rightTouchZone;
     this.leftStick = leftStick;
     this.rightStick = rightStick;
 
-    this.yaw = 0;
+    this.inVr = false;
+    this.moving = false;
+    this.rotating = false;
+
+    this.moveEvent = {
+      axis: [0, 0]
+    };
+    this.rotateYEvent = {
+      value: 0
+    };
 
     this.onEnterVr = this.onEnterVr.bind(this);
     this.onExitVr = this.onExitVr.bind(this);
@@ -46,39 +59,59 @@ AFRAME.registerComponent("virtual-gamepad-controls", {
     this.el.sceneEl.addEventListener("exit-vr", this.onExitVr);
   },
 
-  onJoystickChanged(event, joystick) {
-    if (event.target.id === this.leftStick.id) {
-      if (event.type === "move") {
-        const angle = joystick.angle.radian;
-        const force = joystick.force < 1 ? joystick.force : 1;
-        const x = Math.cos(angle) * force;
-        const z = Math.sin(angle) * force;
-        this.el.sceneEl.emit("move", { axis: [x, z] });
-      } else {
-        this.el.sceneEl.emit("move", { axis: [0, 0] });
+  onMoveJoystickChanged(event, joystick) {
+    const angle = joystick.angle.radian;
+    const force = joystick.force < 1 ? joystick.force : 1;
+    const x = Math.cos(angle) * force;
+    const z = Math.sin(angle) * force;
+    this.moving = true;
+    this.moveEvent.axis[0] = x;
+    this.moveEvent.axis[1] = z;
+  },
+
+  onMoveJoystickEnd() {
+    this.moving = false;
+    this.moveEvent.axis[0] = 0;
+    this.moveEvent.axis[1] = 0;
+    this.el.sceneEl.emit("move", this.moveEvent);
+  },
+
+  onLookJoystickChanged(event, joystick) {
+    // Set pitch and yaw angles on right stick move
+    const angle = joystick.angle.radian;
+    const force = joystick.force < 1 ? joystick.force : 1;
+    this.rotating = true;
+    this.rotateYEvent.value = Math.cos(angle) * force;
+  },
+
+  onLookJoystickEnd() {
+    this.rotating = false;
+    this.rotateYEvent.value = 0;
+    this.el.sceneEl.emit("rotateY", this.rotateYEvent);
+  },
+
+  tick() {
+    if (!this.inVr) {
+      if (this.moving) {
+        this.el.sceneEl.emit("move", this.moveEvent);
       }
-    } else {
-      if (event.type === "move") {
-        // Set pitch and yaw angles on right stick move
-        const angle = joystick.angle.radian;
-        const force = joystick.force < 1 ? joystick.force : 1;
-        this.yaw = Math.cos(angle) * force;
-        this.el.sceneEl.emit("rotateY", { value: this.yaw });
-      } else {
-        this.yaw = 0;
-        this.el.sceneEl.emit("rotateY", { value: this.yaw });
+
+      if (this.rotating) {
+        this.el.sceneEl.emit("rotateY", this.rotateYEvent);
       }
     }
   },
 
   onEnterVr() {
     // Hide the joystick controls
+    this.inVr = true;
     this.leftTouchZone.style.display = "none";
     this.rightTouchZone.style.display = "none";
   },
 
   onExitVr() {
     // Show the joystick controls
+    this.inVr = false;
     this.leftTouchZone.style.display = "block";
     this.rightTouchZone.style.display = "block";
   },
diff --git a/src/hub.js b/src/hub.js
index 9f2c8ffd8901d091b1108ef3ba6838f4d5c7e6d7..19669290064c43131ee2412cf5cac2c58e386123 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -150,7 +150,7 @@ async function enterScene(mediaStream, enterInVR, janusRoomId) {
     scene.setAttribute("stats", true);
   }
 
-  if (isMobile || qsTruthy(qs.mobile)) {
+  if (isMobile || qsTruthy("mobile")) {
     playerRig.setAttribute("virtual-gamepad-controls", {});
   }