diff --git a/app/public/index.html b/app/public/index.html
index 8a7610fdb6d0e0c947f88108fa7677c06a0ee025..9132bd6c20097a139bb584bfa1cc8a5e368f6777 100644
--- a/app/public/index.html
+++ b/app/public/index.html
@@ -1,62 +1,50 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-
-    <meta
-      name="viewport"
-      content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
-    />
-
-    <!-- Open Graph -->
-    <meta
-      property="og:image"
-      content="https://alpha.nodenogg.in/files/logo_nt.png"
-    />
-    <meta property="og:image:width" content="216" />
-    <meta property="og:image:height" content="226" />
-    <meta property="og:image:type" content="image/png" />
-    <meta property="og:title" content="nodenogg.in - ALPHA build" />
-    <meta
-      property="og:description"
-      content="nodenoggin is a Free Open Source Software (FOSS) project that empowers communities of practice to build and create knowledge by bridging the physical and digital studio spaces. designers and makers gather and spatially arrange materials, links and thoughts within the shared digital platform."
-    />
-    <meta property="og:type" content="website" />
-    <meta property="og:url" content="https://alpha.nodenogg.in" />
-
-    <!-- Twitter -->
-    <meta name="twitter:card" content="summary" />
-    <meta
-      property="twitter:image"
-      content="https://alpha.nodenogg.in/files/logo_nt.jpg"
-    />
-    <meta property="twitter:image:width" content="216" />
-    <meta property="twitter:image:height" content="226" />
-    <meta property="twitter:image:type" content="image/png" />
-    <meta property="twitter:title" content="nodenogg.in - ALPHA build" />
-    <meta
-      property="twitter:description"
-      content="nodenoggin is a Free Open Source Software (FOSS) project that empowers communities of practice to build and create knowledge by bridging the physical and digital studio spaces. designers and makers gather and spatially arrange materials, links and thoughts within the shared digital platform."
-    />
-
-    <meta property="twitter:url" content="https://alpha.nodenogg.in" />
-    <meta property="twitter:site" content="@nodenoggin" />
-    <meta property="twitter:creator" content="@nodenoggin" />
-
-    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
-
-    <title><%= htmlWebpackPlugin.options.title %></title>
-  </head>
-  <body>
-    <noscript>
-      <strong
-        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
-        properly without JavaScript enabled. Please enable it to
-        continue.</strong
-      >
-    </noscript>
-    <div id="app"></div>
-    <!-- built files will be auto injected -->
-  </body>
-</html>
+
+<head>
+  <meta charset="utf-8" />
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+
+  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />
+
+  <!-- Open Graph -->
+  <meta property="og:image" content="https://alpha.nodenogg.in/files/logo_nt.png" />
+  <meta property="og:image:width" content="216" />
+  <meta property="og:image:height" content="226" />
+  <meta property="og:image:type" content="image/png" />
+  <meta property="og:title" content="nodenogg.in - ALPHA build" />
+  <meta property="og:description"
+    content="nodenoggin is a Free Open Source Software (FOSS) project that empowers communities of practice to build and create knowledge by bridging the physical and digital studio spaces. designers and makers gather and spatially arrange materials, links and thoughts within the shared digital platform." />
+  <meta property="og:type" content="website" />
+  <meta property="og:url" content="https://alpha.nodenogg.in" />
+
+  <!-- Twitter -->
+  <meta name="twitter:card" content="summary" />
+  <meta property="twitter:image" content="https://alpha.nodenogg.in/files/logo_nt.jpg" />
+  <meta property="twitter:image:width" content="216" />
+  <meta property="twitter:image:height" content="226" />
+  <meta property="twitter:image:type" content="image/png" />
+  <meta property="twitter:title" content="nodenogg.in - ALPHA build" />
+  <meta property="twitter:description"
+    content="nodenoggin is a Free Open Source Software (FOSS) project that empowers communities of practice to build and create knowledge by bridging the physical and digital studio spaces. designers and makers gather and spatially arrange materials, links and thoughts within the shared digital platform." />
+
+  <meta property="twitter:url" content="https://alpha.nodenogg.in" />
+  <meta property="twitter:site" content="@nodenoggin" />
+  <meta property="twitter:creator" content="@nodenoggin" />
+
+  <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
+
+  <title></title>
+</head>
+
+<body>
+  <noscript>
+    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
+      properly without JavaScript enabled. Please enable it to
+      continue.</strong>
+  </noscript>
+  <div id="app"></div>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>
\ No newline at end of file
diff --git a/app/src/components/ConnectorsLayer.vue b/app/src/components/ConnectorsLayer.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1294760926bac00e215793855d3e156a0945c479
--- /dev/null
+++ b/app/src/components/ConnectorsLayer.vue
@@ -0,0 +1,160 @@
+<template>
+  <canvas ref="canvas"></canvas>
+</template>
+
+<script>
+//import { mapState } from 'vuex'
+//import { generateLinkHandles } from './mixins/nodes.js'
+// import { drawLinkBezierCurve, drawArrowHead } from './mixins/canvas.js'
+import { color } from './mixins/color.js'
+
+export default {
+  name: 'ConnectorsLayer',
+  mixins: [color],
+
+  mounted() {
+    this.getPalette(1, 1)
+  }
+}
+
+// export default {
+//   name: 'ConnectorsLayer',
+//   mixins: [generateLinkHandles, drawLinkBezierCurve, drawArrowHead, getPalette],
+//   props: {
+//     nodes: {
+//       type: Array
+//     },
+//     connections: {
+//       type: Array
+//     }
+//   },
+//   mounted() {
+//     this.canvas = this.$refs.canvas
+//     this.context = this.canvas.getContext('2d')
+//     this.draw()
+//   },
+//   data() {
+//     return {
+//       canvas: {},
+//       context: {},
+//       defaultLinkProps: {
+//         // these are our initial 'default' settings for each link
+//         hue: 'dark',
+//         tension: 0.25,
+//         lineWidth: 3,
+//         lineDash: [0, 0]
+//       }
+//     }
+//   },
+//   // computed: mapState({
+//   //   configConnect: state => state.configConnect
+//   // }),
+
+//   // Watch the props for changes and, if necessary, redraw canvas
+//   watch: {
+//     nodes() {
+//       this.draw()
+//     },
+//     links() {
+//       this.draw()
+//     }
+//   },
+//   methods: {
+//     /**
+//      * Clears the context, renders links and nodes on initial load
+//      * and when new data has been provided
+//      **/
+//     draw() {
+//       this.clear()
+//       this.context.save()
+//       this.renderAllLinks()
+//       this.renderAllNodes()
+//       this.context.restore()
+//     },
+
+//     /**
+//      * Clears drawing context
+//      **/
+//     clear() {
+//       this.context.clearRect(0, 0, this.width, this.height)
+//     },
+
+//     /**
+//      * Where a node can be rendered
+//      * @param {Node} node - Target node
+//      **/
+//     renderNode({ x, y }) {
+//       this.context.setTransform(1, 0, 0, 1, x, y)
+//       // this renders nothing, but if we wanted to we
+//       // could render nodes in the canvas as well
+//       this.context.setTransform(1, 0, 0, 1, 0, 0)
+//     },
+
+//     /**
+//      * Renders a link between two nodes
+//      **/
+//     renderLink({ from, to, color, lineDash, lineWidth, hue, tension, arrow }) {
+//       // fetch the nodes based on their id reference provided in the link
+//       const fromNode = this.findNode(from)
+//       const toNode = this.findNode(to)
+
+//       if (fromNode && toNode) {
+//         // apply the link color, falling back to defaultLinkProps
+//         this.context.strokeStyle = getPalette(
+//           color,
+//           hue || this.defaultLinkProps.hue
+//         )
+
+//         // apply link styling, falling back to defaultLinkProps
+//         this.context.setLineDash(lineDash || this.defaultLinkProps.lineDash)
+//         this.context.lineWidth = lineWidth || this.defaultLinkProps.lineWidth
+
+//         // establish link tension, falling back to defaultLinkProps
+//         const curveTension = !isNaN(tension) || this.defaultLinkProps.tension
+
+//         // add the curve to our drawing context
+//         drawLinkBezierCurve(this.context, fromNode, toNode, curveTension)
+//         if (arrow) drawArrowHead(this.context, fromNode, toNode)
+
+//         // render the curve
+//         this.context.stroke()
+//       }
+//     },
+
+//     /**
+//      * Helper to fetch a single node based on its id
+//      *
+//      * @param {string} id - Reference to node id
+//      * @returns {Node}
+//      **/
+//     findNode(id) {
+//       return [...this.nodes].find(pt => pt.id === id)
+//     },
+
+//     /**
+//      * Iterate through the array of links, rendering each one
+//      **/
+//     renderAllLinks() {
+//       for (let link of this.links) {
+//         this.renderLink(link)
+//       }
+//     },
+
+//     /**
+//      * Included for demo only, doesn't actually render anything
+//      * iterate through the array of nodes, rendering each one
+//      **/
+//     renderAllNodes() {
+//       for (let node of this.nodes) {
+//         this.renderNode(node)
+//       }
+//     }
+//   }
+// }
+</script>
+<style scoped>
+canvas {
+  z-index: 1;
+  position: absolute;
+}
+</style>
diff --git a/app/src/components/mixins/canvas.js b/app/src/components/mixins/canvas.js
new file mode 100644
index 0000000000000000000000000000000000000000..16a80c3c932e53171251551dedc6f8fc10ea5f18
--- /dev/null
+++ b/app/src/components/mixins/canvas.js
@@ -0,0 +1,58 @@
+// import * as win from "@/constants/window"
+// import { generateLinkHandles } from "@/utils/nodes"
+// import { mapRange, distance } from "@/utils/numbers"
+
+//////////////////////////////////////////////////////////////////////
+// Canvas Utilities
+//////////////////////////////////////////////////////////////////////
+// Because these helpers directly manipulate the drawing context,
+// their methods don't need to return anything
+
+/**
+ * Adds a bezier curve to the drawing context
+ *
+ * @param {CanvasRenderingContext2D} context - 2D rendering context
+ * @param {Node} from - Origin node
+ * @param {Node} to - Target node
+ * @param {number} tension - Tension of the curve to be drawn
+ *
+ *  */
+export const drawLinkBezierCurve = (context, from, to, tension) => {
+  const [fromHandle, toHandle] = generateLinkHandles(from, to)
+
+  // This is a simple way to adjust the link tension depending
+  // on the distance the link covers
+  const adjustedTension = mapRange(
+    distance(fromHandle, toHandle),
+    0,
+    win.width,
+    tension * 0.01,
+    tension * 2
+  )
+
+  context.beginPath()
+  context.moveTo(fromHandle.x, fromHandle.y)
+  context.bezierCurveTo(
+    fromHandle.x * (1 + adjustedTension),
+    fromHandle.y,
+    toHandle.x * (1 - adjustedTension),
+    toHandle.y,
+    toHandle.x,
+    toHandle.y
+  )
+}
+
+export const drawArrowHead = (context, from, to, size = 10, rotation = 0.0) => {
+  const [fromHandle, toHandle] = generateLinkHandles(from, to)
+  const angle = angleBetween(fromHandle, toHandle)
+
+  context.setLineDash([0, 0])
+  context.setTransform(1, 0, 0, 1, toHandle.x - size, toHandle.y)
+
+  context.rotate(angle * 0.65)
+
+  context.moveTo(-size, -size / 1.25)
+  context.lineTo(0, 0)
+  context.lineTo(-size, size / 1.25)
+  context.setTransform(1, 0, 0, 1, 0, 0)
+}
diff --git a/app/src/components/mixins/color.js b/app/src/components/mixins/color.js
new file mode 100644
index 0000000000000000000000000000000000000000..c86493d1f55176c57a7f1cdcbcda985deb1568bc
--- /dev/null
+++ b/app/src/components/mixins/color.js
@@ -0,0 +1,60 @@
+export const color = {
+  data() {
+    return {
+      palette: {
+        coral: {
+          light: '#FFD8E1',
+          dark: '#F56789'
+        },
+        lime: {
+          light: '#EEFFBC',
+          dark: '#B9DF4E'
+        },
+        blue: {
+          light: '#CDEAFF',
+          dark: '#4EB4FF'
+        },
+
+        purple: {
+          light: '#DAD9FE',
+          dark: '#8A80F6'
+        },
+        pink: {
+          light: '#FBE9FF',
+          dark: '#E47EFD'
+        },
+        yellow: {
+          light: '#FFF3CA',
+          dark: '#FFD84F'
+        },
+        mono: {
+          light: '#FFFFFF',
+          dark: '#A3A3A3'
+        }
+      }
+    }
+  },
+
+  methods: {
+    getPalette(color, hue) {
+      this.palette[(color, hue)] //palette[color][hue]
+      //console.log(this.palette[(1, 1)])
+      // const getPalette = (color = 'mono', type) =>
+      //   palette[color] ? palette[color][type] : palette.mono[type]
+      //
+    }
+  }
+}
+
+/**
+ * Selects a HEX color value depending on a supplied key reference,
+ * providing a default (mono) value if none is found.
+ *
+ * @param {string} color - Target palette (from above)
+ * @param {string} type - Target color type (light or dark)
+ * @returns {string} hex color value
+ *
+ *  */
+// const getPalette = (color = 'mono', type) =>
+//   palette[color] ? palette[color][type] : palette.mono[type]
+//
diff --git a/app/src/components/mixins/drag.js b/app/src/components/mixins/drag.js
deleted file mode 100644
index d270cb77d59810055e4d71631e9e81e821ba28d9..0000000000000000000000000000000000000000
--- a/app/src/components/mixins/drag.js
+++ /dev/null
@@ -1,65 +0,0 @@
-export const drag = {
-  methods: {
-    makeDraggable(incoming) {
-      var active = false
-      var currentX
-      var currentY
-      var initialX
-      var initialY
-      var xOffset = 0
-      var yOffset = 0
-
-      incoming.addEventListener('mousedown', startDrag)
-      incoming.addEventListener('mousemove', drag)
-      incoming.addEventListener('mouseup', endDrag)
-      incoming.addEventListener('mouseleave', endDrag)
-      incoming.addEventListener('touchstart', startDrag)
-      incoming.addEventListener('touchmove', drag)
-      incoming.addEventListener('touchend', endDrag)
-      incoming.addEventListener('touchleave', endDrag)
-      incoming.addEventListener('touchcancel', endDrag)
-
-      function startDrag(e) {
-        if (e.type === 'touchstart') {
-          initialX = e.touches[0].clientX - xOffset
-          initialY = e.touches[0].clientY - yOffset
-        } else {
-          initialX = e.clientX - xOffset
-          initialY = e.clientY - yOffset
-        }
-        if (e.target.parentNode.classList.contains('node')) {
-          active = true
-        }
-      }
-
-      function drag(e) {
-        if (active) {
-          e.preventDefault()
-
-          if (e.type === 'touchmove') {
-            currentX = e.touches[0].clientX - initialX
-            currentY = e.touches[0].clientY - initialY
-          } else {
-            currentX = e.clientX - initialX
-            currentY = e.clientY - initialY
-          }
-
-          xOffset = currentX
-          yOffset = currentY
-
-          setTranslate(currentX, currentY, incoming)
-        }
-      }
-
-      function endDrag() {
-        initialX = currentX
-        initialY = currentY
-        active = false
-      }
-
-      function setTranslate(xPos, yPos, el) {
-        el.style.transform = 'translate3d(' + xPos + 'px, ' + yPos + 'px, 0)'
-      }
-    }
-  }
-}
diff --git a/app/src/components/mixins/draw.js b/app/src/components/mixins/draw.js
deleted file mode 100644
index 9bd5dc3920c911698a80b58d605f5549795cd87c..0000000000000000000000000000000000000000
--- a/app/src/components/mixins/draw.js
+++ /dev/null
@@ -1,30 +0,0 @@
-export const draw = {
-  methods: {
-    draw() {
-      this.box(this.ctx, this.x, this.y)
-    },
-
-    box(ctx, x, y) {
-      ctx.setTransform(1, 0, 0, 1, x, y)
-
-      ctx.fillStyle = this.configConnect.fill
-      ctx.fillRect(
-        this.configConnect.x,
-        this.configConnect.y,
-        this.configConnect.height,
-        this.configConnect.width
-      )
-
-      ctx.fillStyle = this.configHandle.fill
-      ctx.fillRect(
-        this.configHandle.x,
-        this.configHandle.y,
-        this.configHandle.height,
-        this.configHandle.width
-      )
-
-      ctx.stroke()
-      ctx.setTransform(1, 0, 0, 1, 0, 0)
-    }
-  }
-}
diff --git a/app/src/components/mixins/nodes.js b/app/src/components/mixins/nodes.js
new file mode 100644
index 0000000000000000000000000000000000000000..adc1df5abb8c9a0e7636684af6842a8633cb8ae3
--- /dev/null
+++ b/app/src/components/mixins/nodes.js
@@ -0,0 +1,235 @@
+//////////////////////////////////////////////////////////////////////
+// Type Definitions
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * A representation of a point
+ * @typedef {Object} Point
+ * @property {number} x - Horizontal (x) position in pixels
+ * @property {number} y - Vertical (y) position in pixels
+ */
+
+/**
+ * A representation of an area
+ * @typedef {Object} Area
+ * @property {number} x1 - Top left (x) position in pixels
+ * @property {number} y1 - Top left (y) position in pixels
+ * @property {number} x2 - Bottom right (x) position in pixels
+ * @property {number} y2 - Bottom right (y) position in pixels
+ */
+
+/**
+ * A representation of a node
+ * @typedef {Object} Node
+ * @property {number} x - Horizontal (x) position in pixels
+ * @property {number} y - Vertical (y) position in pixels
+ * @property {number} width - Node width in pixels
+ * @property {number} height - Node height in pixels
+ */
+
+//////////////////////////////////////////////////////////////////////
+// NODES
+//////////////////////////////////////////////////////////////////////
+// Helpers for working with nodes, points and areas
+
+/**
+ * Converts a @Node into the @Area it covers
+ *
+ * @param {Node} node - Origin node
+ * @param {number} threshold - Additional threshold area (optional)
+ * @return {Area} Area covered by box, including threshold
+ *
+ *  */
+export const nodeToArea = (node, threshold = 0.0) => {
+  return {
+    x1: node.x * (1.0 - threshold),
+    y1: node.y * (1.0 - threshold),
+    x2: (node.x + node.width) * (1.0 + threshold),
+    y2: (node.y + node.height) * (1.0 + threshold)
+  }
+}
+
+/**
+ * Converts an @Area into a node
+ *
+ * @param {Area} area - Origin node
+ * @return {Node}
+ *
+ *  */
+export const areaToNode = area => {
+  return {
+    x: area.x1,
+    y: area.y1,
+    width: Math.abs(area.x2 - area.x1),
+    height: Math.abs(area.y2 - area.y1)
+  }
+}
+
+/**
+ * Returns whether one @Area completely contains another @Area
+ *
+ * @param {Area} a
+ * @param {Area} b
+ * @return {boolean}
+ *
+ *  */
+export const areaContains = (a, b) =>
+  !(b.x1 < a.x1 || b.y1 < a.y1 || b.x2 > a.x2 || b.y2 > a.y2)
+
+/**
+ * Returns whether one @Area overlaps another @Area
+ *
+ * @param {Area} a
+ * @param {Area} b
+ * @return {boolean}
+ *
+ *  */
+export const areaOverlaps = (a, b) => {
+  if (a.x1 >= b.x2 || b.x1 >= a.x2) return false
+  if (a.y1 >= b.y2 || b.y1 >= a.y2) return false
+
+  return true
+}
+
+/**
+ * Returns anchor positions for drawing links between two Nodes.
+ *
+ * @param {Node} from - Origin node
+ * @param {Node} from - Target node
+ * @return {array} Array of {x,y} positions
+ *
+ *  */
+export const generateLinkHandles = (from, to) => {
+  const toLeft = to.x > from.x
+  return [
+    {
+      x: from.x + from.width,
+      y: from.y + from.height / 2
+    },
+    {
+      // x: to.x + to.width / 2,
+      x: to.x + 10,
+      y: to.y + to.height / 2
+    }
+  ]
+}
+
+/**
+ * Returns a list of nodes which overlap with a given {x1,y1,x2,y2} @Area
+ *
+ * @param {Area} area - Origin node
+ * @param {array} node - List of nodes to check against
+ * @param {number} threshold - Additional threshold area (optional)
+ * @return {array} Array of @Node objects which match
+ *
+ *  */
+export const areaNodeIntersections = (targetNode, nodes, threshold = 0) => {
+  return nodes
+    .filter(node =>
+      areaOverlaps(nodeToArea(targetNode), nodeToArea(node, threshold))
+    )
+    .map(({ id }) => id)
+}
+
+/**
+ * Returns a list of nodes which overlap with a given {x,y} @Point
+ *
+ * @param {Point} point
+ * @param {array} node - List of nodes to check against
+ * @return {array} Array of @Node objects which match
+ *
+ *  */
+export const pointNodeIntersections = (point, nodes) => {
+  return nodes.filter(node => pointWithinNode(point, node)).map(({ id }) => id)
+}
+
+/**
+ * Checks whether a @Point is within a @Node
+ *
+ * @param {Point} point
+ * @param {Node} node
+ * @return {boolean}
+ *
+ *  */
+export const pointWithinNode = (point, node) => {
+  const { x1, y1, x2, y2 } = nodeToArea(node)
+  return x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2
+}
+
+/**
+ * Converts an array of nodes into a single large @Area
+ *
+ * @param {array} node - List of nodes
+ * @return {Area}
+ *
+ *  */
+export const generateAreaFromNodes = nodes => {
+  const sum = {}
+
+  for (let node of nodes) {
+    const area = nodeToArea(node)
+    if (!sum.x1 || area.x1 < sum.x1) {
+      sum.x1 = area.x1
+    }
+    if (!sum.y1 || area.y1 < sum.y1) {
+      sum.y1 = area.y1
+    }
+    if (!sum.x2 || area.x2 > sum.x2) {
+      sum.x2 = area.x2
+    }
+    if (!sum.y2 || area.y2 > sum.y2) {
+      sum.y2 = area.y2
+    }
+  }
+  return sum
+}
+
+/**
+ * Generates a node shape from two given points
+ *  */
+export const generateNode = (origin, point) => {
+  const minusX = origin.x > point.x
+  const minusY = origin.y > point.y
+  const width = Math.abs(point.x - origin.x)
+  const height = Math.abs(point.y - origin.y)
+
+  return {
+    x: minusX ? origin.x - width : origin.x,
+    y: minusY ? origin.y - height : origin.y,
+    width,
+    height
+  }
+}
+
+/**
+ * Transforms a grouped set of nodes based on a base transformation
+ *
+ * @param {Node[]} nodes - List of nodes
+ * @param {Point} transform – transform
+ * @return {Node[]}
+ *  */
+export const transformNodeSelection = (nodes, transform) => {
+  const baseCoordinates = {}
+
+  // iterate through all nodes to get underlying coordinates of group
+  for (let node of nodes) {
+    if (!baseCoordinates.x || node.x < baseCoordinates.x) {
+      baseCoordinates.x = node.x
+    }
+    if (!baseCoordinates.y || node.y < baseCoordinates.y) {
+      baseCoordinates.y = node.y
+    }
+  }
+
+  return nodes.map(node => {
+    const relativeTransform = {
+      x: node.x - baseCoordinates.x,
+      y: node.y - baseCoordinates.y
+    }
+
+    return Object.assign({}, node, {
+      x: transform.x + relativeTransform.x,
+      y: transform.y + relativeTransform.y
+    })
+  })
+}
diff --git a/app/src/components/mixins/numbers.js b/app/src/components/mixins/numbers.js
new file mode 100644
index 0000000000000000000000000000000000000000..7438011693c50d37312a5c648a553093a58e0139
--- /dev/null
+++ b/app/src/components/mixins/numbers.js
@@ -0,0 +1,65 @@
+//////////////////////////////////////////////////////////////////////
+// Maths and Numbers
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Returns the distance between two {x,y} points
+ *
+ * @param {Node} from - Origin node
+ * @param {Node} from - Target node
+ * @return {number} Distance between points
+ *
+ *  */
+export const distance = (from, to) => Math.hypot(to.x - from.x, to.y - from.y)
+
+/**
+ * Returns an interpolated value between two numbers
+ *
+ * @param {number} from
+ * @param {number} to
+ * @param {number} extent - between 0.0 and 1.0
+ * @return {number}
+ *
+ *  */
+export const lerp = (from, to, extent) => from * (1 - extent) + to * extent
+
+/**
+ * Returns an interpolated value between two points
+ *
+ * @param {Point} from
+ * @param {Point} to
+ * @param {number} extent - between 0.0 and 1.0
+ * @return {Point}
+ *
+ *  */
+export const lerpPoint = (from, to, extent) => {
+  return {
+    x: lerp(from.x, to.x, extent),
+    x: lerp(from.y, to.y, extent)
+  }
+}
+
+/**
+ * Map a @number from one range to another
+ *
+ * @param {number} value - value to map
+ * @param {number} from1
+ * @param {number} to1
+ * @param {number} from2
+ * @param {number} to2
+ * @return {number}
+ *
+ *  */
+export const mapRange = (value, from1, to1, from2, to2) =>
+  ((value - from1) * (to2 - from2)) / (to1 - from1) + from2
+
+/**
+ * Calculates the angle between two points
+ *
+ * @param {Point} point1
+ * @param {Point} point2
+ * @return {number}
+ *
+ *  */
+export const angleBetween = (point1, point2) =>
+  Math.atan2(point2.y - point1.y, point2.x - point1.x)
diff --git a/app/src/store/index.js b/app/src/store/index.js
index 81fa567733394c3744e037da594cb5d9ed58cb34..d3a7e22739616cb538ff7fed19a07e32bc373726 100644
--- a/app/src/store/index.js
+++ b/app/src/store/index.js
@@ -110,6 +110,7 @@ const store = new Vuex.Store({
 
     SET_OTHER_NODES(state) {
       state.otherNodes = []
+
       var i
       var j
       for (i = 0; i < Object.keys(state.allNodes).length; i++) {
@@ -126,7 +127,6 @@ const store = new Vuex.Store({
               nodeid: state.allNodes[i].doc.nodes[j].nodeid,
               nodetext: state.allNodes[i].doc.nodes[j].nodetext
             }
-
             state.otherNodes.push(newNode)
           }
         }
diff --git a/app/src/views/Home.vue b/app/src/views/Home.vue
index c3b45dca63d793887b4123ec67ca27c7f8f78390..198f7d079236c6eff78f79ae3048787427dae6e1 100644
--- a/app/src/views/Home.vue
+++ b/app/src/views/Home.vue
@@ -16,7 +16,7 @@
         v-bind:nodetext="value.nodetext"
       />
 
-      <CanvasLayer />
+      <ConnectorsLayer />
 
       <ControlsLayer />
     </div>
@@ -27,7 +27,7 @@
 <script>
 // @ is an alias to /src
 import OnBoard from '@/components/OnBoard.vue'
-import CanvasLayer from '@/components/CanvasLayer.vue'
+import ConnectorsLayer from '@/components/ConnectorsLayer.vue'
 import NodesLayer from '@/components/NodesLayer.vue'
 import OtherNodeslayer from '@/components/OtherNodeslayer.vue'
 import DeBug from '@/components/DeBug.vue'
@@ -47,7 +47,7 @@ export default {
 
   components: {
     OnBoard,
-    CanvasLayer,
+    ConnectorsLayer,
     NodesLayer,
     OtherNodeslayer,
     DeBug,