diff --git a/js/cam/Cam.js b/js/cam/Cam.js
index 61c422aae4cabd61b4c3de1f35096b583aa16fc2..8ee2ac19fc970feee0c2cdde8e825d544b0ebd1a 100644
--- a/js/cam/Cam.js
+++ b/js/cam/Cam.js
@@ -324,20 +324,7 @@ define(['underscore', 'three', 'backbone', 'appState', 'latticeCAM', 'threeModel
 
             var self = this;
             this._getExporter(function(exporter){
-                var data = "";
-                data += exporter.makeHeader(scaledSettings);
-                data += "\n\n";
-                data += exporter.addComment("begin program");
-                data += "\n";
-
-                data += self.get("assembler").postProcess(scaledSettings, exporter);
-
-                data += "\n\n";
-                data += exporter.addComment("end program");
-                data += "\n";
-                data += exporter.makeFooter(scaledSettings);
-
-                self.set("dataOut", data);
+                self.set("dataOut", self.get("assembler").postProcess(scaledSettings, exporter));
                 self.set("editsMadeToProgram", false);
                 self.set("exporter", exporter);
                 if (!appState.get("stockSimulationPlaying")) self.resetSimulation();
diff --git a/js/cam/assemblers/Assembler.js b/js/cam/assemblers/Assembler.js
index cf41d039ac5298ade2bc86c1c96785df6996ffd5..78dbf6ccb8bf0e21b792985bf46b950c269f766d 100644
--- a/js/cam/assemblers/Assembler.js
+++ b/js/cam/assemblers/Assembler.js
@@ -23,7 +23,6 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
         this.object3D = new THREE.Object3D();
         three.sceneAdd(this.object3D);
 
-
         var componentsJSON = json.components;
         this.components = this._buildAssemblerComponents(componentsJSON);
         this._loadSTLs(json, this.components);
@@ -99,11 +98,6 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
         });
     };
 
-
-
-    
-
-    
     Assembler.prototype.setVisibility = function(visible){
         this.object3D.visible = visible;
         this._setTranslucent();
@@ -113,17 +107,33 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
     Assembler.prototype._setTranslucent = function(){
         assemblerMaterial.transparent = (appState.get("currentTab") == "cam" || appState.get("currentTab") == "assemblerSetup");
     };
-
-    Assembler.prototype.moveMachine = function(origin){//origin selection
-        this.object3D.position.set(origin.x, origin.y, origin.z);
-        three.render();
-    };
-    
     
     
     
+
+
+
+
+    //post process
+
+    Assembler.prototype.postProcess = function(settings, exporter){
+        var data = "";
+        data += exporter.makeHeader(settings);
+        data += "\n\n";
+        data += exporter.addComment("begin program");
+        data += "\n";
+
+        data += this._postProcessCells(settings, exporter);
+
+        data += "\n\n";
+        data += exporter.addComment("end program");
+        data += "\n";
+        data += exporter.makeFooter(settings);
+
+        return data;
+    };
     
-    Assembler.prototype.postProcess = function(settings, exporter){//override in subclasses
+    Assembler.prototype._postProcessCells = function(settings, exporter){
         var data = "";
         var self = this;
     
@@ -145,15 +155,16 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
 //                data += self._postMoveXY(exporter, stockPosition.x-wcs.x, stockPosition.y-wcs.y);
 //                data += self._postMoveToStock(exporter, thisStockPosition, rapidHeight, wcs, safeHeight);
             }
-            data += self._postMoveXY(cellPosition.x-settings.originPosition.x, cellPosition.y-settings.originPosition.y, settings, exporter);
-            data += self._postReleaseStock(cellPosition, cell, settings, exporter);
+            data += self._postMoveXY(cellPosition.clone().sub(settings.originPosition), settings, exporter);
+            data += self._postReleaseStock(cellIndex, cellPosition, settings, exporter);
             data += "\n";
         });
+
         return data;
     };
     
