diff --git a/package-lock.json b/package-lock.json
index a03b932625a3a145d196e3007068f0b44d2eea7d..439e3b2c49bc1e9818cd91aa57fd5a55690137db 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -609,9 +609,9 @@
       "dev": true
     },
     "@types/node": {
-      "version": "12.12.12",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.12.tgz",
-      "integrity": "sha512-MGuvYJrPU0HUwqF7LqvIj50RZUX23Z+m583KBygKYUZLlZ88n6w28XRNJRJgsHukLEnLz6w6SvxZoLgbr5wLqQ=="
+      "version": "12.12.14",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.14.tgz",
+      "integrity": "sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA=="
     },
     "@types/stack-utils": {
       "version": "1.0.1",
@@ -859,9 +859,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz",
+          "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==",
           "dev": true
         }
       }
@@ -1182,9 +1182,9 @@
       "dev": true
     },
     "aws4": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
-      "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
+      "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==",
       "dev": true
     },
     "babel-code-frame": {
@@ -2600,9 +2600,9 @@
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001011",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001011.tgz",
-      "integrity": "sha512-h+Eqyn/YA6o6ZTqpS86PyRmNWOs1r54EBDcd2NTwwfsXQ8re1B38SnB+p2RKF8OUsyEIjeDU8XGec1RGO/wYCg==",
+      "version": "1.0.30001012",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz",
+      "integrity": "sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==",
       "dev": true
     },
     "canvas-renderer": {
@@ -3488,9 +3488,9 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.312",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.312.tgz",
-      "integrity": "sha512-/Nk6Hvwt+RfS9X3oA4IXpWqpcnS7cdWsTMP4AmrP8hPpxtZbHemvTEYzjAKghk28aS9zIV8NwGHNt8H+6OmJug==",
+      "version": "1.3.314",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.314.tgz",
+      "integrity": "sha512-IKDR/xCxKFhPts7h+VaSXS02Z1mznP3fli1BbXWXeN89i2gCzKraU8qLpEid8YzKcmZdZD3Mly3cn5/lY9xsBQ==",
       "dev": true
     },
     "elegant-spinner": {
@@ -3710,18 +3710,18 @@
       }
     },
     "es-abstract": {
-      "version": "1.16.0",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz",
-      "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==",
+      "version": "1.16.2",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.2.tgz",
+      "integrity": "sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==",
       "dev": true,
       "requires": {
-        "es-to-primitive": "^1.2.0",
+        "es-to-primitive": "^1.2.1",
         "function-bind": "^1.1.1",
         "has": "^1.0.3",
-        "has-symbols": "^1.0.0",
+        "has-symbols": "^1.0.1",
         "is-callable": "^1.1.4",
         "is-regex": "^1.0.4",
-        "object-inspect": "^1.6.0",
+        "object-inspect": "^1.7.0",
         "object-keys": "^1.1.1",
         "string.prototype.trimleft": "^2.1.0",
         "string.prototype.trimright": "^2.1.0"
@@ -3771,9 +3771,9 @@
       }
     },
     "eslint": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.0.tgz",
-      "integrity": "sha512-dQpj+PaHKHfXHQ2Imcw5d853PTvkUGbHk/MR68KQUl98EgKDCdh4vLRH1ZxhqeQjQFJeg8fgN0UwmNhN3l8dDQ==",
+      "version": "6.7.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.1.tgz",
+      "integrity": "sha512-UWzBS79pNcsDSxgxbdjkmzn/B6BhsXMfUaOHnNwyE8nD+Q6pyT96ow2MccVayUTV4yMid4qLhMiQaywctRkBLA==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
@@ -8330,9 +8330,9 @@
       "dev": true
     },
     "resolve": {
-      "version": "1.12.2",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.2.tgz",
-      "integrity": "sha512-cAVTI2VLHWYsGOirfeYVVQ7ZDejtQ9fp4YhYckWDEkFfqbVjaT11iM8k6xSAfGFMM+gDpZjMnFssPu8we+mqFw==",
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz",
+      "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==",
       "dev": true,
       "requires": {
         "path-parse": "^1.0.6"
@@ -8900,9 +8900,9 @@
       }
     },
     "socket.io-adapter": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
