diff --git a/src/aentity-components.js b/src/aentity-components.js
new file mode 100644
index 0000000000000000000000000000000000000000..b616eedc1e67c2d3c6c077b5f7703d234294bf16
--- /dev/null
+++ b/src/aentity-components.js
@@ -0,0 +1,3 @@
+export default function registerComponents() {
+  AFRAME.AGLTFEntity.registerComponent("rotator");
+}
diff --git a/src/assets/avatars/Bot_With_Components.glb b/src/assets/avatars/Bot_With_Components.glb
new file mode 100644
index 0000000000000000000000000000000000000000..189cf5e26813dff0b0f935158fd914cd455d99d1
Binary files /dev/null and b/src/assets/avatars/Bot_With_Components.glb differ
diff --git a/src/assets/avatars/Bot_With_Components.json b/src/assets/avatars/Bot_With_Components.json
new file mode 100644
index 0000000000000000000000000000000000000000..bd05e122c64f88b04ba49f9e01d676d1cbb1d5b5
--- /dev/null
+++ b/src/assets/avatars/Bot_With_Components.json
@@ -0,0 +1,8 @@
+{
+  "Head": {
+    "rotator": {
+      "axis": { "x": 0, "y": 1, "z": 0 },
+      "speed": 0.2
+    }
+  }
+}
diff --git a/src/components/rotator.js b/src/components/rotator.js
new file mode 100644
index 0000000000000000000000000000000000000000..68518cdcaa4d58310fa5c70061bfe39eafd668aa
--- /dev/null
+++ b/src/components/rotator.js
@@ -0,0 +1,16 @@
+const DEG2RAD = THREE.Math.DEG2RAD;
+
+AFRAME.registerComponent("rotator", {
+  schema: {
+    axis: {
+      type: "vec3"
+    },
+    speed: {
+      type: "number"
+    }
+  },
+
+  tick(time, dt) {
+    this.el.object3D.rotateOnAxis(this.data.axis, dt * this.data.speed * DEG2RAD);
+  }
+});
diff --git a/src/elements/a-gltf-entity.js b/src/elements/a-gltf-entity.js
index ee59e3a24ead224a4095c69c70d2ea0da1c9cbd5..793686f8a7157c62708d17c96427a7d9afb513ba 100644
--- a/src/elements/a-gltf-entity.js
+++ b/src/elements/a-gltf-entity.js
@@ -1,5 +1,15 @@
 const GLTFCache = {};
 
+AFRAME.AGLTFEntity = {
+  defaultSerializer(el, componentName, componentData) {
+    el.setAttribute(componentName, componentData);
+  },
+  registerComponent(componentName, serializer) {
+    AFRAME.AGLTFEntity.components[componentName] = serializer || AFRAME.AGLTFEntity.defaultSerializer;
+  },
+  components: {}
+};
+
 // From https://gist.github.com/cdata/f2d7a6ccdec071839bc1954c32595e87
 // Tracking glTF cloning here: https://github.com/mrdoob/three.js/issues/11573
 function cloneGltf(gltf) {
@@ -83,6 +93,20 @@ const inflateEntities = function(classPrefix, parentEl, node) {
 
   el.setObject3D(node.type.toLowerCase(), node);
 
+  const entityComponents = node.userData;
+
+  if (entityComponents) {
+    for (const prop in entityComponents) {
+      if (entityComponents.hasOwnProperty(prop)) {
+        const serializer = AFRAME.AGLTFEntity.components[prop];
+
+        if (serializer) {
+          serializer(el, prop, entityComponents[prop]);
+        }
+      }
+    }
+  }
+
   children.forEach(childNode => {
     inflateEntities(classPrefix, el, childNode);
   });
diff --git a/src/room.html b/src/room.html
index 703874897968615d777c03353392ae90a8fff6a4..91e92fbda4d6a7ba3cb58b108b6624edb5419f0d 100644
--- a/src/room.html
+++ b/src/room.html
@@ -27,6 +27,7 @@
 
         <a-assets>
             <a-asset-item id="bot-skinned-mesh" response-type="arraybuffer" src="./assets/avatars/Bot_SkinnedWithAnim.glb"></a-asset-item>
+            <a-asset-item id="avatar-with-components" response-type="arraybuffer" src="./assets/avatars/Bot_With_Components.glb"></a-asset-item>
             <a-asset-item id="watch-model" response-type="arraybuffer" src="./assets/hud/watch.glb"></a-asset-item>
 
             <a-asset-item id="meeting-space1-mesh" response-type="arraybuffer" src="./assets/environments/MeetingSpace1_mesh.glb"></a-asset-item>
@@ -149,6 +150,9 @@
             </a-gltf-entity>
         </a-entity>
 
+
+        <a-gltf-entity src="#avatar-with-components" inflate="true" ></a-gltf-entity>
+
         <!-- Environment -->
         <a-gltf-entity
             id="meeting-space"
diff --git a/src/room.js b/src/room.js
index c3ed3d28e188cdf100e4ff4fb09b556a8e4efcd9..98113fb60d8318c5db3643ea293488fde29b1791 100644
--- a/src/room.js
+++ b/src/room.js
@@ -4,6 +4,7 @@ import queryString from "query-string";
 import { patchWebGLRenderingContext } from "./utils/webgl";
 patchWebGLRenderingContext();
 
+import "whatwg-fetch";
 import "aframe-xr";
 import "./vendor/GLTFLoader";
 import "networked-aframe";
@@ -38,10 +39,13 @@ import "./components/water";
 import "./components/skybox";
 import "./components/layers";
 import "./components/spawn-controller";
+import "./components/rotator";
 
 import "./systems/personal-space-bubble";
 
+import registerComponents from "./aentity-components";
 import "./elements/a-gltf-entity";
+registerComponents();
 
 import { promptForName, getCookie, parseJwt } from "./utils/identity";
 import registerNetworkSchemas from "./network-schemas";