diff --git a/README.md b/README.md
index 3bac1b2b363acac2be83bfd05152ccee59d557e9..a1a33084e46bc50df474c20d76902bd9979c371d 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,9 @@
 
 ## oy
 
+- planner reporting lengths that are 100 total when should be 10 
+- stepper not having individual instances of state ? 
+
 - callback-via-hookup ... steppers -> network, planner -> steppers both want this 
 - understand how callbacks work, how often used, etc, cc @ sean 
 - button / multiline / 3js UI elements / ui handling throughout ? 
diff --git a/server.js b/server.js
index db68de2e7427440047d7dfe80ab6ae7f79ecbc4f..795b9d514f5605c83f96c234e0e8c9b232832884 100644
--- a/server.js
+++ b/server.js
@@ -137,16 +137,20 @@ zm.outputs.ack.attach(planner.inputs.acks)
 
 // same motors / bridge 
 xm.state.axis = 'X'
+xm.axis = 'X'
 xm.outputs.packet.attach(bridge.inputs.A)
 bridge.outputs.A.attach(xm.inputs.packet)
 yma.state.axis = 'Y'
+yma.axis = 'Y'
 yma.outputs.packet.attach(bridge.inputs.B)
 bridge.outputs.B.attach(yma.inputs.packet)
 ymb.state.axis = 'Y'
+ymb.axis = 'Y'
 ymb.state.spu = -200
 ymb.outputs.packet.attach(bridge.inputs.C)
 bridge.outputs.C.attach(ymb.inputs.packet)
-zm.state.axis = 'Z'
+zm.state.axis = 'ZA'
+zm.axis = 'Z'
 zm.outputs.packet.attach(bridge.inputs.D)
 bridge.outputs.D.attach(zm.inputs.packet)
 
@@ -164,9 +168,13 @@ setUiPos(zm, 600, 780)
 setUiPos(bridge, 600, 980)
 
 // setting ui elements / state 
+planner.state.isRunning = 0
 term.state.uiInput = "G1 F100 X10"
 term.state.uiInput = "G1 Y10"
