diff --git a/package.json b/package.json
index 0f2a862e7379a769a35826a2d92b8426ffcf3b6f..4ab7fdc35e0031fc04a52fd66d8bae67ff617898 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
     "aframe-physics-extras": "https://github.com/infinitelee/aframe-physics-extras#fix/physics-collider-crash",
     "aframe-physics-system": "https://github.com/infinitelee/aframe-physics-system#feature/shape-component",
     "aframe-rounded": "^1.0.3",
+    "aframe-slice9-component": "^1.0.0",
     "aframe-teleport-controls": "https://github.com/mozillareality/aframe-teleport-controls#hubs/master",
     "aframe-xr": "github:brianpeiris/aframe-xr#3162aed",
     "classnames": "^2.2.5",
@@ -39,7 +40,7 @@
     "moment": "^2.22.0",
     "moment-timezone": "^0.5.14",
     "moving-average": "^1.0.0",
-    "naf-janus-adapter": "^0.7.0",
+    "naf-janus-adapter": "^0.8.0",
     "networked-aframe": "https://github.com/mozillareality/networked-aframe#mr-social-client/master",
     "nipplejs": "https://github.com/mozillareality/nipplejs#mr-social-client/master",
     "phoenix": "^1.3.0",
diff --git a/src/assets/hud/bubble_off-hover.png b/src/assets/hud/bubble_off-hover.png
index efa274eb628b529cbf3959cdb3db9597ead49112..f9359727df9966493016ee57191cff80ffddcfd2 100644
Binary files a/src/assets/hud/bubble_off-hover.png and b/src/assets/hud/bubble_off-hover.png differ
diff --git a/src/assets/hud/bubble_off.png b/src/assets/hud/bubble_off.png
index 782f4d1aa025d5d2ae08bbf0fb745989c67b4157..ff8bac978dcb3493444a6176a91ecf4f1d459756 100644
Binary files a/src/assets/hud/bubble_off.png and b/src/assets/hud/bubble_off.png differ
diff --git a/src/assets/hud/bubble_on-hover.png b/src/assets/hud/bubble_on-hover.png
index ddc5a202747eeaf513f1261664e56b294fb51b32..ee8e5c64d8c7471a1428548b40e9f1078dc541fe 100644
Binary files a/src/assets/hud/bubble_on-hover.png and b/src/assets/hud/bubble_on-hover.png differ
diff --git a/src/assets/hud/bubble_on.png b/src/assets/hud/bubble_on.png
index 0a70407d65498848bd50c6ebcb7167c35c0d8a5f..90dc62d45bbeb96a3977fe95321613a518984b7f 100644
Binary files a/src/assets/hud/bubble_on.png and b/src/assets/hud/bubble_on.png differ
diff --git a/src/assets/hud/freeze_off-hover.png b/src/assets/hud/freeze_off-hover.png
index 80af8637d4d75559166529fb53e96c424d0be695..2917c8fcb41e521496b9e06b6a5dea74a5ad272a 100644
Binary files a/src/assets/hud/freeze_off-hover.png and b/src/assets/hud/freeze_off-hover.png differ
diff --git a/src/assets/hud/freeze_off.png b/src/assets/hud/freeze_off.png
index 302c7a23742b0ac94a7ffc1406935bf90a0a9be6..0b789a8ebded359fa38aac7648f0ea7fd4d9917b 100644
Binary files a/src/assets/hud/freeze_off.png and b/src/assets/hud/freeze_off.png differ
diff --git a/src/assets/hud/freeze_on-hover.png b/src/assets/hud/freeze_on-hover.png
index ce846be44344e1bfa5bb394bc36a1be25599ee67..784be98321121a6599d85357344690f39dbd2553 100644
Binary files a/src/assets/hud/freeze_on-hover.png and b/src/assets/hud/freeze_on-hover.png differ
diff --git a/src/assets/hud/freeze_on.png b/src/assets/hud/freeze_on.png
index edf0da5b9e7f78a00af084cf0429e086289fba01..f9d10766b5101fcd8da0e5340812a89d0baa9515 100644
Binary files a/src/assets/hud/freeze_on.png and b/src/assets/hud/freeze_on.png differ
diff --git a/src/assets/hud/mute_off-hover.png b/src/assets/hud/mute_off-hover.png
index 4e064fb57702c605d08211f836e94dcbbf135a89..ba4261d0ed95a3e6feae8a28092767b1914af9f9 100644
Binary files a/src/assets/hud/mute_off-hover.png and b/src/assets/hud/mute_off-hover.png differ
diff --git a/src/assets/hud/mute_off.png b/src/assets/hud/mute_off.png
index 9dcce25b132006b1de0228458692659cec6c93f3..38f1bc95d10f52dfe6300a1d144a470987dda741 100644
Binary files a/src/assets/hud/mute_off.png and b/src/assets/hud/mute_off.png differ
diff --git a/src/assets/hud/mute_on-hover.png b/src/assets/hud/mute_on-hover.png
index f823c06561115c5208cce101dde4fe3d203d4c18..6efb40f54a0ec16ce58df6eb0ef70090a557d316 100644
Binary files a/src/assets/hud/mute_on-hover.png and b/src/assets/hud/mute_on-hover.png differ
diff --git a/src/assets/hud/mute_on.png b/src/assets/hud/mute_on.png
index e5862312db1c45889cf37613cf3a01dad0566615..0c1ec01983c6ac97261d52ebb470c31d1c0ca0c7 100644
Binary files a/src/assets/hud/mute_on.png and b/src/assets/hud/mute_on.png differ
diff --git a/src/assets/hud/tooltip.9.png b/src/assets/hud/tooltip.9.png
new file mode 100755
index 0000000000000000000000000000000000000000..8f01466f1551e8cc8bb046e4e434c0b99b721a9b
Binary files /dev/null and b/src/assets/hud/tooltip.9.png differ
diff --git a/src/components/block-button.js b/src/components/block-button.js
new file mode 100644
index 0000000000000000000000000000000000000000..9dc23988c351d8483de8ea2e6546579d9e25d5b0
--- /dev/null
+++ b/src/components/block-button.js
@@ -0,0 +1,28 @@
+AFRAME.registerComponent("block-button", {
+  init() {
+    this.onClick = () => {
+      this.block(this.owner);
+    };
+    NAF.utils.getNetworkedEntity(this.el).then(networkedEl => {
+      this.owner = networkedEl.components.networked.data.owner;
+    });
+  },
+
+  play() {
+    this.el.addEventListener("click", this.onClick);
+  },
+
+  pause() {
+    this.el.removeEventListener("click", this.onClick);
+  },
+
+  block(clientId) {
+    NAF.connection.adapter.block(clientId);
+  },
+
+  // Currently unused
+  unblock(clientId) {
+    NAF.connection.adapter.unblock(clientId);
+    NAF.connection.entities.completeSync(clientId);
+  }
+});
diff --git a/src/components/text-button.js b/src/components/text-button.js
new file mode 100644
index 0000000000000000000000000000000000000000..2668694c01d8efc973e7c8bdfd65596554e1ea7b
--- /dev/null
+++ b/src/components/text-button.js
@@ -0,0 +1,54 @@
+AFRAME.registerComponent("text-button", {
+  schema: {
+    haptic: { type: "selector" },
+    textHoverColor: { type: "string" },
+    textColor: { type: "string" },
+    backgroundHoverColor: { type: "string" },
+    backgroundColor: { type: "string" }
+  },
+
+  init() {
+    this.onHover = () => {
+      this.hovering = true;
+      this.updateButtonState();
+      this.emitHapticPulse();
+    };
+    this.onHoverOut = () => {
+      this.hovering = false;
+      this.updateButtonState();
+    };
+    this.onClick = () => {
+      this.emitHapticPulse();
+    };
+    this.textEl = this.el.parentEl.querySelector("[text]");
+  },
+
+  emitHapticPulse() {
+    if (this.data.haptic) {
+      this.data.haptic.emit("haptic_pulse", { intensity: "low" });
+    }
+  },
+
+  play() {
+    this.updateButtonState();
+    this.el.addEventListener("mouseover", this.onHover);
+    this.el.addEventListener("mouseout", this.onHoverOut);
+    this.el.addEventListener("click", this.onClick);
+  },
+
+  pause() {
+    this.el.removeEventListener("mouseover", this.onHover);
+    this.el.removeEventListener("mouseout", this.onHoverOut);
+    this.el.removeEventListener("click", this.onClick);
+  },
+
+  update() {
+    this.updateButtonState();
+  },
+
+  updateButtonState() {
+    const hovering = this.hovering;
+    this.el.setAttribute("slice9", "color", hovering ? this.data.backgroundHoverColor : this.data.backgroundColor);
+    this.textEl.setAttribute("text", "color", hovering ? this.data.textHoverColor : this.data.textColor);
+  }
+});
diff --git a/src/components/visible-while-frozen.js b/src/components/visible-while-frozen.js
new file mode 100644
index 0000000000000000000000000000000000000000..59448cb6b989034699d879daae0a1ac1690c39af
--- /dev/null
+++ b/src/components/visible-while-frozen.js
@@ -0,0 +1,39 @@
+AFRAME.registerComponent("visible-while-frozen", {
+  init() {
+    this.onStateChange = evt => {
+      if (!evt.detail === "frozen") return;
+      this.el.setAttribute("visible", this.el.sceneEl.is("frozen"));
+    };
+    this.el.setAttribute("visible", this.el.sceneEl.is("frozen"));
+  },
+
+  play() {
+    this.el.sceneEl.addEventListener("stateadded", this.onStateChange);
+    this.el.sceneEl.addEventListener("stateremoved", this.onStateChange);
+  },
+
+  pause() {
+    this.el.sceneEl.removeEventListener("stateadded", this.onStateChange);
+    this.el.sceneEl.removeEventListener("stateremoved", this.onStateChange);
+  }
+});
+
+AFRAME.registerComponent("ui-class-while-frozen", {
+  init() {
+    this.onStateChange = evt => {
+      if (!evt.detail === "frozen") return;
+      this.el.classList.toggle("ui", this.el.sceneEl.is("frozen"));
+    };
+    this.el.classList.toggle("ui", this.el.sceneEl.is("frozen"));
+  },
+
+  play() {
+    this.el.sceneEl.addEventListener("stateadded", this.onStateChange);
+    this.el.sceneEl.addEventListener("stateremoved", this.onStateChange);
+  },
+
+  pause() {
+    this.el.sceneEl.removeEventListener("stateadded", this.onStateChange);
+    this.el.sceneEl.removeEventListener("stateremoved", this.onStateChange);
+  }
+});
diff --git a/src/hub.html b/src/hub.html
index f52399ecda32ce20447b7787f1f677b63eb0c099..0b3b72b38371ce427919e04a6326bd4bc488ba5d 100644
--- a/src/hub.html
+++ b/src/hub.html
@@ -30,6 +30,7 @@
         >
 
         <a-assets>
