diff --git a/modules/motion/neilParser b/modules/motion/neilParser
new file mode 100644
index 0000000000000000000000000000000000000000..3b06ba2d61c9247075d0cece2c8f83ea77e8b3e2
--- /dev/null
+++ b/modules/motion/neilParser
@@ -0,0 +1,209 @@
+//
+// gets lines of neil's paths, turns into instructions for mods-machines
+//
+// Neil Gershenfeld and Jake Read
+// (c) Massachusetts Institute of Technology 2018
+// 
+// This work may be reproduced, modified, distributed, performed, and 
+// displayed for any purpose, but must acknowledge the mods
+// project. Copyright is retained and must be preserved. The work is 
+// provided as is; no warranty is provided, and users accept all 
+// liability.
+
+/*
+turns lines of text into objects for machine controller 
+*/
+
+//
+// closure
+//
+(function() {
+    //
+    // module globals
+    //
+    var mod = {}
+    //
+    // name
+    //
+    var name = 'neil parser'
+    //
+    // initialization
+    //
+    var init = function() {
+        mod.g0SpeedIn.value = '100'
+        mod.g1SpeedIn.value = '400'
+        mod.codeMode.value = 'G0'
+    }
+    //
+    // inputs
+    //
+    var inputs = {
+        gcode: {
+            type: 'string',
+            label: 'gcode',
+            event: function(evt) {
+                parseGCode(evt.detail)
+            }
+        }
+    }
+    //
+    // outputs
+    //
+    var outputs = {
+        instruction: {
+            type: 'object',
+            label: 'instruction',
+            event: function(obj) {
+                mods.output(mod, 'instruction', obj)
+            }
+        }
+    }
+    //
+    // interface
+    //
+    var interface = function(div) {
+        mod.div = div
+        //
+        // inputs
+        //
+        // we're going to convert all of these DPIs to MMs because we live in the real world now
+        mod.g0SpeedIn = make_text_input(div, 'G0 speed, gcode units', 12)
+        mod.g1SpeedIn = make_text_input(div, 'G1 speed, gcode units', 12)
+        mod.codeMode = make_text_input(div, 'Modality', 12)
+    }
+
+    function parseGCode(str) {
+        // get letter-value pairs
+        var keyvals = getKeyValues(str)
+        // do modality
+        // check this for no-g moves?
+        if (keyvals.G == 0 | keyvals.G == 1) {
+            mod.codeMode.value = 'G' + keyvals.G.toString()
+        } else if (keyvals.M != null) {
+            mod.codeMode.value = 'M' + keyvals.M.toString()
+        }
+        // do parse and object 
+        if (mod.codeMode.value == 'G0' | mod.codeMode.value == 'G1') {
+
+            var output = {
+                type: 'move',
+                position: {},
+                speed: 0
+            }
+            // loop to find position vals, check for feed update
+            for (key in keyvals) {
+                if (key.match('[A-CX-Z]')) {
+                    output.position[key] = keyvals[key]
+                } else if (key.match('[F]')){
+                    if(mod.codeMode.value == 'G0'){
+                        // assert minimum speed 
+                        mod.g0SpeedIn.value = Math.max(10, keyvals.F)
+                    } else {
+                        mod.g1SpeedIn.value = Math.max(10, keyvals.F)
+                    }
+                }
+            }
+
+            if(mod.codeMode.value == 'G0'){
+                output.speed = parseFloat(mod.g0SpeedIn.value)
+            } else {
+                output.speed = parseFloat(mod.g1SpeedIn.value)
+            }
+
+            outputs.instruction.event(output)
+        } else if (mod.codeMode.value == 'M3'){
+            var output = {
+                type: 'spindle',
+                speed: 0
+            }
+            if(keyvals.S != null){
+                output.speed = keyvals.S
+                outputs.instruction.event(output)
+            } else {
+                console.log('need S parameter on spindle instruction')
+            }
+        } else if (mod.codeMode.value == 'M5'){
+            var output = {
+                type: 'spindle',
+                speed: 0
+            }
+            output.instruction.event(output)
+        } else {
+            console.log('gcode instruction not recognized')
+        }
+    }
+
+    function getKeyValues(str) {
+        var kv = {}
+        for (var i = 0; i < str.length; i++) {
+            if (str[i].match('[A-Za-z]')) { // regex to match upper case letters
+                var lastIndex = str.indexOf(' ', i)
+                if (lastIndex < 0) {
+                    lastIndex = str.length
+                }
+                var key = str[i].toUpperCase()
+                kv[key] = parseFloat(str.slice(i + 1, lastIndex))
+            }
+        }
+        return kv
+    }
+
+
+    /*
+    UI helpers
+    */
+    function make_text_input(div, name, size) {
+        div.appendChild(document.createElement('br'))
+        div.appendChild(document.createTextNode(name + ': '))
+        var input = document.createElement('input')
+        input.type = 'text'
+        input.size = size
+        div.appendChild(input)
+
+        return input
+    }
+
+    function make_button_input(div, text) {
+        div.appendChild(document.createElement('br'))
+        var button = document.createElement('button')
+        button.style.padding = mods.ui.padding
+        button.style.margin = 1
+        button.appendChild(document.createTextNode(text))
+        div.appendChild(button)
+
+        return button
+    }
+
+    function make_checkbox_input(div, prefix) {
+        div.appendChild(document.createElement('br'))
+        div.appendChild(document.createTextNode(prefix + ': '))
+        var checkbox = document.createElement('input')
+        checkbox.type = 'checkbox'
+        div.appendChild(checkbox)
+
+        return checkbox
+    }
+
+    function make_text_display(div, prefix) {
+        div.appendChild(document.createElement('br'))
+        div.appendChild(document.createTextNode(prefix + ': '))
+        var span = document.createElement('span')
+        span.innerHTML = ''
+        div.appendChild(span)
+
+        return span
+    }
+
+
+    //
+    // return values
+    //
+    return ({
+        mod: mod,
+        name: name,
+        init: init,
+        inputs: inputs,
+        outputs: outputs,
+        interface: interface
+    })
+}())
\ No newline at end of file
diff --git a/modules/motion/planner b/modules/motion/planner
index 906343652ab9c0e7f01c150e8bb3865cba0451ad..891da8dee2351d98d7584bcf0cda5714d7f7a42f 100644
--- a/modules/motion/planner
+++ b/modules/motion/planner
@@ -50,7 +50,7 @@ motors
         mod.junctionDeviationIn.value = '1'
         mod.minSpeedIn.value = '4'
 
-        mod.axisIdentifiers.value = 'X,Y,Z'
+        mod.axisIdentifiers.value = 'X,Y'
         resetNetwork()
 
         mod.netWindowIn.value = '12'
@@ -197,6 +197,10 @@ motors
         // see windowed state and push more data out if need be
         // TODO here
         var ok = false
+        if(axisNetCounters[0] == axisNetCounters[1]){
+            ok = true
+        }
+        /*
         for(var i = 0; i < axisNetCounters.length - 2; i ++){
             if(axisNetCounters[i] == axisNetCounters[i + 1]){
                 ok = true
@@ -204,6 +208,7 @@ motors
                 ok = false
             }
         }
+        */
         if(ok){
             var opening = packetWindowSize - axisNetCounters[0]
             if(opening > moveQue.length){