diff --git a/src/assets/avatars/Bot_SkinnedWithAnim.fbx b/src/assets/avatars/Bot_SkinnedWithAnim.fbx
new file mode 100755
index 0000000000000000000000000000000000000000..38bfe3673af74de3599aadb3fc473cd2196ee820
Binary files /dev/null and b/src/assets/avatars/Bot_SkinnedWithAnim.fbx differ
diff --git a/src/assets/avatars/Bot_SkinnedWithAnim.glb b/src/assets/avatars/Bot_SkinnedWithAnim.glb
new file mode 100755
index 0000000000000000000000000000000000000000..5531da9cf237d1de307ec227c400a7f6e9b80d12
Binary files /dev/null and b/src/assets/avatars/Bot_SkinnedWithAnim.glb differ
diff --git a/src/components/hand-controls2.js b/src/components/hand-controls2.js
index 28b0062358ef463815cadc2e1d38fc8fb73bfec3..655bb54cf639bd22e15ccd2d6fbe7ded3ebb61b9 100644
--- a/src/components/hand-controls2.js
+++ b/src/components/hand-controls2.js
@@ -60,10 +60,7 @@ AFRAME.registerComponent("hand-controls2", {
     this.onControllerDisconnected = this.onControllerDisconnected.bind(this);
 
     el.addEventListener("controllerconnected", this.onControllerConnected);
-    el.addEventListener(
-      "controllerdisconnected",
-      this.onControllerDisconnected
-    );
+    el.addEventListener("controllerdisconnected", this.onControllerDisconnected);
 
     el.setAttribute("visible", false);
   },
@@ -80,10 +77,7 @@ AFRAME.registerComponent("hand-controls2", {
 
   pause() {
     const el = this.el;
-    el.removeEventListener(
-      "middle_ring_pinky_down",
-      this.onMiddleRingPinkyDown
-    );
+    el.removeEventListener("middle_ring_pinky_down", this.onMiddleRingPinkyDown);
     el.removeEventListener("middle_ring_pinky_up", this.onMiddleRingPinkyUp);
     el.removeEventListener("thumb_down", this.onThumbDown);
     el.removeEventListener("thumb_up", this.onThumbUp);
@@ -113,10 +107,7 @@ AFRAME.registerComponent("hand-controls2", {
   remove() {
     const el = this.el;
     el.removeEventListener("controllerconnected", this.onControllerConnected);
-    el.removeEventListener(
-      "controllerdisconnected",
-      this.onControllerDisconnected
-    );
+    el.removeEventListener("controllerdisconnected", this.onControllerDisconnected);
   },
 
   updateGesture(nextFingersDown) {
@@ -124,9 +115,9 @@ AFRAME.registerComponent("hand-controls2", {
     const gesture = this.determineGesture();
 
     if (gesture !== this.gesture) {
+      var previous = this.gesture;
       this.gesture = gesture;
-      this.el.emit(this.last + "end");
-      this.el.emit(this.gesture + "start");
+      this.el.emit("hand-gesture", { previous: previous, current: this.gesture });
     }
   },
 
diff --git a/src/components/robot-hand-gestures.js b/src/components/robot-hand-gestures.js
new file mode 100644
index 0000000000000000000000000000000000000000..6715fe531460544b866dff45489bd83d9b220cd4
--- /dev/null
+++ b/src/components/robot-hand-gestures.js
@@ -0,0 +1,86 @@
+// Global THREE, AFRAME
+const robotGestures = {
+  open: "pinch", //TODO
+  point: "point",
+  pointThumb: "point",
+  fist: "grip",
+  hold: "grip",
+  thumbUp: "thumbup"
+};
+
+AFRAME.registerComponent("robot-hand-gestures", {
+  schema: {
+    leftHand: { type: "selector", default: "#left-hand" },
+    rightHand: { type: "selector", default: "#right-hand" }
+  },
+
+  init: function() {
+    this.playAnimation = this.playAnimation.bind(this);
+    this.onModelLoaded = this.onModelLoaded.bind(this);
+    this.el.addEventListener("model-loaded", this.onModelLoaded);
+  },
+
+  onModelLoaded: function() {
+    var root = this.el.object3D.children[0].children[0].children[0]; // The "Root Scene" in threejs land of type "Scene"
+    console.log(this.el);
+    this.mixer = new THREE.AnimationMixer(root);
+    this.loaded = true;
+  },
+
+  play: function() {
+    this.data.leftHand.addEventListener("hand-gesture", this.playAnimation);
+    this.data.rightHand.addEventListener("hand-gesture", this.playAnimation);
+  },
+
+  pause: function() {
+    this.data.leftHand.removeEventListener("hand-gesture", this.playAnimation);
+    this.data.rightHand.removeEventListener("hand-gesture", this.playAnimation);
+  },
+
+  tick: function(_t, dt) {
+    if (!this.loaded) return;
+    this.mixer.update(dt * 0.001);
+  },
+
+  /**
+  * Play hand animation based on button state.
+  *
+  * @param {string} gesture - Name of the animation as specified by the model.
+  * @param {string} lastGesture - Previous pose.
+  */
+  playAnimation: function(evt) {
+    const { current, previous } = evt.detail;
+    var fromAction;
+    var toAction;
+    var mixer = this.mixer;
+    const suffix = evt.target === this.data.leftHand ? "_L" : "_R";
+    const from = robotGestures[previous] + suffix;
+    const to = robotGestures[current] + suffix;
+
+    // Grab clip action.
+    toAction = mixer.clipAction(to);
+    toAction.clampWhenFinished = true;
+    //    toAction.loop = THREE.LoopRepeat;
+    toAction.repetitions = 0;
+    toAction.weight = 1;
+
+    // No gesture to gesture or gesture to no gesture.
+    if (!previous || current === previous) {
+      // Stop all current animations.
+      mixer.stopAllAction();
+
+      // Play animation.
+      toAction.play();
+      return;
+    }
+
+    // Animate or crossfade from gesture to gesture.
+
+    fromAction = mixer.clipAction(from);
+    mixer.stopAllAction();
+    fromAction.weight = 0.15;
+    fromAction.play();
+    toAction.play();
+    fromAction.crossFadeTo(toAction, 0.15, true);
+  }
+});
diff --git a/src/room.js b/src/room.js
index d6e4fe75eac02e0ff34812713c9663277d303970..2138bf934bb49149d797da2880ad59dd75f0b7c4 100644
--- a/src/room.js
+++ b/src/room.js
@@ -37,6 +37,7 @@ import "./components/water";
 import "./components/skybox";
 import "./components/layers";
 import "./components/spawn-controller";
+import "./components/robot-hand-gestures";
 import "./systems/personal-space-bubble";
 
 import { promptForName, getCookie, parseJwt } from "./utils/identity";
@@ -45,10 +46,7 @@ import { inGameActions, config } from "./input-mappings";
 import registerTelemetry from "./telemetry";
 
 AFRAME.registerInputBehaviour("vive_trackpad_dpad4", vive_trackpad_dpad4);
-AFRAME.registerInputBehaviour(
-  "oculus_touch_joystick_dpad4",
-  oculus_touch_joystick_dpad4
-);
+AFRAME.registerInputBehaviour("oculus_touch_joystick_dpad4", oculus_touch_joystick_dpad4);
 AFRAME.registerInputActivator("pressedmove", PressedMove);
 AFRAME.registerInputActivator("reverseY", ReverseY);
 AFRAME.registerInputActions(inGameActions, "default");
@@ -85,10 +83,7 @@ window.App = {
     const scene = document.querySelector("a-scene");
 
     scene.setAttribute("networked-scene", {
-      room:
-        qs.room && !isNaN(parseInt(qs.room))
-          ? parseInt(qs.room)
-          : window.CONFIG.default_room,
+      room: qs.room && !isNaN(parseInt(qs.room)) ? parseInt(qs.room) : window.CONFIG.default_room,
       serverURL: window.CONFIG.janus_server_url
     });
 
@@ -122,10 +117,7 @@ window.App = {
 
     const mediaStream = await navigator.mediaDevices.getUserMedia({
       audio: true,
-      video:
-        qs.screen === "true"
-          ? { mediaSource: "screen", height: 720, frameRate: 30 }
-          : false
+      video: qs.screen === "true" ? { mediaSource: "screen", height: 720, frameRate: 30 } : false
     });
 
     // Don't send video by deafult
diff --git a/templates/room.hbs b/templates/room.hbs
index 63c3f90db866b36c6042a05e10ae0a39befa8998..fffd1373bd908c2eec5d11e34d42d0c7dbec47ba 100644
--- a/templates/room.hbs
+++ b/templates/room.hbs
@@ -48,6 +48,7 @@
             <a-asset-item id="bot-body-mesh" response-type="arraybuffer" src="{{asset "assets/avatars/Bot_Body_Mesh.glb" }}"></a-asset-item>
             <a-asset-item id="bot-left-hand-mesh" response-type="arraybuffer" src="{{asset "assets/avatars/Bot_LeftHand_Mesh.glb" }}"></a-asset-item>
             <a-asset-item id="bot-right-hand-mesh" response-type="arraybuffer" src="{{asset "assets/avatars/Bot_RightHand_Mesh.glb"}}"></a-asset-item>
+            <a-asset-item id="bot-whole-body-mesh" response-type="arraybuffer" src="{{asset "assets/avatars/Bot_SkinnedWithAnim.glb"}}"></a-asset-item>
 
             <a-asset-item id="watch-model" response-type="arraybuffer" src="{{asset "assets/hud/watch.glb"}}"></a-asset-item>
 
@@ -82,6 +83,14 @@
                     position="0 -0.05 0"
                 ></a-entity>
             </script>
+            <script id="body-template2" type="text/html">
+                <a-entity
+                    class="body"
+                    cached-gltf-model="#bot-whole-body-mesh"
+                    rotation="0 180 0"
+                    position="0 -0.05 0"
+                ></a-entity>
+            </script>
 
             <script id="left-hand-template" type="text/html">
                 <a-entity
@@ -128,17 +137,30 @@
         >
             <a-entity
                 id="head"
-                camera="userHeight: 1.6"
                 personal-space-bubble
-                look-controls
                 networked="template: #head-template; showLocalTemplate: false;"
-            ></a-entity>
+                position ="0 1.6 0" 
+            >
+                <a-entity
+                    id="third-person-cam"
+                    camera=""
+                    look-controls
+                    position ="0 2 -1"
+                >
+                </a-entity>
+            </a-entity>
 
             <a-entity
                 id="body"
-                body-controller="eyeNeckOffset: 0 -0.11 0.09; neckHeight: 0.05"
+                body-controller="camera: #head; eyeNeckOffset: 0 -0.11 0.09; neckHeight: 0.05"
                 networked="template: #body-template;"
             ></a-entity>
+            <a-entity
+                id="body2"
+                body-controller="camera: #head; eyeNeckOffset: 0 -0.11 0.09; neckHeight: 0.05"
+                networked="template: #body-template2;"
+                robot-hand-gestures="leftHand: #left-hand; rightHand: #right-hand"
+            ></a-entity>
             <a-entity
                 id="nametag"
                 networked="template: #nametag-template; showLocalTemplate: false;"