+            <img id="tooltip"  src="./assets/hud/tooltip.9.png" >
             <img id="mute-off"  src="./assets/hud/mute_off.png" >
             <img id="mute-off-hover"  src="./assets/hud/mute_off-hover.png" >
             <img id="mute-on"  src="./assets/hud/mute_on.png" >
@@ -91,7 +92,36 @@
                         </template>
 
                         <template data-selector=".Chest">
-                            <a-entity personal-space-invader="radius: 0.2; useMaterial: true;" bone-visibility></a-entity>
+                            <a-entity>
+                              <a-entity personal-space-invader="radius: 0.2; useMaterial: true;" bone-visibility> </a-entity>
+                              <a-entity billboard>
+                                  <a-entity
+                                      block-button
+                                      visible-while-frozen
+                                      ui-class-while-frozen
+                                      text-button="haptic:#player-right-controller;
+                                                   textHoverColor: #fff;
+                                                   textColor: #fff;
+                                                   backgroundHoverColor: #ea4b54;
+                                                   backgroundColor: #fff;"
+                                      slice9="width: 0.45;
+                                                   height: 0.2;
+                                                   left: 53;
+                                                   top: 53;
+                                                   right: 10;
+                                                   bottom: 10;
+                                                   opacity: 1.3;
+                                                   src: #tooltip"
+                                      position="0 0 .35">
+                                  </a-entity>
+                                  <a-entity
+                                      visible-while-frozen
+                                      text="value:Block;
+                                            width:2.5;
+                                            align:center;"
+                                      position="0 0 0.36"></a-entity>
+                              </a-entity>
+                            </a-entity>
                         </template>
 
                         <template data-selector=".Head">