-    Assembler.prototype._postMoveXY = function(x, y, settings, exporter){
-        return exporter.rapidXY(x, y, settings);
+    Assembler.prototype._postMoveXY = function(position, settings, exporter){
+        return exporter.rapidXY(position, settings);
     };
     
 //    Assembler.prototype._postMoveToStock = function(exporter, stockPosition, rapidHeight, wcs, safeHeight){
@@ -167,23 +178,38 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
 //    };
     
     Assembler.prototype._postGetStock = function(index, position, settings, exporter){
-        return exporter.addComment("get stock");
+        var json = {
+            index:index,
+            position: position
+        };
+        return exporter.addComment("get stock " + JSON.stringify(json));
     };
     
-    Assembler.prototype._postReleaseStock = function(cellPosition, cell, settings, exporter){
+    Assembler.prototype._postReleaseStock = function(index, position, settings, exporter){
+        var json = {
+            index:index,
+            position: position
+        };
         var data = "";
-        data += exporter.rapidZ(cellPosition.z-settings.originPosition.z+settings.safeHeight, settings);
-        data += exporter.moveZ(cellPosition.z-settings.originPosition.z, settings);
-        data += exporter.addComment(JSON.stringify(cell.getAbsoluteIndex()));
-        data += exporter.moveZ(cellPosition.z-settings.originPosition.z+settings.safeHeight, settings);
+        data += exporter.rapidZ(position.z-settings.originPosition.z+settings.safeHeight, settings);
+        data += exporter.moveZ(position.z-settings.originPosition.z, settings);
+        data += exporter.addComment(JSON.stringify(json));
+        data += exporter.moveZ(position.z-settings.originPosition.z+settings.safeHeight, settings);
         data += exporter.rapidZ(settings.rapidHeight, settings);
         return data;
     };
+
+
     
     
     
     
     //animation methods
+
+    Assembler.prototype.moveMachine = function(origin){//origin selection
+        this.object3D.position.set(origin.x, origin.y, origin.z);
+        three.render();
+    };
     
     Assembler.prototype.updateCellMode = function(){//message from cam
         _.each(this.stock, function(stock){
@@ -203,9 +229,10 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
         });
     };
     
-    Assembler.prototype.releaseStock = function(index, settings){
-        console.log(index);
-        lattice.showCellAtIndex(JSON.parse(index));
+    Assembler.prototype.releaseStock = function(json, settings){
+        json = JSON.parse(json);
+        console.log(json.index);
+        lattice.showCellAtIndex(json.index);
         _.each(this.stock, function(stock){
             stock.hide();
         });
@@ -214,14 +241,8 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
     Assembler.prototype.pause = function(){
     };
     
-    Assembler.prototype.moveTo = function(x, y, z, speed, settings, callback){
-        x = this._makeAbsPosition(x, settings.originPosition.x);
-        y = this._makeAbsPosition(y, settings.originPosition.y);
-        z = this._makeAbsPosition(z, settings.originPosition.z);
-        this._moveTo(x, y, z, speed, callback);
-    };
-    
-    Assembler.prototype._moveTo = function(x, y, z, speed, callback){
+    Assembler.prototype.moveTo = function(position, speed, settings, callback){
+
         var totalThreads = 3;
         function sketchyCallback(){
             totalThreads -= 1;
@@ -229,54 +250,35 @@ define(['underscore', 'appState', 'lattice', 'stlLoader', 'threeModel', 'cam', '
             callback();
         }
         var startingPos = {x:this.components.xAxis.getPosition().x, y:this.components.yAxis.getPosition().y, z:this.components.zAxis.getPosition().z};
-        speed = this._normalizeSpeed(startingPos, x, y, this._reorganizeSpeed(speed));
-        this.components.xAxis.moveTo(this._makeAxisVector(x, "x"), speed.x, sketchyCallback);
-        this.components.yAxis.moveTo(this._makeAxisVector(y, "y"), speed.y, sketchyCallback);
-        this.components.zAxis.moveTo(this._makeAxisVector(z, "z"), speed.z, sketchyCallback);
-    };
-    
-    Assembler.prototype._makeAbsPosition = function(target, origin){
-        if (target == "" || target == null || target === undefined) return null;
-        return parseFloat(target)+origin;
+        speed = this._normalizeSpeed(startingPos, position, new THREE.Vector3(speed, speed, speed));
+        this.components.xAxis.moveTo(this._makeAxisVector(position, "x"), speed.x, sketchyCallback);
+        this.components.yAxis.moveTo(this._makeAxisVector(position, "y"), speed.y, sketchyCallback);
+        this.components.zAxis.moveTo(this._makeAxisVector(position, "z"), speed.z, sketchyCallback);
     };
     
-    Assembler.prototype._reorganizeSpeed = function(speed){
-        var newSpeed = {};
-        newSpeed.x = speed.xy;
-        newSpeed.y = speed.xy;
-        newSpeed.z = speed.z;
-        return newSpeed;
-    };
-    
-    Assembler.prototype._normalizeSpeed = function(startingPos, x, y, speed){//xy moves need speed normalization
-        var normSpeed = {};
-        if (x == "" || y == "" || x === null || y === null) return speed;
-        var deltaX = x-startingPos.x;
-        var deltaY = y-startingPos.y;
+    Assembler.prototype._normalizeSpeed = function(startingPos, position, speed){//todo make this more general
+        if (position.x === null && position.y === null) return speed;
+        var deltaX = position.x-startingPos.x;
+        var deltaY = position.y-startingPos.y;
         var totalDistance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
         if (totalDistance == 0) return speed;
-        normSpeed.x = Math.abs(deltaX/totalDistance*speed.x);
-        normSpeed.y = Math.abs(deltaY/totalDistance*speed.y);
-        normSpeed.z = speed.z;
-        return normSpeed;
+        speed.x = Math.abs(deltaX/totalDistance*speed.x);
+        speed.y = Math.abs(deltaY/totalDistance*speed.y);
+        return speed;
     };
     
     Assembler.prototype._makeAxisVector = function(position, axis){
-        switch (axis){
-            case "x":
-                return {x:position, y:0, z:0};
-            case "y":
-                return {x:0, y:position, z:0};
-            case "z":
-                return {x:0, y:0, z:position};
-            default:
-                console.warn(axis + " axis not recognized");
-                return null;
-        }
+        if (position[axis] == null) return null;
+        var vector = new THREE.Vector3(0,0,0);
+        vector[axis] = position[axis];
+        return vector;
     };
     
     
-    
+
+
+
+
     
     //helper
     
diff --git a/js/cam/assemblers/Component.js b/js/cam/assemblers/Component.js
index 331fc3c6c27f6c5c379d5f560da4ff031b0542b7..56c2902d0c0feb182b808fabcdb8e7eb872a764a 100644
--- a/js/cam/assemblers/Component.js
+++ b/js/cam/assemblers/Component.js
@@ -78,55 +78,33 @@ define(['underscore', 'cam', 'three'], function(_, cam, THREE){
     };
 
     Component.prototype.moveTo = function(target, speed, callback){
+        if (target === null){
+            if (callback) callback();
+            return;
+        }
         var currentPosition = this.getPosition();
-        var diff = _.clone(target);
-        _.each(_.keys(target), function(key){
-            if (target[key] === null) diff[key] = 0;
-            else diff[key] -= currentPosition[key];
-        });
-
-        var diffLength = this._getLength(diff);
         var increment = speed/25*cam.get("simSpeed");
+        var incrVector = target.clone().sub(currentPosition);
 
-        if (increment == 0 || diffLength == 0) {
+        if (increment == 0 || incrVector.length() == 0) {
             if (callback) callback();
             return;
         }
         increment = Math.max(increment, 0.00001);//need to put a min on the increment - otherwise this stalls out with floating pt tol
 
-        var incrementVector = diff;
-        _.each(_.keys(incrementVector), function(key){
-            incrementVector[key] *= increment/diffLength;
-        });
-        this._incrementalMove(incrementVector, target, callback);
-    };
-
-    Component.prototype._remainingDistanceToTarget = function(target){
-        var position = this.getPosition();
-        var dist = 0;
-        _.each(_.keys(target), function(key){
-            dist += Math.pow(target[key] - position[key], 2);
-        });
-        return dist;
-    };
-
-    Component.prototype._getLength = function(vector){
-        var length = 0;
-        _.each(_.keys(vector), function(key){
-            length += Math.pow(vector[key], 2);
-        });
-        return length;
+        incrVector.normalize().multiplyScalar(increment);
+        this._incrementalMove(incrVector, target, callback);
     };
 
     Component.prototype._incrementalMove = function(increment, target, callback){
         var self = this;
         setTimeout(function(){
-            var remainingDist = Math.abs(self._remainingDistanceToTarget(target));
+            var remainingDist = (target.clone().sub(self.getPosition())).length();
             var nextPos;
             if (remainingDist == 0) {
                 if (callback) callback();
                 return;
-            } else if (remainingDist < self._getLength(increment)){
+            } else if (remainingDist < increment.length()){
                 nextPos = target;//don't overshoot
             } else {
                 nextPos = self.getPosition();
diff --git a/js/cam/processes/GCodeExporter.js b/js/cam/processes/GCodeExporter.js
index aa57830f05ed9e0954bae7af4cea5fdf54fdd07b..9b173600d39e510e8c04e32e2087a8ccb4a835f2 100644
--- a/js/cam/processes/GCodeExporter.js
+++ b/js/cam/processes/GCodeExporter.js
@@ -43,16 +43,16 @@ define(['underscore', 'cam', 'lattice'], function(_, cam, lattice){
 
     GCodeExporter.prototype._setSpeed = function(speed){
         return "F"+ speed + "\n";
-    }
+    };
 
     //GCodeExporter.prototype._rapidXYZ = function(x, y, z){
     //    return this._goXYZ(x,y,z);
     //};
 
-    GCodeExporter.prototype.rapidXY = function(x, y, settings){
+    GCodeExporter.prototype.rapidXY = function(position, settings){
         var data = "";
         if (this.postSpeed != settings.rapidSpeeds.x) data += this._setSpeed(settings.rapidSpeeds.x);
-        return data + this._goXYZ(x, y, null);
+        return data + this._goXYZ(position.x, position.y, null);
     };
 
     GCodeExporter.prototype.rapidZ = function(z, settings){
@@ -97,7 +97,7 @@ define(['underscore', 'cam', 'lattice'], function(_, cam, lattice){
     };
 
     GCodeExporter.prototype.simulate = function(line, machine, settings,  callback){
-        if (line == "(get stock)"){
+        if (line.substr(0,11) == "(get stock)"){
             machine.pickUpStock(settings);
             return callback();
         }
@@ -113,24 +113,27 @@ define(['underscore', 'cam', 'lattice'], function(_, cam, lattice){
             return callback();
         }
         if (line.substr(0,3) == "G01"){
-            return this._simulateGetPosition(line, {xy:this.animationSpeed, z:this.animationSpeed}, machine, settings, callback);
+            return this._simulateG01(line, this.animationSpeed, machine, settings, callback);
         } else {
             console.warn("problem parsing gcode: " + line);
             return callback();
         }
     };
 
-    GCodeExporter.prototype._simulateGetPosition = function(line, speed, machine, settings, callback){
+    GCodeExporter.prototype._simulateG01 = function(line, speed, machine, settings, callback){
         var data = line.split(" ");
-        var position = {x:"",y:"",z:""};
-        if (data.length<2) console.warn("problem parsing gcode " + line);
+        var position = {x:null,y:null,z:null};
+        if (data.length<2) {
+            console.warn("problem parsing gcode " + line);
+            return callback();
+        }
         for (var i=1;i<data.length;i++){
             var item = data[i];
-            if (item[0] == "X") position.x = item.substr(1) / settings.scale;
-            if (item[0] == "Y") position.y = item.substr(1) / settings.scale;
-            if (item[0] == "Z") position.z = item.substr(1) / settings.scale;
+            if (item[0] == "X") position.x = parseFloat(item.substr(1)) / settings.scale;
+            if (item[0] == "Y") position.y = parseFloat(item.substr(1)) / settings.scale;
+            if (item[0] == "Z") position.z = parseFloat(item.substr(1)) / settings.scale;
         }
-        machine.moveTo(position.x, position.y, position.z, speed, settings, callback);
+        machine.moveTo(position, speed, settings, callback);
     };
 
     return GCodeExporter;