-      "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
+      "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
     },
     "socket.io-client": {
       "version": "2.3.0",
@@ -9467,9 +9467,9 @@
       },
       "dependencies": {
         "@types/node": {
-          "version": "10.17.5",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz",
-          "integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==",
+          "version": "10.17.6",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz",
+          "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==",
           "dev": true
         },
         "ci-info": {
@@ -9663,9 +9663,9 @@
           }
         },
         "execa": {
-          "version": "3.3.0",
-          "resolved": "https://registry.npmjs.org/execa/-/execa-3.3.0.tgz",
-          "integrity": "sha512-j5Vit5WZR/cbHlqU97+qcnw9WHRCIL4V1SVe75VcHcD1JRBdt8fv0zw89b7CQHQdUHTt2VjuhcF5ibAgVOxqpg==",
+          "version": "3.4.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
+          "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
           "dev": true,
           "requires": {
             "cross-spawn": "^7.0.0",
@@ -10324,9 +10324,9 @@
       "dev": true
     },
     "uglify-js": {
-      "version": "3.6.9",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.9.tgz",
-      "integrity": "sha512-pcnnhaoG6RtrvHJ1dFncAe8Od6Nuy30oaJ82ts6//sGSXOP5UjBMEthiProjXmMNHOfd93sqlkztifFMcb+4yw==",
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.0.tgz",
+      "integrity": "sha512-PC/ee458NEMITe1OufAjal65i6lB58R1HWMRcxwvdz1UopW0DYqlRL3xdu3IcTvTXsB02CRHykidkTRL+A3hQA==",
       "dev": true,
       "optional": true,
       "requires": {
@@ -10618,9 +10618,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz",
+          "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==",
           "dev": true
         },
         "eslint-scope": {
@@ -10657,9 +10657,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz",
+          "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==",
           "dev": true
         }
       }
diff --git a/public/index.html b/public/index.html
index ca2ae6044aece77c536d264245695f3d3464af17..2286a49b8b334ee832cf9b3635e11d9d77cb7534 100644
--- a/public/index.html
+++ b/public/index.html
@@ -197,13 +197,21 @@
             </div>
           </div>
         </div>
-        <button id="eraser-tool"><i class="fa fa-eraser"></i></button>
+        <button id="eraser-tool">
+          <i class="fa fa-eraser"></i>
+        </button>
         <div id="status-info">
-          <div id="user-avatar"></div>
+          <button id="fast-undo-tool" class="disabled">
+            <i class="fa fa-fast-backward"></i>
+          </button>
+          <button id="undo-tool" class="disabled">
+            <i class="fa fa-backward"></i>
+          </button>
           <div id="connected-room-info">
-            Room <i class="fa fa-globe">: </i> &nbsp;
+            Room:&nbsp;
             <span id="connected-room-id"></span>
           </div>
+          <div id="user-avatar"></div>
         </div>
       </div>
     </div>
diff --git a/public/styles.css b/public/styles.css
index d1f4a1381ed965be737d4eb3082e5c50a941ad2f..f4c1de641ba7745eae2a6ac5c3326f21553bdeb0 100644
--- a/public/styles.css
+++ b/public/styles.css
@@ -33,14 +33,8 @@ body {
   align-items: center;
   background-color: #4f4f4fb7;
   border-radius: 4px;
-  margin-left: 8px;
   justify-content: center;
-  height: 44px;
-}
-
-#connected-room-info:hover {
-  background-color: #4f4f4f !important;
-  transition-duration: 0.4s;
+  padding: 0.75em;
 }
 
 button.selected {
@@ -269,6 +263,11 @@ button.selected {
   border-radius: 4px;
 }
 
+#room-connect:hover {
+  background-color: #4f4f4f !important;
+  transition-duration: 0.4s;
+}
+
 #pen-tool {
   background-color: #2f2f2f;
   color: white;
@@ -285,6 +284,10 @@ button.selected {
   transition-duration: 0.4s;
 }
 
+#pen-tool > i {
+  padding: 0 1px;
+}
+
 #eraser-tool {
   background-color: #2f2f2f;
   color: white;
@@ -293,6 +296,7 @@ button.selected {
   border: none;
   cursor: pointer;
   border-radius: 50%;
+  margin-right: 8px;
 }
 
 #eraser-tool:hover {
@@ -300,6 +304,58 @@ button.selected {
   transition-duration: 0.4s;
 }
 
+#eraser-tool > i {
+  padding: 0 0.5px;
+}
+
+#undo-tool {
+  background-color: #2f2f2f;
+  color: white;
+  padding: 10px;
+  font-size: 16px;
+  border: none;
+  cursor: pointer;
+  border-radius: 50%;
+  margin-right: 8px;
+}
+
+#undo-tool:hover {
+  background-color: #4f4f4f !important;
+  transition-duration: 0.4s;
+}
+
+#undo-tool.disabled {
+  display: none;
+}
+
+#undo-tool > i {
+  padding: 0 3px 0 0;
+}
+
+#fast-undo-tool {
+  background-color: #2f2f2f;
+  color: white;
+  padding: 10px;
+  font-size: 16px;
+  border: none;
+  cursor: pointer;
+  border-radius: 50%;
+  margin-right: 8px;
+}
+
+#fast-undo-tool:hover {
+  background-color: #4f4f4f !important;
+  transition-duration: 0.4s;
+}
+
+#fast-undo-tool.disabled {
+  display: none;
+}
+
+#fast-undo-tool > i {
+  padding: 0 1px;
+}
+
 .properties {
   display: none;
   position: fixed;
@@ -547,11 +603,8 @@ button.selected {
   align-items: center;
   background-color: #4f4f4fb7;
   border-radius: 4px;
-}
-
-#user-avatar:hover {
-  background-color: #4f4f4f !important;
-  transition-duration: 0.4s;
+  margin-left: 0.75em;
+  padding: 0 0.75em 0 0;
 }
 
 #status-info {