diff --git a/src/hub.js b/src/hub.js
index ffe1face9c11a6c82e8e092f1bb8adcb0afd3099..26b9e1f368908a0b94a4612193cd722d1b11f38b 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -16,6 +16,7 @@ import "aframe-input-mapping-component";
 import "aframe-billboard-component";
 import "aframe-rounded";
 import "webrtc-adapter";
+import "aframe-slice9-component";
 
 import trackpad_dpad4 from "./behaviours/trackpad-dpad4";
 import joystick_dpad4 from "./behaviours/joystick-dpad4";
@@ -51,6 +52,9 @@ import "./components/gltf-bundle";
 import "./components/hud-controller";
 import "./components/freeze-controller";
 import "./components/icon-button";
+import "./components/text-button";
+import "./components/block-button";
+import "./components/visible-while-frozen";
 import "./components/stats-plus";
 import "./components/networked-avatar";
 
@@ -246,6 +250,14 @@ const onReady = async () => {
       screenEntity.setAttribute("visible", sharingScreen);
     });
 
+    document.body.addEventListener("blocked", ev => {
+      NAF.connection.entities.removeEntitiesOfClient(ev.detail.clientId);
+    });
+
+    document.body.addEventListener("unblocked", ev => {
+      NAF.connection.entities.completeSync(ev.detail.clientId);
+    });
+
     if (!qsTruthy("offline")) {
       document.body.addEventListener("connected", () => {
         hubChannel.sendEntryEvent().then(() => {
diff --git a/yarn.lock b/yarn.lock
index f4dda0c74d94ae3e53ba72a2db25708329ed912d..7a97810355e2247db67092ffd7a9302c840eb61a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -188,6 +188,10 @@ aframe-rounded@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/aframe-rounded/-/aframe-rounded-1.0.3.tgz#72c7d9c0ff02e94ee138bf217c284e187efa3cfb"
 
+aframe-slice9-component@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/aframe-slice9-component/-/aframe-slice9-component-1.0.0.tgz#fb0f8441dadd1e8b11cc24512ba7aa692d622be1"
+
 "aframe-teleport-controls@https://github.com/mozillareality/aframe-teleport-controls#hubs/master":
   version "0.3.2"
   resolved "https://github.com/mozillareality/aframe-teleport-controls#9e2ef7da57144c4a615eba40a945d4cfa105a092"
@@ -5396,9 +5400,9 @@ mute-stream@0.0.7:
   version "0.0.7"
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
 
-naf-janus-adapter@^0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/naf-janus-adapter/-/naf-janus-adapter-0.7.0.tgz#00ced989bac9e073e32b74a5bbc1f41cc61db6ea"
+naf-janus-adapter@^0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/naf-janus-adapter/-/naf-janus-adapter-0.8.0.tgz#61fa7185c17437f9a33b9b97b1508eb9293b4f22"
   dependencies:
     debug "^3.1.0"
     minijanus "0.6.0"