diff --git a/src/components/character-controller.js b/src/components/character-controller.js
index e811dd507bc8f5a0d886b1c912cc7679ebdf55a8..26dc12a8cd1e36eefe4d4ab65faee4c559576f09 100644
--- a/src/components/character-controller.js
+++ b/src/components/character-controller.js
@@ -89,7 +89,8 @@ AFRAME.registerComponent("character-controller", {
     const rotationInvMatrix = new THREE.Matrix4();
     const pivotRotationMatrix = new THREE.Matrix4();
     const pivotRotationInvMatrix = new THREE.Matrix4();
-    const start = new THREE.Vector3();
+    const startPos = new THREE.Vector3();
+    const startScale = new THREE.Vector3();
 
     return function(t, dt) {
       const deltaSeconds = dt / 1000;
@@ -98,7 +99,8 @@ AFRAME.registerComponent("character-controller", {
       const distance = this.data.groundAcc * deltaSeconds;
       const rotationDelta = this.data.rotationSpeed * this.angularVelocity * deltaSeconds;
 
-      start.copy(root.position);
+      startScale.copy(root.scale);
+      startPos.copy(root.position);
 
       // Other aframe components like teleport-controls set position/rotation/scale, not the matrix, so we need to make sure to compose them back into the matrix
       root.updateMatrix();
@@ -134,19 +136,13 @@ AFRAME.registerComponent("character-controller", {
       // Reapply playspace (player rig) translation
       root.applyMatrix(trans);
 
-      // @TODO this is really ugly, can't just set the position/rotation directly or they wont network
-      this.el.setAttribute("rotation", {
-        x: root.rotation.x * THREE.Math.RAD2DEG,
-        y: root.rotation.y * THREE.Math.RAD2DEG,
-        z: root.rotation.z * THREE.Math.RAD2DEG
-      });
+      // TODO: the above matrix trnsfomraitons introduce some floating point erros in scale, this reverts them to avoid spamming network with fake scale updates
+      root.scale.copy(startScale);
 
       this.pendingSnapRotationMatrix.identity(); // Revert to identity
 
       if (this.velocity.lengthSq() > EPS) {
-        this.setPositionOnNavMesh(start, root);
-      } else {
-        this.el.setAttribute("position", root.position);
+        this.setPositionOnNavMesh(startPos, root);
       }
     };
   })(),
diff --git a/src/components/wasd-to-analog2d.js b/src/components/wasd-to-analog2d.js
index 35b68026bd121a35bb7f7c139d15423262475b86..a86641623b348f67c743e1845f51dd1c6e9ccb7f 100644
--- a/src/components/wasd-to-analog2d.js
+++ b/src/components/wasd-to-analog2d.js
@@ -11,9 +11,11 @@ AFRAME.registerComponent("wasd-to-analog2d", {
       s: [0, -1],
       d: [1, 0]
     };
-    this.onWasd = this.onWasd.bind(this);
     this.keys = {};
+
+    this.onWasd = this.onWasd.bind(this);
     this.move = this.move.bind(this);
+    this.onBlur = this.onBlur.bind(this);
   },
 
   play: function() {
@@ -25,18 +27,24 @@ AFRAME.registerComponent("wasd-to-analog2d", {
     // directly because ideally this would live as an input mapping, but the events
     // generated by this component won't actually get mapped.
     this.el.sceneEl.addEventListener(this.data.analog2dOutputAction, this.move);
-  },
-
-  move: function(event) {
-    this.el.emit("move", { axis: event.detail.axis });
+    window.addEventListener("blur", this.onBlur);
   },
 
   pause: function() {
     this.el.sceneEl.removeEventListener("wasd", this.onWasd);
     this.el.sceneEl.removeEventListener(this.data.analog2dOutputAction, this.move);
+    window.removeEventListener("blur", this.onBlur);
     this.keys = {};
   },
 
+  onBlur: function() {
+    this.keys = {};
+  },
+
+  move: function(event) {
+    this.el.emit("move", { axis: event.detail.axis });
+  },
+
   onWasd: function(event) {
     const keyEvent = event.type;
     const down = keyEvent.indexOf("down") !== -1;
diff --git a/src/index.js b/src/index.js
index 198ee8d47378bd740fc9a2891cc6945447442b2a..2383019035144bc82277e15baa01b034f6244754 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,8 +1,16 @@
 import "./assets/stylesheets/index.scss";
 import React from "react";
 import ReactDOM from "react-dom";
-import HomeRoot from "./react-components/home-root";
 import registerTelemetry from "./telemetry";
+import HomeRoot from "./react-components/home-root";
+import InfoDialog from "./react-components/info-dialog.js";
+import queryString from "query-string";
+
+const qs = queryString.parse(location.search);
 
 registerTelemetry();
-ReactDOM.render(<HomeRoot />, document.getElementById("home-root"));
+
+ReactDOM.render(
+  <HomeRoot dialogType={qs.list_signup ? InfoDialog.dialogTypes.updates : null} />,
+  document.getElementById("home-root")
+);
diff --git a/src/react-components/home-root.js b/src/react-components/home-root.js
index f930eaea721535e886cc0ddbeb9611f8644da52c..6e780474b5ecf98164f6e34cc47e6dcc9a0551ac 100644
--- a/src/react-components/home-root.js
+++ b/src/react-components/home-root.js
@@ -27,7 +27,8 @@ const ENVIRONMENT_URLS = [
 
 class HomeRoot extends Component {
   static propTypes = {
-    intl: PropTypes.object
+    intl: PropTypes.object,
+    dialogType: PropTypes.symbol
   };
 
   state = {
@@ -39,6 +40,7 @@ class HomeRoot extends Component {
 
   componentDidMount() {
     this.loadEnvironments();
+    this.setState({ dialogType: this.props.dialogType });
     document.querySelector("#background-video").playbackRate = 0.75;
   }