-term.state.uiInput = "G1 X5 Y1500"
+term.state.uiInput = "G1 X0"
+term.state.uiInput = "G1 Y0"
+planner.state.isRunning = 1
+
 /*
 term.state.uiInput = "G1 X0 Y10"
 term.state.uiInput = "G1 X-1 Y0"
diff --git a/src/hardware/stepper.js b/src/hardware/stepper.js
index 81f53e7f5d624c47c37d928b62faabe311ea2fa2..e4ca235de0201dbb0a28fe85e48775f27642ede8 100644
--- a/src/hardware/stepper.js
+++ b/src/hardware/stepper.js
@@ -6,110 +6,204 @@ let Output = InOut.Output
 let State = InOut.State
 let Button = InOut.Button
 
-const MJS = require ('mathjs')
+const MJS = require('mathjs')
+const DCRT = require('../../lib/cartesian.js')
 
 function Stepper() {
-	var stepper = {
-		description: {
-			name: 'ATK Network Stepper Driver',
-			alt: 'software representation of stepper',
-			isHardware: true 
-		}
-	}
-
-	stepper.state = State()
-	state = stepper.state 
-
-	state.axis = 'X'
-	state.spu = 200 // steps per unit 
-	state.rawMove = -10
-
-	state.makeMove = Button('test move')
-
-	state.position = 0 // in steps 
-
-	state.onChange('makeMove', function(){
-		onRawMove()
-		state.makeMove.isPressed = false
-	})
-
-	stepper.inputs = {
-		move: Input('move instruction', onNewInstruction),
-		packet: Input('headless packet', onHardwareIn)
-	}
-
-	stepper.outputs = {
-		ack: Output('move acknowledgement'),
-		q: Output('number'), // how much juice used for last move
-		packet: Output('headless packet')
-	}
-
-	function onHardwareIn(pckt){
-		console.log('packet from stepper', pckt)
-	}
-
-	function onRawMove(){
-		console.log('raw move for', state.rawMove)
-		// finds type of ramp, calculates entry and exit ramp lengths 
-		var length = Math.abs(state.rawMove)
-		var testTrapezoid = calcDiscreteMoves(state.rawMove, 10, 100, length / 2 - length/4, length / 2 + length / 4)
-		console.log(testTrapezoid)
-		/*
-		var machineTrap = calcDiscreteMoves(rawTrap)
-		var packet = makeTrapezoidPacket(machineTrap)
-		// send it 
-		stepper.outputs.packet.emit(machineTrap)
-		*/
-	}
-
-	function onNewInstruction(move){
-		console.log('move to stepper', move)
-		// pick out axis (check if it's a wait move)
-
-		// write trapezoid
-
-		// machine trapezoid 
-
-		// send and setup for ack ? 
-	}
-
-
-	function calcDiscreteMoves(delta, entry, accel, aLength, dLength){
-		// steps, entryspeed, accel, accellength, deccellength
-		var dLength = watchRounding(Math.abs(delta * state.spu))
-		var dDelta = 0
-		if(delta < 0){
-			dDelta = - dLength
-		} else {
-			dDelta = dLength
-		}
-		var dEntry = watchRounding(entry * state.spu)
-		var dAccel = watchRounding(accel * state.spu)
-		var dALength = watchRounding(aLength * state.spu)
-		var dDLength = watchRounding(dLength * state.spu)
-
-		var discreteTrap = {
-			// HERE !
-		}
-		// from float to step conversions, watching for corner (haha) cases 
-	}
-
-	function watchRounding(val){
-		var rounded = Math.round(val)
-		if(rounded < 0){
-			console.log('WATCH ZERO', val, rounded)
-		}
-		var error = Math.abs(val/rounded - 1)
-		if(error > 0.05){
-			console.log('WATCH ROUNDING', val, rounded, error)
-		}
-	}
-
-	function makeTrapezoidPacket(machineTrapezoid){
-		// make a packit
-	}
-
-	return stepper
+    var stepper = {
+        description: {
+            name: 'ATK Network Stepper Driver',
+            alt: 'software representation of stepper',
+            isHardware: true
+        }
+    }
+
+    stepper.state = State()
+    state = stepper.state
+
+    state.axis = 'X'
+    state.spu = 200 // steps per unit 
+    state.rawMove = -10
+
+    state.makeMove = Button('test move')
+
+    state.lead = 0 
+    state.position = 0 // in steps 
+
+    state.onChange('makeMove', function() {
+        onRawMove()
+        state.makeMove.isPressed = false
+    })
+
+    stepper.inputs = {
+        move: Input('move instruction', onNewInstruction),
+        packet: Input('headless packet', onHardwareIn)
+    }
+
+    stepper.outputs = {
+        ack: Output('move acknowledgement'),
+        q: Output('number'), // how much juice used for last move
+        packet: Output('headless packet')
+    }
+
+    function onHardwareIn(pckt) {
+        console.log('packet from stepper', pckt)
+    }
+
+    function onRawMove() {
+        console.log('raw move for', state.rawMove)
+        // finds type of ramp, calculates entry and exit ramp lengths 
+        var length = Math.abs(state.rawMove)
+        var testTrapezoid = calcDiscreteMoves(state.rawMove, 10, 100, length / 2 - length / 4, length / 2 + length / 4)
+        console.log(testTrapezoid)
+        /*
+        var machineTrap = calcDiscreteMoves(rawTrap)
+        var packet = makeTrapezoidPacket(machineTrap)
+        // send it 
+        stepper.outputs.packet.emit(machineTrap)
+        */
+    }
+
+    function onNewInstruction(move) {
+        console.log('move to stepper', stepper.id, state.axis, stepper.axis, stepper.state.axis)
+        // pick out axis (check if it's a wait move)
+        // like
+        /*
+        var move = {
+        	p1, p2,
+        	cruise, entry, exit,
+        	vector,
+        	type, 
+        	t1, d1, t2, d2, t3, d3
+        }
+        */
+
+        // axis values
+        var axisIndex = move.axes.indexOf(state.axis)
+        console.log('axisIndex', axisIndex, state.axis)
+        if (axisIndex == -1) {
+            console.log('STEPPER AXIS NOT FOUND IN MOVE')
+        } else {
+            // have to watch out for zero-lengths on this axis, also 
+            var delta = move.p2[axisIndex] - move.p1[axisIndex]
+            console.log('delta', delta)
+            if (delta <= 0) {
+                // find a DOF w/o zlv
+                var fnd = false
+                var altAxis = null
+                for (i in move.p1) {
+                    if (Math.abs(move.p2[i] - move.p1[i]) > 0) {
+                        altAxis = i
+                    }
+                }
+                if (altAxis != null) {
+                    var axisMove = pullAxis(move, i)
+                    axisMove.isWait = true
+                    sendToHardware(axisMove)
+                } else {
+                    console.log("ZERO LENGTH INTO STEPPER")
+                }
+            } else {
+                var axisMove = pullAxis(move, axisIndex)
+                axisMove.isWait = false
+                sendToHardware(axisMove)
+            }
+        }
+    }
+
+    function pullAxis(move, i) {
+    	// like
+        /*
+        var move = {
+        	p1, p2,
+        	cruise, entry, exit,
+        	vector,
+        	type, 
+        	t1, d1, t2, d2, t3, d3
+        }
+        */
+        /*
+        var pckt = {
+        	steps,
+        	entry, 
+        	accel,
+        	accelLen,
+        	deccelLen
+        }
+        */
+    	var delta = move.p2[i] - move.p1[i] 
+        var frLen = DCRT.length(move.vector)
+        var rel = Math.abs(delta) / frLen
+
+        console.log(delta, frLen, rel)
+
+        var entry = move.entry * rel 
+        var accel = move.accel * rel 
+        var accelLen = move.accelLen * rel 
+        var deccelLen = move.deccelLen * rel 
+
+        var aMove = {
+        	delta: delta,
+        	entry: entry,
+        	accel: accel,
+        	accelLen: accelLen,
+        	deccelLen: deccelLen
+        }
+
+        console.log('return pull', aMove)
+
+        return aMove
+    }
+
+    function sendToHardware(aMove) {
+    	// 'axis' move and discreet move
+    	var dMove = {}
+    	dMove.steps = watchRounding(aMove.delta)
+    	dMove.entry = watchRounding(aMove.entry)
+    	dMove.accel = watchRounding(aMove.accel)
+    	dMove.accelLen = Math.round(aMove.accelLen)
+    	dMove.deccelLen = Math.round(aMove.deccelLen)
+
+    	var packet = new Array() 
+    	// step blocks are #131
+    	// wait blocks are #132
+    	if(aMove.isWait){
+    		packet.push(132)
+    	} else {
+    		packet.push(131)
+    	}
+    	packet = packet.concat(pack32(dMove.steps))
+    	packet = packet.concat(pack32(dMove.entry))
+    	packet = packet.concat(pack32(dMove.accel))
+    	packet = packet.concat(pack32(dMove.accelLen))
+    	packet = packet.concat(pack32(dMove.deccelLen))
+
+    	state.lead = state.lead + dMove.steps 
+    	stepper.outputs.packet.emit(packet)
+
+    	console.log('stepper packet out', packet)
+    }
+
+    function sendToHardware(dMove){
+
+    }
+
+    function watchRounding(val) {
+        var rounded = Math.round(val)
+        if (rounded == 0 ) {
+            console.log('WATCH ZERO', val, rounded)
+        }
+        var error = Math.abs(val / rounded - 1)
+        if (error > 0.05) {
+            console.log('WATCH ROUNDING', val, rounded, error)
+        }
+    }
+
+    function makeTrapezoidPacket(machineTrapezoid) {
+        // make a packit
+    }
+
+    return stepper
 }
 
