diff --git a/editor/editor.html b/editor/editor.html
index 527abd44ef3fc12f8ba68f1d8b699bd7f4fa04e9..65de428c39875d03bae0623414e3dacc353e65ba 100644
--- a/editor/editor.html
+++ b/editor/editor.html
@@ -30,6 +30,7 @@
     <script src="%WWW%editor/js/tools/collecttool.js"></script>
     <script src="%WWW%editor/js/tools/deletetool.js"></script>
     <script src="%WWW%editor/js/tools/addnodetool.js"></script>
+    <script src="%WWW%editor/js/tools/connecttool.js"></script>
     <script src="%WWW%editor/js/display.js"></script>
     <script src="%WWW%editor/js/state.js"></script>
     <script src="%WWW%editor/js/editor.js"></script>
diff --git a/editor/images/tools/connect.png b/editor/images/tools/connect.png
new file mode 100644
index 0000000000000000000000000000000000000000..0cb1991878d15423eaa17ffaf0d4379a2bedc88d
Binary files /dev/null and b/editor/images/tools/connect.png differ
diff --git a/editor/js/graph.js b/editor/js/graph.js
index a8d3d4095dbc985562d40dc69f2ccba09fdc204b..6987a65b667fdaae7aff75e56c8b79bc14a167c3 100644
--- a/editor/js/graph.js
+++ b/editor/js/graph.js
@@ -196,6 +196,40 @@ const graph = {
         return result;
     },
 
+    addLink(sourceId, targetId, linkDetails = {}) {
+        // Copy params
+        var newLink = linkDetails;
+
+        // Make sure the IDs exist
+        if (
+            sourceId === undefined ||
+            targetId === undefined ||
+            graph.existsNodeId(sourceId) === false ||
+            graph.existsNodeId(targetId) === false
+        ) {
+            return;
+        }
+
+
+        // Make sure the link is unique
+        if (graph.existsLink(sourceId, targetId)) {
+            return;
+        }
+
+        newLink[LINK_SOURCE] = sourceId;
+        newLink[LINK_TARGET] = targetId;
+
+        // Basic node properties
+        newLink.link = true;
+        newLink.node = false;
+
+        // Add node
+        graph.data[GRAPH_LINKS].push(newLink);
+        graph.update();
+
+        return newLink;
+    },
+
     addNode(nodeDetails) {
         // Copy params
         var newNode = nodeDetails;
@@ -210,7 +244,6 @@ const graph = {
         // Basic node properties
         newNode.node = true;
         newNode.link = false;
-        newNode.index = graph.data[GRAPH_NODES].length;
 
         // Add node
         graph.data[GRAPH_NODES].push(newNode);
diff --git a/editor/js/state.js b/editor/js/state.js
index a58d25332e55150220ad2ed0b38eb6fd925fb6dc..4d46c5e7c8975ad633d4fb0fd992280d440d55b8 100644
--- a/editor/js/state.js
+++ b/editor/js/state.js
@@ -3,6 +3,7 @@ const TOOLS = {
     collect: new CollectTool("collect"),
     delete: new DeleteTool("delete"),
     addnode: new AddNodeTool("addnode"),
+    connect: new ConnectTool("connect"),
 };
 
 const CONTEXT = {
diff --git a/editor/js/tools/connecttool.js b/editor/js/tools/connecttool.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd47b504f0ed047920382266d6deb7d6c15d769a
--- /dev/null
+++ b/editor/js/tools/connecttool.js
@@ -0,0 +1,46 @@
+const KEEP_SOURCE_KEY_ID = 17;
+
+class ConnectTool extends Tool {
+    constructor(key) {
+        super("Connect two nodes", "connect", key);
+        this.keepSource = false;
+    }
+
+    onNodeClick(node) {
+        // Is a first node selected?
+        if (state.selectedItem === undefined || state.selectedItem.node === false) {
+            state.setSelectedItem(node);
+            return;
+        }
+
+        // Add new link
+        var link = graph.addLink(state.selectedItem[NODE_ID], node[NODE_ID]);
+
+        if (link === undefined) {
+            console.error("Could not create new link");
+            return;
+        }
+
+        if (this.keepSource === false) {
+            // Deselect the current first node
+            // TODO: Returned object not yet converted to normal one
+            state.setSelectedItem(link);
+        }
+    }
+
+    onBackgroundClick(event, positions) {
+        state.setSelectedItem(undefined);
+    }
+
+    onKeyDown(key) {
+        if (key.keyCode === KEEP_SOURCE_KEY_ID) {
+            this.keepSource = true;
+        }
+    }
+
+    onKeyUp(key) {
+        if (key.keyCode === KEEP_SOURCE_KEY_ID) {
+            this.keepSource = false;
+        }
+    }
+}
\ No newline at end of file