diff --git a/src/app.js b/src/app.js
index 62626b62832d8be6b263f7489d3858eeaf8fea11..4367171fd94c405ca120d0152251580f76805b91 100644
--- a/src/app.js
+++ b/src/app.js
@@ -158,6 +158,11 @@ const onRoomConnect = (room_) => {
       canvas.renderPath(id, points, room.erasureIntervals[id] || [])
     },
   )
+
+  room.addEventListener("undoEnabled", () => {
+    HTML.fastUndoButton.classList.remove("disabled")
+    HTML.undoButton.classList.remove("disabled")
+  })
 }
 
 const tryRoomConnect = async (roomID) => {
@@ -190,12 +195,35 @@ const onRoomJoinEnter = () => {
 
   canvas.clear()
   HTML.connectedPeers.innerHTML = "No peers are connected"
+  HTML.fastUndoButton.classList.add("disabled")
+  HTML.undoButton.classList.add("disabled")
 
   tryRoomConnect(selectedRoomID)
 }
 
 HTML.roomConnectButton.addEventListener("click", onRoomJoinEnter)
 
+HTML.fastUndoButton.addEventListener("click", () => {
+  if (room == null) return
+
+  room.fastUndo()
+
+  if (!room.canUndo()) {
+    HTML.fastUndoButton.classList.add("disabled")
+    HTML.undoButton.classList.add("disabled")
+  }
+})
+HTML.undoButton.addEventListener("click", () => {
+  if (room == null) return
+
+  room.undo()
+
+  if (!room.canUndo()) {
+    HTML.fastUndoButton.classList.add("disabled")
+    HTML.undoButton.classList.add("disabled")
+  }
+})
+
 HTML.roomIDElem.addEventListener("keydown", (event) => {
   if (event.key == "Enter") {
     event.target.blur()
diff --git a/src/elements.js b/src/elements.js
index b1902a21ff6bd350fede2d44e7300c243ab7efa3..d2dd34fb019b214355e71fcbbc0586963bccb9d2 100644
--- a/src/elements.js
+++ b/src/elements.js
@@ -13,6 +13,9 @@ export const canvas = document.getElementById("canvas")
 export const penButton = document.getElementById("pen-tool")
 export const eraserButton = document.getElementById("eraser-tool")
 
+export const fastUndoButton = document.getElementById("fast-undo-tool")
+export const undoButton = document.getElementById("undo-tool")
+
 export const roomIDElem = document.getElementById("room-id")
 export const roomConnectButton = document.getElementById("room-connect")
 export const connectedRoomID = document.getElementById("connected-room-id")
diff --git a/src/room.js b/src/room.js
index a158b5a902f43fa963f10023c76a2d63bbdee235..d39589111bdb4a6e4b3a83e08aed05f4c2420c5c 100644
--- a/src/room.js
+++ b/src/room.js
@@ -24,6 +24,7 @@ class Room extends EventTarget {
     this._y = null
     this.ownID = null
     this.erasureIntervals = {}
+    this.undoStack = []
   }
 
   disconnect() {
@@ -36,11 +37,25 @@ class Room extends EventTarget {
     this.shared.strokePoints.set(id, Y.Array).push([[x, y, w, colour]])
     this.shared.eraseIntervals.set(id, Y.Union)
 
+    this.undoStack.push([id, 0, 0])
+
+    this.dispatchEvent(new CustomEvent("undoEnabled"))
+
     return id
   }
 
   extendPath(id, [x, y, w, colour]) {
-    this.shared.strokePoints.get(id).push([[x, y, w, colour]])
+    const path = this.shared.strokePoints.get(id)
+
+    path.push([[x, y, w, colour]])
+
+    if (path.length == 2) {
+      this.undoStack[this.undoStack.length - 1] = [id, 0, 1]
+    } else {
+      this.undoStack.push([id, path.length - 2, path.length - 1])
+    }
+
+    this.dispatchEvent(new CustomEvent("undoEnabled"))
   }
 
   extendErasureIntervals(pathID, pointID, newIntervals) {
@@ -49,6 +64,40 @@ class Room extends EventTarget {
       .merge(flattenErasureIntervals({ [pointID]: newIntervals }))
   }
 
+  undo() {
+    const operation = this.undoStack.pop()
+
+    if (!operation) return
+
+    const [id, ...interval] = operation
+
+    this.shared.eraseIntervals.get(id).merge([interval])
+  }
+
+  fastUndo() {
+    let from = this.undoStack.length - 1
+
+    if (from < 0) return
+
+    // eslint-disable-next-line no-unused-vars
+    const [id, _, end] = this.undoStack[from]
+
+    for (; from >= 0; from--) {
+      if (this.undoStack[from][0] != id) {
+        from++
+        break
+      }
+    }
+
+    this.undoStack = this.undoStack.slice(0, Math.max(0, from))
+
+    this.shared.eraseIntervals.get(id).merge([[0, end]])
+  }
+
+  canUndo() {
+    return this.undoStack.length > 0
+  }
+
   getPaths() {
     const paths = new Map()