diff --git a/src/components/image-plus.js b/src/components/image-plus.js
index f23efefcdf0f5b741ebc63ffbe2730562391c92d..bbe1238414e5c4702aa6dfd556476e786a33a074 100644
--- a/src/components/image-plus.js
+++ b/src/components/image-plus.js
@@ -1,6 +1,5 @@
 import GIFWorker from "../workers/gifparsing.worker.js";
 import errorImageSrc from "!!url-loader!../assets/images/media-error.gif";
-import { resolveMedia } from "../utils/media-utils";
 
 class GIFTexture extends THREE.Texture {
   constructor(frames, delays, disposals) {
@@ -37,6 +36,41 @@ class GIFTexture extends THREE.Texture {
   }
 }
 
+async function createGIFTexture(url) {
+  return new Promise((resolve, reject) => {
+    // TODO: pool workers
+    const worker = new GIFWorker();
+    worker.onmessage = e => {
+      const [success, frames, delays, disposals] = e.data;
+      if (!success) {
+        reject(`error loading gif: ${e.data[1]}`);
+        return;
+      }
+
+      let loadCnt = 0;
+      for (let i = 0; i < frames.length; i++) {
+        const img = new Image();
+        img.onload = e => {
+          loadCnt++;
+          frames[i] = e.target;
+          if (loadCnt === frames.length) {
+            const texture = new GIFTexture(frames, delays, disposals);
+            texture.image.src = url;
+            resolve(texture);
+          }
+        };
+        img.src = frames[i];
+      }
+    };
+    fetch(url, { mode: "cors" })
+      .then(r => r.arrayBuffer())
+      .then(rawImageData => {
+        worker.postMessage(rawImageData, [rawImageData]);
+      })
+      .catch(reject);
+  });
+}
+
 /**
  * Create video element to be used as a texture.
  *
@@ -54,8 +88,42 @@ function createVideoEl(src) {
   return videoEl;
 }
 
+function createVideoTexture(url) {
+  return new Promise((resolve, reject) => {
+    const videoEl = createVideoEl(url);
+
+    const texture = new THREE.VideoTexture(videoEl);
+    texture.minFilter = THREE.LinearFilter;
+    videoEl.addEventListener("loadedmetadata", () => resolve(texture), { once: true });
+    videoEl.onerror = reject;
+
+    // If iOS and video is HLS, do some hacks.
+    if (
+      AFRAME.utils.device.isIOS() &&
+      AFRAME.utils.material.isHLS(
+        videoEl.src || videoEl.getAttribute("src"),
+        videoEl.type || videoEl.getAttribute("type")
+      )
+    ) {
+      // Actually BGRA. Tell shader to correct later.
+      texture.format = THREE.RGBAFormat;
+      texture.needsCorrectionBGRA = true;
+      // Apparently needed for HLS. Tell shader to correct later.
+      texture.flipY = false;
+      texture.needsCorrectionFlipY = true;
+    }
+  });
+}
+
 const textureLoader = new THREE.TextureLoader();
 textureLoader.setCrossOrigin("anonymous");
+function createImageTexture(url) {
+  return new Promise((resolve, reject) => {
+    textureLoader.load(url, resolve, null, function(xhr) {
+      reject(`'${url}' could not be fetched (Error code: ${xhr.status}; Response: ${xhr.statusText})`);
+    });
+  });
+}
 
 const textureCache = new Map();
 
@@ -105,76 +173,6 @@ AFRAME.registerComponent("image-plus", {
     console.log(textureCache);
   },
 
-  async loadGIF(url) {
-    return new Promise((resolve, reject) => {
-      // TODO: pool workers
-      const worker = new GIFWorker();
-      worker.onmessage = e => {
-        const [success, frames, delays, disposals] = e.data;
-        if (!success) {
-          reject(`error loading gif: ${e.data[1]}`);
-          return;
-        }
-
-        let loadCnt = 0;
-        for (let i = 0; i < frames.length; i++) {
-          const img = new Image();
-          img.onload = e => {
-            loadCnt++;
-            frames[i] = e.target;
-            if (loadCnt === frames.length) {
-              const texture = new GIFTexture(frames, delays, disposals);
-              texture.image.src = url;
-              resolve(texture);
-            }
-          };
-          img.src = frames[i];
-        }
-      };
-      fetch(url, { mode: "cors" })
-        .then(r => r.arrayBuffer())
-        .then(rawImageData => {
-          worker.postMessage(rawImageData, [rawImageData]);
-        })
-        .catch(reject);
-    });
-  },
-
-  loadVideo(url) {
-    return new Promise((resolve, reject) => {
-      const videoEl = createVideoEl(url);
-
-      const texture = new THREE.VideoTexture(videoEl);
-      texture.minFilter = THREE.LinearFilter;
-      videoEl.addEventListener("loadedmetadata", () => resolve(texture), { once: true });
-      videoEl.onerror = reject;
-
-      // If iOS and video is HLS, do some hacks.
-      if (
-        this.el.sceneEl.isIOS &&
-        AFRAME.utils.material.isHLS(
-          videoEl.src || videoEl.getAttribute("src"),
-          videoEl.type || videoEl.getAttribute("type")
-        )
-      ) {
-        // Actually BGRA. Tell shader to correct later.
-        texture.format = THREE.RGBAFormat;
-        texture.needsCorrectionBGRA = true;
-        // Apparently needed for HLS. Tell shader to correct later.
-        texture.flipY = false;
-        texture.needsCorrectionFlipY = true;
-      }
-    });
-  },
-
-  loadImage(url) {
-    return new Promise((resolve, reject) => {
-      textureLoader.load(url, resolve, null, function(xhr) {
-        reject(`'${url}' could not be fetched (Error code: ${xhr.status}; Response: ${xhr.statusText})`);
-      });
-    });
-  },
-
   async update(oldData) {
     let texture;
     try {
@@ -195,11 +193,11 @@ AFRAME.registerComponent("image-plus", {
         if (src === "error") {
           texture = errorTexture;
         } else if (contentType.includes("image/gif")) {
-          texture = await this.loadGIF(src);
+          texture = await createGIFTexture(src);
         } else if (contentType.startsWith("image/")) {
-          texture = await this.loadImage(src);
+          texture = await createImageTexture(src);
         } else if (contentType.startsWith("video/") || contentType.startsWith("audio/")) {
-          texture = await this.loadVideo(src);
+          texture = await createVideoTexture(src);
           cacheItem.audioSource = this.el.sceneEl.audioListener.context.createMediaElementSource(texture.image);
         } else {
           throw new Error(`Unknown content type: ${contentType}`);