diff --git a/src/components/networked-counter.js b/src/components/networked-counter.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b31fdb31f123c5ad2469a5a53865b61580a4ac4
--- /dev/null
+++ b/src/components/networked-counter.js
@@ -0,0 +1,127 @@
+AFRAME.registerComponent("networked-counter", {
+  schema: {
+    max: { default: 3 },
+    ttl: { default: 120 }
+  },
+
+  init: function() {
+    this.count = 0;
+    this.queue = {};
+    this.timeouts = {};
+  },
+
+  getCount: function() {
+    return queue.length;
+  },
+
+  getMax: function() {
+    return this.data.max;
+  },
+
+  getTtl: function() {
+    return this.data.ttl;
+  },
+
+  register: function(networkedEl) {
+    if (this.data.max <= 0) {
+      return;
+    }
+
+    const id = this._getNetworkId(networkedEl);
+    if (this.queue.hasOwnProperty(id)) {
+      return;
+    }
+
+    const now = Date.now();
+    const onGrabHandler = this._onGrabbed.bind(this, id);
+    const onReleaseHandler = this._onReleased.bind(this, id);
+    this.queue[id] = {
+      ts: now,
+      el: networkedEl,
+      onGrabHandler: onGrabHandler,
+      onReleaseHandler: onReleaseHandler
+    };
+
+    networkedEl.addEventListener("grab-start", onGrabHandler);
+    networkedEl.addEventListener("grab-end", onReleaseHandler);
+
+    this.count++;
+
+    if (!this._isCurrentlyGrabbed(id)) {
+      this._addTimeout(id);
+    }
+
+    this._removeOldest();
+  },
+
+  deregister: function(networkedEl) {
+    const id = this._getNetworkId(networkedEl);
+    if (this.queue.hasOwnProperty(id)) {
+      const item = this.queue[id];
+      networkedEl.removeEventListener("grab-start", item.onGrabHandler);
+      networkedEl.removeEventListener("grab-end", item.onReleaseHandler);
+
+      delete this.queue[id];
+
+      this._removeTimeout(id);
+      delete this.timeouts[id];
+
+      this.count--;
+    }
+  },
+
+  _onGrabbed: function(id, e) {
+    this._removeTimeout(id);
+  },
+
+  _onReleased: function(id, e) {
+    this._removeTimeout(id);
+    this._addTimeout(id);
+  },
+
+  _removeOldest: function() {
+    if (this.count > this.data.max) {
+      let oldest = null, ts = Number.MAX_VALUE;
+      Object.keys(this.queue).forEach(function(id) {
+        const expiration = this.queue[id].ts + this.data.ttl * 1000;
+        if (this.queue[id].ts < ts && !this._isCurrentlyGrabbed(id)) {
+          oldest = this.queue[id];
+          ts = this.queue[id].ts;
+        }
+      }, this);
+      if (ts > 0) {
+        this.deregister(oldest.el);
+        this._destroy(oldest.el);
+      }
+    }
+  },
+
+  _isCurrentlyGrabbed: function(id) {
+    const networkedEl = this.queue[id].el;
+    return networkedEl.is("grabbed");
+  },
+
+  _addTimeout: function(id) {
+    const timeout = this.data.ttl * 1000;
+    this.timeouts[id] = setTimeout(() => {
+
+      const el = this.queue[id].el;
+      this.deregister(el);
+      this._destroy(el);
+    }, timeout);
+  },
+
+  _removeTimeout: function(id) {
+    if (this.timeouts.hasOwnProperty(id)) {
+      clearTimeout(this.timeouts[id]);
+    }
+  },
+
+  _destroy: function(networkedEl) {
+    networkedEl.parentNode.removeChild(networkedEl);
+  },
+
+  _getNetworkId: function(networkedEl) {
+    return networkedEl.components.networked.data.networkId;
+  }
+});
diff --git a/src/components/remote-dynamic-body.js b/src/components/remote-dynamic-body.js
index de74826064609c716ffcda7208577e3e7b255f93..09ebc617aace3da3045266ea223a4a77062a3f9a 100644
--- a/src/components/remote-dynamic-body.js
+++ b/src/components/remote-dynamic-body.js
@@ -1,36 +1,48 @@
 AFRAME.registerComponent("remote-dynamic-body", {
+  schema: {
+    mass: { default: 1 },
+    counter: { type: "selector" }
+  },
 
   init: function() {
+    this.counter = this.data.counter.components["networked-counter"];
+    this.timer = 0;
+
     this.networkedEl = NAF.utils.getNetworkedEntity(this.el);
 
     if (!this._isMine()) {
       this.networkedEl.setAttribute("dynamic-body", "mass: 0;");
       this.networkedEl.setAttribute("grabbable", "");
       this.networkedEl.setAttribute("stretchable", "");
-      this.el.setAttribute("color", "white");
+    } else {
+      this.counter.register(this.networkedEl);
+      this.timer = Date.now();
     }
 
     this.wasMine = this._isMine();
 
-    const self = this;
-
-    this.networkedEl.addEventListener('grab-start', function(e){
-      if (!self._isMine()) {
-        if(self.networkedEl.components.networked.takeOwnership()) {
-          self.networkedEl.components["dynamic-body"].updateMass(1);
-          self.el.setAttribute("color", "green");
-          self.wasMine = true;
-        }
-      }
+    this.networkedEl.addEventListener("grab-start", e => {
+      this._onGrabStart(e);
     });
   },
 
   tick: function(t) {
-    if(this.wasMine && !this._isMine()) {
+    if (this.wasMine && !this._isMine()) {
       this.wasMine = false;
       this.networkedEl.components["dynamic-body"].updateMass(0);
-      this.el.setAttribute("color", "white");
       this.networkedEl.components["grabbable"].resetGrabber();
+      this.counter.deregister(this.networkedEl);
+      this.timer = 0;
+    }
+  },
+
+  _onGrabStart: function(e) {
+    if (!this._isMine()) {
+      if (this.networkedEl.components.networked.takeOwnership()) {
+        this.networkedEl.components["dynamic-body"].updateMass(this.data.mass);
+        this.wasMine = true;
+        this.counter.register(this.networkedEl);
+      }
     }
   },
 
diff --git a/src/room.js b/src/room.js
index c836acaf48d725f9499a294f22f8d950730dd5ae..7840ccff681b8793961442c343b1161f062fc6a5 100644
--- a/src/room.js
+++ b/src/room.js
@@ -41,6 +41,7 @@ import "./components/skybox";
 import "./components/layers";
 import "./components/spawn-controller";
 import "./components/remote-dynamic-body";
+import "./components/networked-counter";
 import "./systems/personal-space-bubble";
 
 import { promptForName, getCookie, parseJwt } from "./utils/identity";
diff --git a/templates/room.hbs b/templates/room.hbs
index 342cb1f8298d535917051ba3589a49c2cc8ee0dd..97b6b1cb66be4e22875007211d0e1b7b4a98aa0e 100644
--- a/templates/room.hbs
+++ b/templates/room.hbs
@@ -117,12 +117,17 @@
                     scale="6 6 6"
                 ></a-entity>
             </script>
-
             <script id="physics-cube" type="text/html">
-                <a-box class="box" remote-dynamic-body physics-collider scale="0.25 0.25 0.25"  material="color: green"></a-box>
+                <a-box class="box" remote-dynamic-body="counter: #counter" physics-collider scale="0.25 0.25 0.25"  material="color: green"></a-box>
             </script>
         </a-assets>
 
+        <a-entity
+            id="counter"
+            networked-counter="max: 3; ttl: 120"
+        >
+        </a-entity>
+
         <!-- Player Rig -->
         <a-entity
             id="player-rig"