-module.exports = Stepper 
\ No newline at end of file
+module.exports = Stepper
\ No newline at end of file
diff --git a/src/motion/planner.js b/src/motion/planner.js
index 64540b9ea0f9a0e0fc82204fb1190e945b807ce6..cd4d5bf7726ec2901113aa26d51bb457cc472574 100644
--- a/src/motion/planner.js
+++ b/src/motion/planner.js
@@ -54,17 +54,17 @@ function Planner() {
     ------------------------------------------------------
     */
 
-    function onAck(msg){
+    function onAck(msg) {
         console.log("Planner onAck:", msg)
         // stepper has moved, ID to position & speed state, count for time to send new move 
     }
 
-    function axisIDUpdate(){
+    function axisIDUpdate() {
         var axes = state.axisIDs.split(',')
         var position = new Array(axes.length)
         position.fill(0)
         var packetState = new Array(axes.length)
-        for(i in axes){
+        for (i in axes) {
             position.push(0)
             packetState.push(0)
             // could do 
@@ -75,14 +75,44 @@ function Planner() {
         console.log(planner)
     }
 
-    function onPlannerReset(){
+    function onPlannerReset() {
         console.log("RESET PLANNER")
     }
 
-    function netStateRefresh(){
-        
+    function netStateRefresh() {
+        // if there are less packets on the network than our window
+        // and the planner is running
+        // send a packet 
+        if(state.isRunning){
+            var ns = state.netState 
+            var i = 0
+            while(ns[i] == ns[i+1]){
+                i ++ 
+                if(i > ns.length - 1){
+                    break 
+                }
+            }
+            if(i == ns.length - 1){
+                if(ns[i] < state.netWindow){
+                    sendMoveToNetwork()
+                }
+            }
+        }
+    }
+
+    function sendMoveToNetwork(){
+        if(mq.length > 0){
+            for(i in state.netState){
+                state.netState[i] ++ 
+            }
+            // dereference
+            var move = JSON.parse(JSON.stringify(mq.shift()))
+            console.log("MOVE FROM PLANNER", move)
+            planner.outputs.moves.emit(move)
+        } else {
+            planner.isRunning = 0
+        }
     }
-}
 
     /*
     ------------------------------------------------------
@@ -98,7 +128,7 @@ function Planner() {
         var axes = state.axisIDs.split(',')
 
         // we'll make a new move object
-        // start and end points 
+        // start and end points, and axes to track
         var p1 = []
         var p2 = new Array(axes.length)
         p2.fill(0)
@@ -125,6 +155,7 @@ function Planner() {
             console.log('planner throwing zero length vector')
         } else {
             var newMove = {
+                axes: axes,
                 p1: p1,
                 p2: p2,
                 cruise: move.speed,
@@ -220,7 +251,7 @@ function Planner() {
             console.log('TRAPEZOIDS')
             for (var i = 0; i < mq.length; i++) {
                 calcTrap(mq[i], accel, false)
-                if(moveTime(mq[i]) < 0.1){
+                if (moveTime(mq[i]) < 0.1) {
                     console.log("WARN! move time here", moveTime(mq[i]))
                 }
                 console.log(moveTime(mq[i]))