diff --git a/README.md b/README.md
index 6f8389ef5850ac897cb27c7ce9b0ba5b9841d061..98ce70b9f1486de052b70671b735406c3be8cac5 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ It's in the early stages, so bear with us. Everything is going to be great.
 
 To Run DMC, you'll need to install node.js, and then the packages serialport and ws (websocket).
 
+
+
 ### Install Node.js
 
 Node.js is a runtime environment for javascript, so you can write and run js locally. [Download and install it here](https://nodejs.org/en/download/). 
@@ -110,9 +112,15 @@ Herein will contain a list of known problems / common errors and their fixes.
 
 ## For MW
 
+ - bug hunting
+  - dereferenced events / stepper axis vector 
+  - multiple button calls ... 
+  - stepper / planner bug 
+  - is load / save really consistent ? what is the state answer ? 
+
 - title is still 'xperiment'
-- do hw if you can, and gifs / demo at the same time?
-- some example program 
+- stepper move.vector is a ref issue? derefed before running calcTrap() ? runs ? in planner ? 
+
 - example modules 
 
 - add reset button to hardware
diff --git a/client/client.js b/client/client.js
index e5e341691daae3d0b25775a633268edb02462896..7932d809f54b68abc7d5d793e153d1632f191b00 100644
--- a/client/client.js
+++ b/client/client.js
@@ -342,7 +342,7 @@ function redrawLinks() {
         if (mdlRep.description.isHardware && !mdlRep.description.isLink) {
             nLnk++
             var hwPt = getRightWall(mdlRep.ui.domElem)
-            lnkPt.y += 10 * nLnk
+            lnkPt.y += 5 * nLnk
             var ln = newLine(hwPt.x, hwPt.y, lnkPt.x, lnkPt.y)
         }
     }
diff --git a/client/divtools.js b/client/divtools.js
index a931512c0fbacf137bc9361a15fd6699430d6289..ba16c0124a28e79f60f84afd00b37f26a88b427f 100644
--- a/client/divtools.js
+++ b/client/divtools.js
@@ -301,9 +301,10 @@ function getInputArrow(div) {
 function newLine(x1, y1, x2, y2) {
     var ln = {}
     ln.elem = document.createElementNS(svgns, 'line')
-    ln.elem.style.stroke = '#fcd17b'
+    ln.elem.style.stroke = '#1a1a1a'
+    ln.elem.setAttribute('stroke-dasharray', '21, 7, 7, 7')
     ln.elem.style.fill = 'none'
-    ln.elem.style.strokeWidth = '7px'
+    ln.elem.style.strokeWidth = '6px'
     ln.x1 = x1
     ln.y1 = y1
     ln.x2 = x2
diff --git a/client/index.html b/client/index.html
index 5008fd782a7e5fbf20d24a38693b0c0207023404..7ee3bec947104854f142bac4974b661b053b5088 100644
--- a/client/index.html
+++ b/client/index.html
@@ -2,7 +2,7 @@
 <html>
 
 <head>
-    <title>xperiment</title>
+    <title>RuNDMC</title>
 </head>
 
 <body>
diff --git a/lib/atkunit.js b/lib/atkunit.js
index 72c02ad297921df560a235777d041779fb836d30..08e7f125eda5a376f04f873d3bd2324d8a40b31b 100644
--- a/lib/atkunit.js
+++ b/lib/atkunit.js
@@ -7,7 +7,7 @@ let Output = InOut.Output
 let State = InOut.State
 let Button = InOut.Button
 
-const ATKRoute = require('./atkroute.js')
+let ATKRoute = require('./atkroute.js')
 
 function Hardware(){
 	var hardware = {
diff --git a/main.js b/main.js
index 8570552f4bd53221e334070ed808c07c23b9d747..4bf43423ea9d2c16f432bd3a3d4e576c2ec4a7d5 100644
--- a/main.js
+++ b/main.js
@@ -29,7 +29,7 @@ const Programs = require('./programs.js')
 
 var program = Programs.new('new program')
 
-var step = Programs.loadModuleFromSource(program, './modules/hardware/atkstepper.js')
+// var step = Programs.loadModuleFromSource(program, './modules/hardware/atkstepper.js')
 
 // UI 
 const View = require('./views.js')
diff --git a/modules/hardware/atkseriallink.js b/modules/hardware/atkseriallink.js
index 4655d356a5599f0949042b11611ef73e9fbd394b..207dc8635ac0d77a47ce4192d0017f5c43880e1b 100644
--- a/modules/hardware/atkseriallink.js
+++ b/modules/hardware/atkseriallink.js
@@ -19,8 +19,8 @@ function ATKSerialLink() {
         routes: new Array()
     }
 
-    var state = State()
-    atkSerialLink.state = state
+    atkSerialLink.state = State()
+    var state = atkSerialLink.state 
 
     state.portName = '---'
     state.connect = Button('click to find and connect', findSerialPort)
@@ -61,7 +61,7 @@ function ATKSerialLink() {
             })
         })
         if(!found){
-            console.log('no CP2102 device found, try serialport-list to make sure it is available to the system')
+            console.log('LINK ERR: no CP2102 device found, try serialport-list to make sure it is available to the system')
             state.portStatus = 'no CP2102 device found'
         }
     }
@@ -110,7 +110,7 @@ function ATKSerialLink() {
                 if (writeToSerialPort(pckt)) {
                     console.log('PCKT OOT >>', pckt.toString())
                 } else {
-                    console.log('ERR: attempt to send to hardware, port not writable')
+                    console.log('LINK ERR: attempt to send to hardware, port not writable')
                 }
             }
         } else {
diff --git a/modules/parsing/gcode.js b/modules/parsing/gcode.js
index e848509063647d31b41bd2f53bacebd3ae008584..ae2ecb824e1847b9d848b92e11e4f08b04884392 100644
--- a/modules/parsing/gcode.js
+++ b/modules/parsing/gcode.js
@@ -36,8 +36,8 @@ function Gcode() {
             console.log('GCODE:', instruction)
             gcode.outputs.instructionOut.emit(instruction)
         } else {
-            console.log('GCODE:', gcode.ui.mode)
-            gcode.outputs.modeChange.emit(gcode.ui.mode)
+            console.log('GCODE:', gcode.state.mode)
+            gcode.outputs.modeChange.emit(gcode.state.mode)
         }
     }
 
