diff --git a/public/room.html b/public/room.html
index b44af42514f4061e85dd11b90c76bff330a49adc..85f93514a863761945a8a6564fc24d31d4cfec1e 100644
--- a/public/room.html
+++ b/public/room.html
@@ -50,7 +50,7 @@
             <script id="head-template" type="text/html">
                 <a-entity
                     class="head"
-                    gltf-model="#bot-head-mesh"
+                    gltf-model2="#bot-head-mesh"
                     networked-audio-source
                     networked-audio-analyser
                     matcolor-audio-feedback="objectName: Head_Mesh"
@@ -64,7 +64,7 @@
             <script id="body-template" type="text/html">
                 <a-entity
                     class="body"
-                    gltf-model="#bot-body-mesh"
+                    gltf-model2="#bot-body-mesh"
                     personal-space-invader
                     rotation="0 180 0"
                     position="0 -0.05 0"
@@ -74,7 +74,7 @@
             <script id="left-hand-template" type="text/html">
                 <a-entity
                     class="hand"
-                    gltf-model="#bot-left-hand-mesh"
+                    gltf-model2="#bot-left-hand-mesh"
                     animation-mixer
                     personal-space-invader
                     rotation="-90 90 0"
@@ -85,7 +85,7 @@
             <script id="right-hand-template" type="text/html">
                 <a-entity
                     class="hand"
-                    gltf-model="#bot-right-hand-mesh"
+                    gltf-model2="#bot-right-hand-mesh"
                     personal-space-invader
                     rotation="-90 -90 0"
                     position="0 0 0.075"
@@ -144,7 +144,7 @@
             >
                 <a-entity
                     id="watch"
-                    gltf-model="assets/hud/watch.gltf"
+                    gltf-model2="assets/hud/watch.gltf"
                     position="0 0.0015 0.147"
                     rotation="3.5 0 0"
                 >
@@ -175,17 +175,17 @@
 
         <!-- Environment -->
         <a-entity
-            gltf-model="#meeting-space1-mesh"
+            gltf-model2="#meeting-space1-mesh"
             position="0 0 0"
         ></a-entity>
 
         <a-entity
-            gltf-model="#outdoor-facade-mesh"
+            gltf-model2="#outdoor-facade-mesh"
             position="0 0 0"
         ></a-entity>
 
         <a-entity
-            gltf-model="#floor-nav-mesh"
+            gltf-model2="#floor-nav-mesh"
             visible="false"
             position="0 0 0"
         ></a-entity>
diff --git a/src/components/gltf-model2.js b/src/components/gltf-model2.js
new file mode 100644
index 0000000000000000000000000000000000000000..868c1a4604e0fcca36eec7f9ef5382bd1863c7e0
--- /dev/null
+++ b/src/components/gltf-model2.js
@@ -0,0 +1,68 @@
+import "../vendor/GLTFLoader";
+
+const GLTFCache = {};
+
+/**
+ * glTF model loader.
+ */
+AFRAME.registerComponent("gltf-model2", {
+  schema: { type: "model" },
+
+  init: function() {
+    this.model = null;
+    this.loader = new THREE.GLTFLoader();
+    this.onLoad = this.onLoad.bind(this);
+    this.onError = this.onError.bind(this);
+  },
+
+  update: function() {
+    const self = this;
+    const el = this.el;
+    const src = this.data;
+
+    if (!src) {
+      return;
+    }
+
+    const cachedModel = GLTFCache[src];
+
+    if (cachedModel) {
+      this.model = cachedModel.clone(true);
+      this.model.visible = true;
+      this.model.animations = cachedModel.animations;
+      this.el.setObject3D("mesh", this.model);
+      this.el.emit("model-loaded", { format: "gltf", model: this.model });
+    }
+
+    this.remove();
+
+    this.loader.load(
+      src,
+      this.onLoad,
+      undefined /* onProgress */,
+      this.onError
+    );
+  },
+
+  onLoad(gltfModel) {
+    this.model = gltfModel.scene || gltfModel.scenes[0];
+    this.model.animations = gltfModel.animations;
+    GLTFCache[this.data] = this.model;
+    this.el.setObject3D("mesh", this.model);
+    this.el.emit("model-loaded", { format: "gltf", model: this.model });
+  },
+
+  onError(error) {
+    const message =
+      error && error.message ? error.message : "Failed to load glTF model";
+    console.warn(message);
+    this.el.emit("model-error", { format: "gltf", src: this.data });
+  },
+
+  remove: function() {
+    if (!this.model) {
+      return;
+    }
+    this.el.removeObject3D("mesh");
+  }
+});
diff --git a/src/index.js b/src/index.js
index 7a82341d8c6e2f943158ab2b3f1fdcf405e325e5..29948633419588c3d441f456fac77b25b3d935ce 100644
--- a/src/index.js
+++ b/src/index.js
@@ -22,6 +22,7 @@ import "./components/character-controller";
 import "./components/split-axis-events";
 import "./components/networked-video-player";
 import "./components/offset-relative-to";
+import "./components/gltf-model2";
 import "./systems/personal-space-bubble";
 
 import registerNetworkScheams from "./network-schemas";