diff --git a/public/room.html b/public/room.html
index 85f93514a863761945a8a6564fc24d31d4cfec1e..03c8dd6a33c4e9e6e095aa9d195f8243e2759df9 100644
--- a/public/room.html
+++ b/public/room.html
@@ -50,10 +50,10 @@
             <script id="head-template" type="text/html">
                 <a-entity
                     class="head"
-                    gltf-model2="#bot-head-mesh"
                     networked-audio-source
                     networked-audio-analyser
                     matcolor-audio-feedback="objectName: Head_Mesh"
+                    cached-gltf-model="#bot-head-mesh"
                     scale-audio-feedback
                     personal-space-invader
                     rotation="0 180 0"
@@ -64,7 +64,7 @@
             <script id="body-template" type="text/html">
                 <a-entity
                     class="body"
-                    gltf-model2="#bot-body-mesh"
+                    cached-gltf-model="#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-model2="#bot-left-hand-mesh"
+                    cached-gltf-model="#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-model2="#bot-right-hand-mesh"
+                    cached-gltf-model="#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-model2="assets/hud/watch.gltf"
+                    cached-gltf-model="assets/hud/watch.gltf"
                     position="0 0.0015 0.147"
                     rotation="3.5 0 0"
                 >
@@ -175,17 +175,17 @@
 
         <!-- Environment -->
         <a-entity
-            gltf-model2="#meeting-space1-mesh"
+            cached-gltf-model="#meeting-space1-mesh"
             position="0 0 0"
         ></a-entity>
 
         <a-entity
-            gltf-model2="#outdoor-facade-mesh"
+            cached-gltf-model="#outdoor-facade-mesh"
             position="0 0 0"
         ></a-entity>
 
         <a-entity
-            gltf-model2="#floor-nav-mesh"
+            cached-gltf-model="#floor-nav-mesh"
             visible="false"
             position="0 0 0"
         ></a-entity>
diff --git a/src/components/cached-gltf-model.js b/src/components/cached-gltf-model.js
new file mode 100644
index 0000000000000000000000000000000000000000..c50b6788228ddb2a79beaa9202ac50be6a75adcf
--- /dev/null
+++ b/src/components/cached-gltf-model.js
@@ -0,0 +1,126 @@
+import "../vendor/GLTFLoader";
+
+const GLTFCache = {};
+
+// From https://gist.github.com/cdata/f2d7a6ccdec071839bc1954c32595e87
+// Tracking glTF cloning here: https://github.com/mrdoob/three.js/issues/11573
+function cloneGltf(gltf) {
+  const clone = {
+    animations: gltf.animations,
+    scene: gltf.scene.clone(true)
+  };
+
+  const skinnedMeshes = {};
+
+  gltf.scene.traverse(node => {
+    if (node.isSkinnedMesh) {
+      skinnedMeshes[node.name] = node;
+    }
+  });
+
+  const cloneBones = {};
+  const cloneSkinnedMeshes = {};
+
+  clone.scene.traverse(node => {
+    if (node.isBone) {
+      cloneBones[node.name] = node;
+    }
+
+    if (node.isSkinnedMesh) {
+      cloneSkinnedMeshes[node.name] = node;
+    }
+  });
+
+  for (const name in skinnedMeshes) {
+    const skinnedMesh = skinnedMeshes[name];
+    const skeleton = skinnedMesh.skeleton;
+    const cloneSkinnedMesh = cloneSkinnedMeshes[name];
+
+    const orderedCloneBones = [];
+
+    for (let i = 0; i < skeleton.bones.length; ++i) {
+      const cloneBone = cloneBones[skeleton.bones[i].name];
+      orderedCloneBones.push(cloneBone);
+    }
+
+    cloneSkinnedMesh.bind(
+      new THREE.Skeleton(orderedCloneBones, skeleton.boneInverses),
+      cloneSkinnedMesh.matrixWorld
+    );
+
+    cloneSkinnedMesh.material = skinnedMesh.material.clone();
+  }
+
+  return clone;
+}
+
+/**
+ * glTF model loader.
+ */
+AFRAME.registerComponent("cached-gltf-model", {
+  schema: { type: "model" },
+
+  init: function() {
+    this.model = null;
+    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;
+    }
+
+    // Remove any existing model
+    this.remove();
+
+    // Load the gltf model from the cache if it exists.
+    const gltf = GLTFCache[src];
+
+    if (gltf) {
+      // Use a cloned copy of the cached model.
+      const clonedGltf = cloneGltf(gltf);
+      this.onLoad(clonedGltf);
+      return;
+    }
+
+    // Otherwise load the new gltf model.
+    new THREE.GLTFLoader().load(
+      src,
+      this.onLoad,
+      undefined /* onProgress */,
+      this.onError
+    );
+  },
+
+  onLoad(gltfModel) {
+    if (!GLTFCache[this.data]) {
+      // Store a cloned copy of the gltf model.
+      GLTFCache[this.data] = cloneGltf(gltfModel);
+    }
+
+    this.model = gltfModel.scene || gltfModel.scenes[0];
+    this.model.animations = gltfModel.animations;
+
+    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/components/gltf-model2.js b/src/components/gltf-model2.js
deleted file mode 100644
index 868c1a4604e0fcca36eec7f9ef5382bd1863c7e0..0000000000000000000000000000000000000000
--- a/src/components/gltf-model2.js
+++ /dev/null
@@ -1,68 +0,0 @@
-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 29948633419588c3d441f456fac77b25b3d935ce..a39a9762915693ada0adf431f655b3b71f0379f3 100644
--- a/src/index.js
+++ b/src/index.js
@@ -22,7 +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 "./components/cached-gltf-model";
 import "./systems/personal-space-bubble";
 
 import registerNetworkScheams from "./network-schemas";