diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..963354f23168f2e9f79b42c261c612cc662e849c
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,3 @@
+{
+  "printWidth": 120
+}
diff --git a/src/behaviours/oculus-touch-joystick-dpad4.js b/src/behaviours/oculus-touch-joystick-dpad4.js
index ed85bca9555cf127d6fd90e196753cfcd47e9f97..758fb603c70faceb932539d722e08976e603046d 100644
--- a/src/behaviours/oculus-touch-joystick-dpad4.js
+++ b/src/behaviours/oculus-touch-joystick-dpad4.js
@@ -1,4 +1,4 @@
-import { angleTo4Direction, angleTo8Direction } from "../utils";
+import { angleTo4Direction, angleTo8Direction } from "../utils/dpad";
 
 // @TODO specify 4 or 8 direction
 function oculus_touch_joystick_dpad4(el, outputPrefix) {
diff --git a/src/behaviours/vive-trackpad-dpad4.js b/src/behaviours/vive-trackpad-dpad4.js
index 4ef7364ab7d8ee4c22780c68b1183b4eba0db82a..3f4e3a275a4c6bad6a74aa6ef3c8836bb3a26500 100644
--- a/src/behaviours/vive-trackpad-dpad4.js
+++ b/src/behaviours/vive-trackpad-dpad4.js
@@ -1,4 +1,4 @@
-import { angleTo4Direction, angleTo8Direction } from "../utils";
+import { angleTo4Direction, angleTo8Direction } from "../utils/dpad";
 
 function vive_trackpad_dpad4(el, outputPrefix) {
   this.outputPrefix = outputPrefix;
diff --git a/src/room.js b/src/room.js
index e2c1600e9d1fe465a72f4d6bc1642d589ab50d98..d6e4fe75eac02e0ff34812713c9663277d303970 100644
--- a/src/room.js
+++ b/src/room.js
@@ -1,5 +1,8 @@
 import queryString from "query-string";
 
+import { patchWebGLRenderingContext } from "./utils/webgl";
+patchWebGLRenderingContext();
+
 import "aframe";
 import "./vendor/GLTFLoader";
 import "networked-aframe";
@@ -36,7 +39,7 @@ import "./components/layers";
 import "./components/spawn-controller";
 import "./systems/personal-space-bubble";
 
-import { promptForName, getCookie, parseJwt } from "./utils";
+import { promptForName, getCookie, parseJwt } from "./utils/identity";
 import registerNetworkSchemas from "./network-schemas";
 import { inGameActions, config } from "./input-mappings";
 import registerTelemetry from "./telemetry";
diff --git a/src/utils/dpad.js b/src/utils/dpad.js
new file mode 100644
index 0000000000000000000000000000000000000000..6f135122e6408bfdbc0a5a87d373104cbdc2e9bd
--- /dev/null
+++ b/src/utils/dpad.js
@@ -0,0 +1,30 @@
+export function angleTo4Direction(angle) {
+  angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360;
+  if (angle > 0 && angle < 90) {
+    return "north";
+  } else if (angle >= 90 && angle < 180) {
+    return "west";
+  } else if (angle >= 180 && angle < 270) {
+    return "south";
+  } else {
+    return "east";
+  }
+}
+
+export function angleTo8Direction(angle) {
+  angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360;
+  var direction = "";
+  if ((angle >= 0 && angle < 120) || angle >= 330) {
+    direction += "north";
+  }
+  if (angle >= 150 && angle < 300) {
+    direction += "south";
+  }
+  if (angle >= 60 && angle < 210) {
+    direction += "west";
+  }
+  if ((angle >= 240 && angle < 360) || angle < 30) {
+    direction += "east";
+  }
+  return direction;
+}
diff --git a/src/utils.js b/src/utils/identity.js
similarity index 78%
rename from src/utils.js
rename to src/utils/identity.js
index 346f0994cf16943b7461a34e778cca16c87eebfc..54539286368182b31b49ae77a4e0d42898d78931 100644
--- a/src/utils.js
+++ b/src/utils/identity.js
@@ -190,34 +190,3 @@ export function parseJwt(token) {
   var base64 = base64Url.replace("-", "+").replace("_", "/");
   return JSON.parse(window.atob(base64));
 }
-
-export function angleTo4Direction(angle) {
-  angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360;
-  if (angle > 0 && angle < 90) {
-    return "north";
-  } else if (angle >= 90 && angle < 180) {
-    return "west";
-  } else if (angle >= 180 && angle < 270) {
-    return "south";
-  } else {
-    return "east";
-  }
-}
-
-export function angleTo8Direction(angle) {
-  angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360;
-  var direction = "";
-  if ((angle >= 0 && angle < 120) || angle >= 330) {
-    direction += "north";
-  }
-  if (angle >= 150 && angle < 300) {
-    direction += "south";
-  }
-  if (angle >= 60 && angle < 210) {
-    direction += "west";
-  }
-  if ((angle >= 240 && angle < 360) || angle < 30) {
-    direction += "east";
-  }
-  return direction;
-}
diff --git a/src/utils/webgl.js b/src/utils/webgl.js
new file mode 100644
index 0000000000000000000000000000000000000000..a209b3e75efa31f888b3890ef68ba07b9f52253d
--- /dev/null
+++ b/src/utils/webgl.js
@@ -0,0 +1,34 @@
+import AFRAME from "aframe";
+const THREE = AFRAME.THREE;
+
+function checkFloatTextureSupport() {
+  const renderer = new THREE.WebGLRenderer();
+
+  const scene = new THREE.Scene();
+  const dataTexture = new THREE.DataTexture(new Float32Array(2 * 2 * 4), 2, 2, THREE.RGBAFormat, THREE.FloatType);
+  const box = new THREE.Mesh(new THREE.PlaneBufferGeometry(1, 1), new THREE.MeshBasicMaterial({ map: dataTexture }));
+  box.material.map.needsUpdate = true;
+  scene.add(box);
+
+  renderer.render(scene, new THREE.Camera());
+  return renderer.context.getError() === 0;
+}
+let supportsFloatTextures = checkFloatTextureSupport();
+
+export function patchWebGLRenderingContext() {
+  const originalGetExtension = WebGLRenderingContext.prototype.getExtension;
+  WebGLRenderingContext.prototype.getExtension = function patchedGetExtension(name) {
+    // It appears that Galaxy S6 devices falsely report that they support OES_texture_float in Firefox.
+    // This workaround disables float textures for those devices.
+    // See https://github.com/mozilla/mr-social-client/issues/32 and https://bugzilla.mozilla.org/show_bug.cgi?id=1338656
+    if (name === "OES_texture_float" && /Android.+Firefox/.test(navigator.userAgent)) {
+      if (supportsFloatTextures === undefined) {
+        supportsFloatTextures = checkFloatTextureSupport();
+      }
+      if (!supportsFloatTextures) {
+        return null;
+      }
+    }
+    return originalGetExtension.call(this, name);
+  };
+}