diff --git a/modules/ui/button.js b/modules/ui/button.js
index 48c7b6a3cf3386e7e49e79e06c13a14a97dd62c0..d8435aa67b7f57e49eec959f99d81851e199c6d9 100644
--- a/modules/ui/button.js
+++ b/modules/ui/button.js
@@ -11,7 +11,7 @@ function uiButton() {
     var button = {
         // descriptions are used in UI
         description: {
-            name: 'Button!',
+            name: 'Button',
             alt: 'for clicking'
         }
     }
@@ -20,8 +20,7 @@ function uiButton() {
     // alias !
     var state = button.state 
 
-    state.button = Button('WHAM')
-    state.onChange('button', onButtonPress)
+    state.button = Button('WHAM', onButtonPress)
 
     button.inputs = {
         thru: Input('any', onButtonPress) // makes anything into '1' event
diff --git a/modules/ui/number.js b/modules/ui/number.js
index 8e827e890f01c8e648c9bf267f3f475c70f20520..467d231b46c06e9819b18978543152bde87bbffa 100644
--- a/modules/ui/number.js
+++ b/modules/ui/number.js
@@ -11,7 +11,7 @@ function uiNum() {
     var uinum = {
         // descriptions are used in UI
         description: {
-            name: 'number output!',
+            name: 'number output',
             alt: 'for clicking'
         }
     }
diff --git a/package.json b/package.json
index 8501b57d350e1ca4b560ea2cf4eeff4861229f32..5b90e9f126ae24c4d6121eee32bf521f9a7e09a3 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
   "dependencies": {
     "express": "^4.16.3",
     "http": "0.0.0",
-    "mathjs": "^5.1.2",
+    "mathjs": "^5.2.3",
     "node-webcam": "^0.4.5",
     "readline": "^1.3.0",
     "serialport": "^6.2.2",
diff --git a/programs.js b/programs.js
index 35c238f1c23854cff1edf518d1882f682f908fea..8f0f80d95eebc815b55beff1ad659678b59889c6 100644
--- a/programs.js
+++ b/programs.js
@@ -30,7 +30,7 @@ function loadModuleFromSource(program, path, id) {
             program.description.counter++
         }
 
-        // make unique name 
+        // make unique name, or recall from program save 
         if (id) {
             mod.description.id = id
         } else {
@@ -38,22 +38,22 @@ function loadModuleFromSource(program, path, id) {
         }
         mod.description.path = path
 
+        // add to program object 
+        program.modules[mod.description.id] = mod
+
         /* ---------------------------------- */
         // WARN! Corner Case should Go Away or Improve at next spiral 
-        if(mod.description.isLink){
+        if (mod.description.isLink) {
             for (mdlName in program.modules) {
                 if (program.modules[mdlName].description.isLink) {
                     console.log("PRGMEM ONLY BIG ENOUGH FOR ONE LINK")
-                    process.exit()
+                    //process.exit()
                 }
             }
         }
         // end corner case code 
         /* ---------------------------------- */
 
-        // add to program object 
-        program.modules[mod.description.id] = mod
-
         // input need references for later hookup
         for (key in mod.inputs) {
             mod.inputs[key].parentId = mod.description.id
@@ -89,9 +89,9 @@ function loadModuleFromSource(program, path, id) {
         // here's what we'll do
         // if it's hardware, and we're not loading from some saved program (no id)
         // 
-        if (mod.description.isHardware && !mod.description.isLink && id == null) {
+        if (mod.description.isHardware && !mod.description.isLink /* && id == null */ ) {
             // make sure we haven't already done this, thx 
-            var lnk = null 
+            var lnk = null
             for (mdlName in program.modules) {
                 if (program.modules[mdlName].description.isLink) {
                     lnk = mdlName
@@ -120,7 +120,7 @@ function writeStateObject(mod, key) {
         set: function(x) {
             // update internal value 
             this['_' + key] = x
-            //console.log('SET', key, this['_' + key])
+            // console.log('SET', key, this['_' + key])
             // push to internal state change handler
             // let's call emitChange from the server-side ...
             // so that we don't get into any heavy VIR
@@ -229,7 +229,7 @@ function openProgram(path) {
         var mdl = program.modules[modName]
 
         if (mdl == null) {
-            console.log('NULL')
+            console.log('-------------------------------- NULL MDL at openProgram')
             console.log('prgRep modules', prgRep.modules)
             console.log('program modules', program.modules)
         }
@@ -249,17 +249,30 @@ function openProgram(path) {
         }
 
         // restoring state 
-        for (key in mdlRep.state) {
-            if (isStateKey(key)) {
-                // I think this is OK?
-                // would prefer to do this before we write getters and setters
-                // for now we walk-around to secret key ... 
-                mdl.state['_' + key] = mdlRep.state[key]
+        /* the first wrap, only here to prevent link not-reconnecting on program restart, should go away */
+        if (!mdlRep.description.isLink) {
+            for (key in mdlRep.state) {
+                if (isStateKey(key)) {
+                    // I think this is OK?
+                    // would prefer to do this before we write getters and setters
+                    // for now we walk-around to secret key ... 
+                    if (mdl.state[key].type == 'button' || mdl.state[key].type == 'multiline') {
+                        // defaul vals
+                    } else if (key == 'route'){
+                        // absolutely does not belong here 
+                        // TODO: states: sometimes we load, we want to run the change emitter ... sometimes we don't
+                        // what choice ? 
+                        mdl.state['_' + key] = mdlRep.state[key]
+                        mdl.state.emitChange('route')
+                    } else {
+                        mdl.state['_' + key] = mdlRep.state[key]
+                    }
+                }
             }
         }
 
-        console.log('mdlRep', mdlRep)
-        console.log('mdl', mdl)
+        //console.log('mdlRep', mdlRep)
+        //console.log('mdl', mdl)
         // restore position / UI state
         if (mdlRep.description.position != null) {
             // ??
diff --git a/programs/hwtest-2.json b/programs/hwtest-2.json
new file mode 100644
index 0000000000000000000000000000000000000000..0886e2e9e729ad22dea64f8170564f4353d96bb3
--- /dev/null
+++ b/programs/hwtest-2.json
@@ -0,0 +1,573 @@
+{
+  "description": {
+    "name": "new program",
+    "counter": 12
+  },
+  "modules": {
+    "Serialport ATK Link-1": {
+      "description": {
+        "id": "Serialport ATK Link-1",
+        "name": "Serialport ATK Link",
+        "alt": "window into hardware world",
+        "path": "./modules/hardware/atkseriallink.js",
+        "isHardware": true,
+        "isLink": true,
+        "position": {
+          "left": 968,
+          "top": 347
+        }
+      },
+      "inputs": {},
+      "outputs": {},
+      "state": {
+        "portName": "COM10",
+        "connect": {
+          "type": "button",
+          "label": "click to find and connect"
+        },
+        "portStatus": "open"
+      }
+    },
+    "ATKStepper-0": {
+      "description": {
+        "id": "ATKStepper-0",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,3",
+        "rate": 2000,
+        "axis": "X",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-2": {
+      "description": {
+        "id": "ATKStepper-2",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 456,
+          "top": 491
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,0",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": -200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-3": {
+      "description": {
+        "id": "ATKStepper-3",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 883
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,5",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-4": {
+      "description": {
+        "id": "ATKStepper-4",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 459,
+          "top": 1274
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test packet out",
+        "route": "0,1",
+        "rate": 2000,
+        "axis": "Z",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": -2000,
+        "position": 0
+      }
+    },
+    "ATKBBB-Servo-5": {
+      "description": {
+        "id": "ATKBBB-Servo-5",
+        "name": "ATKBBB-Servo",
+        "alt": "software representation of networked hardware object",
+        "path": "./modules/hardware/atkbreadboard.js",
+        "isHardware": true,
+        "position": {
+          "left": 891,
+          "top": 1354
+        }
+      },
+      "inputs": {
+        "servoVal": {
+          "accepts": "number"
+        },
+        "adcRequest": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "servoConf": {
+          "emits": "event",
+          "calls": []
+        },
+        "adcValue": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,2",
+        "servoButton": {
+          "type": "button",
+          "label": "SEND VALUE"
+        },
+        "servoVal": 0,
+        "adcButton": {
+          "type": "button",
+          "label": "REQUEST ADC CONVERSION"
+        }
+      }
+    },
+    "Button-7": {
+      "description": {
+        "id": "Button-7",
+        "name": "Button",
+        "alt": "for clicking",
+        "path": "./modules/ui/button.js",
+        "position": {
+          "left": -544,
+          "top": 337
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "whammy": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "delay-9",
+              "key": "thru"
+            },
+            {
+              "parentId": "number output-8",
+              "key": "evt"
+            }
+          ]
+        }
+      },
+      "state": {
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "number output-8": {
+      "description": {
+        "id": "number output-8",
+        "name": "number output",
+        "alt": "for clicking",
+        "path": "./modules/ui/number.js",
+        "position": {
+          "left": -545,
+          "top": 605
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        },
+        "evt": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "Multi-line Text Input-12",
+              "key": "req"
+            }
+          ]
+        }
+      },
+      "state": {
+        "number": 10,
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "delay-9": {
+      "description": {
+        "id": "delay-9",
+        "name": "delay",
+        "alt": "in ... out",
+        "path": "./modules/util/delay.js",
+        "position": {
+          "left": -546,
+          "top": 499
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "any",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "run"
+            }
+          ]
+        }
+      },
+      "state": {
+        "ms": 100
+      }
+    },
+    "Lookahead-Motion-Planner-10": {
+      "description": {
+        "id": "Lookahead-Motion-Planner-10",
+        "name": "Lookahead-Motion-Planner",
+        "alt": "movements -> acceleration planned moves",
+        "path": "./modules/motion/planner.js",
+        "position": {
+          "left": -31,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "instruction": {
+          "accepts": "move instruction"
+        },
+        "acks": {
+          "accepts": "move acknowledgement"
+        },
+        "run": {
+          "accepts": "boolean"
+        }
+      },
+      "outputs": {
+        "moves": {
+          "emits": "move instruction",
+          "calls": []
+        },
+        "moveComplete": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "axisIDs": "X,Y,Z",
+        "reset": {
+          "type": "button",
+          "label": "reset planner"
+        },
+        "accel": 200,
+        "jd": 0.1,
+        "minSpeed": 1,
+        "startStop": {
+          "type": "button",
+          "label": "start / stop planner"
+        },
+        "position": [
+          0,
+          0,
+          0
+        ],
+        "isRunning": 1,
+        "netWindow": 3,
+        "netState": [
+          0,
+          0,
+          0
+        ]
+      }
+    },
+    "Gcode Parser-11": {
+      "description": {
+        "id": "Gcode Parser-11",
+        "name": "Gcode Parser",
+        "alt": "line of gcode -> planner recognized move",
+        "path": "./modules/parsing/gcode.js",
+        "position": {
+          "left": -556,
+          "top": 83
+        }
+      },
+      "inputs": {
+        "lineIn": {
+          "accepts": "string"
+        }
+      },
+      "outputs": {
+        "instructionOut": {
+          "emits": "move instruction",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "instruction"
+            }
+          ]
+        },
+        "modeChange": {
+          "emits": "string",
+          "calls": []
+        }
+      },
+      "state": {
+        "mode": "G0",
+        "G0": 1200,
+        "G1": 400
+      }
+    },
+    "Multi-line Text Input-12": {
+      "description": {
+        "id": "Multi-line Text Input-12",
+        "name": "Multi-line Text Input",
+        "alt": "sequential txt input",
+        "path": "./modules/ui/multiline.js",
+        "position": {
+          "left": -1117,
+          "top": 89
+        }
+      },
+      "inputs": {
+        "req": {
+          "accepts": "number"
+        },
+        "lineIn": {
+          "accepts": "string"
+        },
+        "load": {
+          "accepts": "path"
+        }
+      },
+      "outputs": {
+        "lineOut": {
+          "emits": "string",
+          "calls": [
+            {
+              "parentId": "Gcode Parser-11",
+              "key": "lineIn"
+            }
+          ]
+        }
+      },
+      "state": {
+        "load": {
+          "type": "button",
+          "label": "LOAD"
+        },
+        "thru": {
+          "type": "button",
+          "label": "WHAM"
+        },
+        "previously": {
+          "type": "multiline",
+          "label": "lines complete",
+          "rows": 11,
+          "value": ""
+        },
+        "now": {
+          "type": "multiline",
+          "label": "line just out",
+          "rows": 1,
+          "value": ""
+        },
+        "incoming": {
+          "type": "multiline",
+          "label": "future lines",
+          "rows": 36,
+          "value": "G0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\n"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/programs/hwtest.json b/programs/hwtest.json
new file mode 100644
index 0000000000000000000000000000000000000000..7ccaf4585f38072155c163e291893a917e34b999
--- /dev/null
+++ b/programs/hwtest.json
@@ -0,0 +1,308 @@
+{
+  "description": {
+    "name": "new program",
+    "counter": 5
+  },
+  "modules": {
+    "Serialport ATK Link-1": {
+      "description": {
+        "id": "Serialport ATK Link-1",
+        "name": "Serialport ATK Link",
+        "alt": "window into hardware world",
+        "path": "./modules/hardware/atkseriallink.js",
+        "isHardware": true,
+        "isLink": true,
+        "position": {
+          "left": 968,
+          "top": 347
+        }
+      },
+      "inputs": {},
+      "outputs": {},
+      "state": {
+        "portName": "COM10",
+        "connect": {
+          "type": "button",
+          "label": "click to find and connect"
+        },
+        "portStatus": "open"
+      }
+    },
+    "ATKStepper-0": {
+      "description": {
+        "id": "ATKStepper-0",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,3",
+        "rate": 2000,
+        "axis": "X",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-2": {
+      "description": {
+        "id": "ATKStepper-2",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 456,
+          "top": 491
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,0",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": -200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-3": {
+      "description": {
+        "id": "ATKStepper-3",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 883
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,5",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-4": {
+      "description": {
+        "id": "ATKStepper-4",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 459,
+          "top": 1274
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test packet out",
+        "route": "0,1",
+        "rate": 2000,
+        "axis": "Z",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": -2000,
+        "position": 0
+      }
+    },
+    "ATKBBB-Servo-5": {
+      "description": {
+        "id": "ATKBBB-Servo-5",
+        "name": "ATKBBB-Servo",
+        "alt": "software representation of networked hardware object",
+        "path": "./modules/hardware/atkbreadboard.js",
+        "isHardware": true,
+        "position": {
+          "left": 891,
+          "top": 1354
+        }
+      },
+      "inputs": {
+        "servoVal": {
+          "accepts": "number"
+        },
+        "adcRequest": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "servoConf": {
+          "emits": "event",
+          "calls": []
+        },
+        "adcValue": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,2",
+        "servoButton": {
+          "type": "button",
+          "label": "SEND VALUE"
+        },
+        "servoVal": 0,
+        "adcButton": {
+          "type": "button",
+          "label": "REQUEST ADC CONVERSION"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/programs/hwtst-3.json b/programs/hwtst-3.json
new file mode 100644
index 0000000000000000000000000000000000000000..d0adf2ac1294dc6e1e9f6825bc1744647535f88d
--- /dev/null
+++ b/programs/hwtst-3.json
@@ -0,0 +1,590 @@
+{
+  "description": {
+    "name": "new program",
+    "counter": 12
+  },
+  "modules": {
+    "Serialport ATK Link-1": {
+      "description": {
+        "id": "Serialport ATK Link-1",
+        "name": "Serialport ATK Link",
+        "alt": "window into hardware world",
+        "path": "./modules/hardware/atkseriallink.js",
+        "isHardware": true,
+        "isLink": true,
+        "position": {
+          "left": 968,
+          "top": 347
+        }
+      },
+      "inputs": {},
+      "outputs": {},
+      "state": {
+        "portName": "COM10",
+        "connect": {
+          "type": "button",
+          "label": "click to find and connect"
+        },
+        "portStatus": "open"
+      }
+    },
+    "ATKStepper-0": {
+      "description": {
+        "id": "ATKStepper-0",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,3",
+        "rate": 2000,
+        "axis": "X",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-2": {
+      "description": {
+        "id": "ATKStepper-2",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 456,
+          "top": 491
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,0",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": -200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-3": {
+      "description": {
+        "id": "ATKStepper-3",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 883
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,5",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-4": {
+      "description": {
+        "id": "ATKStepper-4",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 459,
+          "top": 1274
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test packet out",
+        "route": "0,1",
+        "rate": 2000,
+        "axis": "Z",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": -2000,
+        "position": 0
+      }
+    },
+    "ATKBBB-Servo-5": {
+      "description": {
+        "id": "ATKBBB-Servo-5",
+        "name": "ATKBBB-Servo",
+        "alt": "software representation of networked hardware object",
+        "path": "./modules/hardware/atkbreadboard.js",
+        "isHardware": true,
+        "position": {
+          "left": 891,
+          "top": 1354
+        }
+      },
+      "inputs": {
+        "servoVal": {
+          "accepts": "number"
+        },
+        "adcRequest": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "servoConf": {
+          "emits": "event",
+          "calls": []
+        },
+        "adcValue": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,2",
+        "servoButton": {
+          "type": "button",
+          "label": "SEND VALUE"
+        },
+        "servoVal": 0,
+        "adcButton": {
+          "type": "button",
+          "label": "REQUEST ADC CONVERSION"
+        }
+      }
+    },
+    "Button-7": {
+      "description": {
+        "id": "Button-7",
+        "name": "Button",
+        "alt": "for clicking",
+        "path": "./modules/ui/button.js",
+        "position": {
+          "left": -544,
+          "top": 337
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "whammy": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "delay-9",
+              "key": "thru"
+            },
+            {
+              "parentId": "number output-8",
+              "key": "evt"
+            }
+          ]
+        }
+      },
+      "state": {
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "number output-8": {
+      "description": {
+        "id": "number output-8",
+        "name": "number output",
+        "alt": "for clicking",
+        "path": "./modules/ui/number.js",
+        "position": {
+          "left": -545,
+          "top": 605
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        },
+        "evt": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "Multi-line Text Input-12",
+              "key": "req"
+            }
+          ]
+        }
+      },
+      "state": {
+        "number": 10,
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "delay-9": {
+      "description": {
+        "id": "delay-9",
+        "name": "delay",
+        "alt": "in ... out",
+        "path": "./modules/util/delay.js",
+        "position": {
+          "left": -546,
+          "top": 499
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "any",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "run"
+            }
+          ]
+        }
+      },
+      "state": {
+        "ms": 100
+      }
+    },
+    "Lookahead-Motion-Planner-10": {
+      "description": {
+        "id": "Lookahead-Motion-Planner-10",
+        "name": "Lookahead-Motion-Planner",
+        "alt": "movements -> acceleration planned moves",
+        "path": "./modules/motion/planner.js",
+        "position": {
+          "left": -31,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "instruction": {
+          "accepts": "move instruction"
+        },
+        "acks": {
+          "accepts": "move acknowledgement"
+        },
+        "run": {
+          "accepts": "boolean"
+        }
+      },
+      "outputs": {
+        "moves": {
+          "emits": "move instruction",
+          "calls": [
+            {
+              "parentId": "ATKStepper-0",
+              "key": "trapezoid"
+            },
+            {
+              "parentId": "ATKStepper-2",
+              "key": "trapezoid"
+            },
+            {
+              "parentId": "ATKStepper-3",
+              "key": "trapezoid"
+            },
+            {
+              "parentId": "ATKStepper-4",
+              "key": "trapezoid"
+            }
+          ]
+        },
+        "moveComplete": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "axisIDs": "X,Y,Z",
+        "reset": {
+          "type": "button",
+          "label": "reset planner"
+        },
+        "accel": 200,
+        "jd": 0.1,
+        "minSpeed": 1,
+        "startStop": {
+          "type": "button",
+          "label": "start / stop planner"
+        },
+        "position": [
+          0,
+          0,
+          0
+        ],
+        "isRunning": 1,
+        "netWindow": 3,
+        "netState": [
+          0,
+          0,
+          0
+        ]
+      }
+    },
+    "Gcode Parser-11": {
+      "description": {
+        "id": "Gcode Parser-11",
+        "name": "Gcode Parser",
+        "alt": "line of gcode -> planner recognized move",
+        "path": "./modules/parsing/gcode.js",
+        "position": {
+          "left": -556,
+          "top": 83
+        }
+      },
+      "inputs": {
+        "lineIn": {
+          "accepts": "string"
+        }
+      },
+      "outputs": {
+        "instructionOut": {
+          "emits": "move instruction",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "instruction"
+            }
+          ]
+        },
+        "modeChange": {
+          "emits": "string",
+          "calls": []
+        }
+      },
+      "state": {
+        "mode": "G0",
+        "G0": 1200,
+        "G1": 400
+      }
+    },
+    "Multi-line Text Input-12": {
+      "description": {
+        "id": "Multi-line Text Input-12",
+        "name": "Multi-line Text Input",
+        "alt": "sequential txt input",
+        "path": "./modules/ui/multiline.js",
+        "position": {
+          "left": -1117,
+          "top": 89
+        }
+      },
+      "inputs": {
+        "req": {
+          "accepts": "number"
+        },
+        "lineIn": {
+          "accepts": "string"
+        },
+        "load": {
+          "accepts": "path"
+        }
+      },
+      "outputs": {
+        "lineOut": {
+          "emits": "string",
+          "calls": [
+            {
+              "parentId": "Gcode Parser-11",
+              "key": "lineIn"
+            }
+          ]
+        }
+      },
+      "state": {
+        "load": {
+          "type": "button",
+          "label": "LOAD"
+        },
+        "thru": {
+          "type": "button",
+          "label": "WHAM"
+        },
+        "previously": {
+          "type": "multiline",
+          "label": "lines complete",
+          "rows": 11,
+          "value": ""
+        },
+        "now": {
+          "type": "multiline",
+          "label": "line just out",
+          "rows": 1,
+          "value": ""
+        },
+        "incoming": {
+          "type": "multiline",
+          "label": "future lines",
+          "rows": 36,
+          "value": "G0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\n"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/views.js b/views.js
index ff9d5af039e1efadf49626d074596dca526fe2d0..474197918071747b0a1b289bbf8cf0bd3275c0f5 100644
--- a/views.js
+++ b/views.js
@@ -246,7 +246,7 @@ function uiRequestStateChange(data) {
 
     if (mdlState[data.key]) {
         switch (mdlState[data.key].type) {
-            case 'button':
+            case 'button': 
                 mdlState[data.key].onClick()
                 break
             case 'multiline':