diff --git a/examples/whiteboard/README.md b/examples/whiteboard/README.md
new file mode 100644
index 0000000000..8d443db8a1
--- /dev/null
+++ b/examples/whiteboard/README.md
@@ -0,0 +1,17 @@
+
+# Socket.IO Collaborative Whiteboard
+
+A simple collaborative whiteboard for socket.io
+
+## How to use
+
+```
+$ npm i && npm start
+```
+
+And point your browser to `http://localhost:3000`. Optionally, specify
+a port by supplying the `PORT` env variable.
+
+## Features
+
+- draw on the whiteboard and all other users will see you drawings live
diff --git a/examples/whiteboard/index.js b/examples/whiteboard/index.js
new file mode 100644
index 0000000000..44cc97f9d3
--- /dev/null
+++ b/examples/whiteboard/index.js
@@ -0,0 +1,16 @@
+
+const express = require('express');
+const app = express();
+const http = require('http').Server(app);
+const io = require('socket.io')(http);
+const port = process.env.PORT || 3000;
+
+app.use(express.static(__dirname + '/public'));
+
+function onConnection(socket){
+ socket.on('drawing', (data) => socket.broadcast.emit('drawing', data));
+}
+
+io.on('connection', onConnection);
+
+http.listen(port, () => console.log('listening on port ' + port));
diff --git a/examples/whiteboard/package.json b/examples/whiteboard/package.json
new file mode 100644
index 0000000000..cb78467785
--- /dev/null
+++ b/examples/whiteboard/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "whiteboard",
+ "version": "1.0.0",
+ "description": "A simple collaborative whiteboard using socket.io",
+ "main": "index.js",
+ "keywords": [
+ "socket.io",
+ "whiteboard"
+ ],
+ "dependencies": {
+ "express": "4.9.x",
+ "socket.io": "latest"
+ },
+ "scripts": {
+ "start": "node index"
+ },
+ "author": "Damien Arrachequesne",
+ "license": "MIT"
+}
diff --git a/examples/whiteboard/public/index.html b/examples/whiteboard/public/index.html
new file mode 100644
index 0000000000..710932a897
--- /dev/null
+++ b/examples/whiteboard/public/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+ Socket.IO whiteboard
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/whiteboard/public/main.js b/examples/whiteboard/public/main.js
new file mode 100644
index 0000000000..808f52b223
--- /dev/null
+++ b/examples/whiteboard/public/main.js
@@ -0,0 +1,100 @@
+'use strict';
+
+(function() {
+
+ var socket = io();
+ var canvas = document.getElementsByClassName('whiteboard')[0];
+ var colors = document.getElementsByClassName('color');
+ var context = canvas.getContext('2d');
+
+ var current = {
+ color: 'black'
+ };
+ var drawing = false;
+
+ canvas.addEventListener('mousedown', onMouseDown, false);
+ canvas.addEventListener('mouseup', onMouseUp, false);
+ canvas.addEventListener('mouseout', onMouseUp, false);
+ canvas.addEventListener('mousemove', throttle(onMouseMove, 10), false);
+
+ for (var i = 0; i < colors.length; i++){
+ colors[i].addEventListener('click', onColorUpdate, false);
+ }
+
+ socket.on('drawing', onDrawingEvent);
+
+ window.addEventListener('resize', onResize, false);
+ onResize();
+
+
+ function drawLine(x0, y0, x1, y1, color, emit){
+ context.beginPath();
+ context.moveTo(x0, y0);
+ context.lineTo(x1, y1);
+ context.strokeStyle = color;
+ context.lineWidth = 2;
+ context.stroke();
+ context.closePath();
+
+ if (!emit) { return; }
+ var w = canvas.width;
+ var h = canvas.height;
+
+ socket.emit('drawing', {
+ x0: x0 / w,
+ y0: y0 / h,
+ x1: x1 / w,
+ y1: y1 / h,
+ color: color
+ });
+ }
+
+ function onMouseDown(e){
+ drawing = true;
+ current.x = e.clientX;
+ current.y = e.clientY;
+ }
+
+ function onMouseUp(e){
+ if (!drawing) { return; }
+ drawing = false;
+ drawLine(current.x, current.y, e.clientX, e.clientY, current.color, true);
+ }
+
+ function onMouseMove(e){
+ if (!drawing) { return; }
+ drawLine(current.x, current.y, e.clientX, e.clientY, current.color, true);
+ current.x = e.clientX;
+ current.y = e.clientY;
+ }
+
+ function onColorUpdate(e){
+ current.color = e.target.className.split(' ')[1];
+ }
+
+ // limit the number of events per second
+ function throttle(callback, delay) {
+ var previousCall = new Date().getTime();
+ return function() {
+ var time = new Date().getTime();
+
+ if ((time - previousCall) >= delay) {
+ previousCall = time;
+ callback.apply(null, arguments);
+ }
+ };
+ }
+
+ function onDrawingEvent(data){
+ var w = canvas.width;
+ var h = canvas.height;
+ drawLine(data.x0 * w, data.y0 * h, data.x1 * w, data.y1 * h, data.color);
+ }
+
+ // make the canvas fill its parent
+ function onResize() {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ }
+
+})();
diff --git a/examples/whiteboard/public/style.css b/examples/whiteboard/public/style.css
new file mode 100644
index 0000000000..437a29cfef
--- /dev/null
+++ b/examples/whiteboard/public/style.css
@@ -0,0 +1,44 @@
+
+/**
+ * Fix user-agent
+ */
+
+* {
+ box-sizing: border-box;
+}
+
+html, body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+/**
+ * Canvas
+ */
+
+.whiteboard {
+ height: 100%;
+ width: 100%;
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+}
+
+.colors {
+ position: fixed;
+}
+
+.color {
+ display: inline-block;
+ height: 48px;
+ width: 48px;
+}
+
+.color.black { background-color: black; }
+.color.red { background-color: red; }
+.color.green { background-color: green; }
+.color.blue { background-color: blue; }
+.color.yellow { background-color: yellow; }