diff --git a/data/shopbotEndEffector.stl b/data/shopbotEndEffector.stl
new file mode 100644
index 0000000000000000000000000000000000000000..53bcf0aaa1d5955030c634bdf8fc77f3e545d740
Binary files /dev/null and b/data/shopbotEndEffector.stl differ
diff --git a/js/cam/Assembler.js b/js/cam/Assembler.js
index a96832e1057ba24e7227bd7fd4b49be6af257423..1ef826c3d1656fb1778e71089702508ad7064c0f 100644
--- a/js/cam/Assembler.js
+++ b/js/cam/Assembler.js
@@ -27,7 +27,7 @@ Assembler = Backbone.Model.extend({
         rapidSpeeds:{xy: 3, z: 2},//rapids at clearance height
         feedRate:{xy: 0.1, z: 0.1},//speed when heading towards assembly
 
-        simLineNumber: 1,//used for stock simulation, reading through gcode
+        simLineNumber: 0,//used for stock simulation, reading through gcode
         simSpeed: 4//#X times real speed
     },
 
@@ -65,23 +65,7 @@ Assembler = Backbone.Model.extend({
         this.listenTo(options.lattice, "change:partType", this._updatePartType);
         this.listenTo(options.appState, "change:cellMode", this._updateCellMode);
 
-
-
-
-        //init origin mesh
-        var origin = new THREE.Mesh(new THREE.SphereGeometry(1),
-            new THREE.MeshBasicMaterial({color:0xff0000}));
-        dmaGlobals.three.sceneAdd(origin);
-        this.set("origin", origin);
-        this._moveOrigin();
-        //init stock mesh
-        var stock = new THREE.Mesh(new THREE.SphereGeometry(1),
-            new THREE.MeshBasicMaterial({color:0xff00ff}));
-        dmaGlobals.three.sceneAdd(stock);
-        this.set("stock", stock);
-        this._moveStock();
-        this._setCAMScale(options.lattice.get("scale"));
-        this._setCAMVisibility();
+        this._initOriginAndStock(options.lattice);
     },
 
     makeProgramEdits: function(data){
@@ -121,6 +105,22 @@ Assembler = Backbone.Model.extend({
         dmaGlobals.three.render();
     },
 
+    _initOriginAndStock: function(lattice){//todo this is ugly
+        var origin = new THREE.Mesh(new THREE.SphereGeometry(1),
+            new THREE.MeshBasicMaterial({color:0xff0000}));
+        dmaGlobals.three.sceneAdd(origin);
+        this.set("origin", origin);
+        this._moveOrigin();
+        //init stock mesh
+        var stock = new THREE.Mesh(new THREE.SphereGeometry(1),
+            new THREE.MeshBasicMaterial({color:0xff00ff}));
+        dmaGlobals.three.sceneAdd(stock);
+        this.set("stock", stock);
+        this._moveStock();
+        this._setCAMScale(lattice.get("scale"));
+        this._setCAMVisibility();
+    },
+
     _moveOrigin: function(){
         var position = this.get("originPosition");
         this.get("origin").position.set(position.x, position.y, position.z);
@@ -140,6 +140,7 @@ Assembler = Backbone.Model.extend({
     _stockSimulation: function(){
         if (dmaGlobals.appState.get("stockSimulationPlaying")){
             var currentLine = this.get("simLineNumber");
+            if (currentLine == 0) dmaGlobals.lattice.hideCells();
             var allLines = this.get("dataOut").split("\n");
             if(currentLine<allLines.length){
                 var self = this;
@@ -151,7 +152,7 @@ Assembler = Backbone.Model.extend({
                 });
             } else {
                 //finished simulation
-                this.set("simLineNumber", 1);
+                this.set("simLineNumber", 0);
                 dmaGlobals.appState.set("stockSimulationPlaying", false);
             }
         } else {
@@ -168,7 +169,7 @@ Assembler = Backbone.Model.extend({
         this.set("needsPostProcessing", true);
     },
 
-        postProcess: function(){
+    postProcess: function(){
         this.set("needsPostProcessing", false);
         var exporter = this._getExporter();
 
@@ -201,7 +202,7 @@ Assembler = Backbone.Model.extend({
 
         this.set("dataOut", data);
         this.set("exporter", exporter);
-        this.set("simLineNumber", 1);
+        this.set("simLineNumber", 0);
         return {data:data, exporter:exporter};
     },
 
@@ -233,6 +234,7 @@ Assembler = Backbone.Model.extend({
         data += exporter.rapidXY(stockPosition.x, stockPosition.y);
         data += exporter.rapidZ(stockPosition.z+safeHeight);
         data += exporter.moveZ(stockPosition.z);
+        data += exporter.addComment("get stock");
         data += exporter.moveZ(stockPosition.z+safeHeight);
         data += exporter.rapidZ(rapidHeight);
         return data;
@@ -244,6 +246,7 @@ Assembler = Backbone.Model.extend({
         data += exporter.rapidXY(cellPosition.x-wcs.x, cellPosition.y-wcs.y);
         data += exporter.rapidZ(cellPosition.z-wcs.z+safeHeight);
         data += exporter.moveZ(cellPosition.z-wcs.z);
+        data += exporter.addComment(JSON.stringify(cell.indices));
         data += exporter.moveZ(cellPosition.z-wcs.z+safeHeight);
         data += exporter.rapidZ(rapidHeight);
         return data;
diff --git a/js/cam/Machine.js b/js/cam/Machine.js
index 71d9990b6d6ef59ec20af548b7d6f169692d0af3..6a0c47219f57947b21219beffb108a2d48935157 100644
--- a/js/cam/Machine.js
+++ b/js/cam/Machine.js
@@ -5,6 +5,23 @@
 
 function Machine() {
 
+    this.hasStock = false;
+
+    //load end effector geo
+    var loader = new THREE.STLLoader();
+    var self = this;
+    loader.load("data/shopbotEndEffector.stl", function(geometry){
+
+        geometry.computeBoundingBox();
+        var unitScale = 1.5/geometry.boundingBox.max.y;
+        geometry.applyMatrix(new THREE.Matrix4().makeScale(unitScale, unitScale, unitScale));
+        geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,0, Math.sqrt(2)/2));
+        var mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({color:0xaaaaaa, shading: THREE.FlatShading}));
+        self.endEffector = mesh;
+        dmaGlobals.three.sceneAdd(mesh);
+        mesh.visible = false;
+    });
+
     this.cell = new DMARotatedEdgeCell(null);
     this.setVisibility(false);
 
@@ -12,9 +29,11 @@ function Machine() {
 
 Machine.prototype.setVisibility = function(visible){
     if (visible){
-        this.cell.draw();
+        if (this.hasStock) this.cell.draw();
+        if (this.endEffector) this.endEffector.visible = true;
     } else {
         this.cell.hide();
+        if (this.endEffector) this.endEffector.visible = false;
     }
 };
 
@@ -23,10 +42,16 @@ Machine.prototype.updatePartType = function(){
     this.cell.draw();
 };
 
+Machine.prototype.pickUpStock = function(){
+    this.hasStock = true;
+    this.cell.draw();
+};
 
-
-
-
+Machine.prototype.releaseStock = function(index){
+    this.hasStock = false;
+    dmaGlobals.lattice.showCellAtIndex(JSON.parse(index));
+    this.cell.hide();
+};
 
 Machine.prototype.pause = function(){
 };
@@ -35,9 +60,21 @@ Machine.prototype.moveTo = function(x, y, z, speed, wcs, callback){
     var self = this;
     setTimeout( function() {
         //reaching a little deep here, might want to find a better solution
-        if (x != "") self.cell.cellMesh.position.x = parseFloat(x)+wcs.x;
-        if (y != "") self.cell.cellMesh.position.y = parseFloat(y)+wcs.y;
-        if (z != "") self.cell.cellMesh.position.z = parseFloat(z)+wcs.z;
+        if (x != "") {
+            var nextX = parseFloat(x)+wcs.x;
+            self.endEffector.position.x = nextX;
+            self.cell.cellMesh.position.x = nextX;
+        }
+        if (y != "") {
+            var nextY = parseFloat(y)+wcs.y;
+            self.endEffector.position.y = nextY;
+            self.cell.cellMesh.position.y = nextY;
+        }
+        if (z != "") {
+            var nextZ = parseFloat(z)+wcs.z;
+            self.endEffector.position.z = nextZ;
+            self.cell.cellMesh.position.z = nextZ;
+        }
         self.cell.updateForScale();
         dmaGlobals.three.render();
         return callback();
diff --git a/js/cam/ShopbotExporter.js b/js/cam/ShopbotExporter.js
index 43c315a33e21b8f884c8ae4795790146b2d5371f..196ea8d61b07b6ae60c9d58d276f681721a55b34 100644
--- a/js/cam/ShopbotExporter.js
+++ b/js/cam/ShopbotExporter.js
@@ -28,7 +28,7 @@ ShopbotExporter.prototype.addLine = function(command, params, comment){
             return;
         }
         if (dmaGlobals.lattice.get("units") == "mm") param = self.convertToInches(param);//all shopbot stuff must be in inches
-        data += param.toFixed(3) + ", ";
+        data += parseFloat(param).toFixed(3) + ", ";
     });
     if (comment) data += "'" +comment;
     data += "\n";
@@ -84,20 +84,28 @@ ShopbotExporter.prototype.convertToInches = function(mm){
 
 
 ShopbotExporter.prototype.simulate = function(line, machine, wcs,  callback){
+    if (line == "'get stock"){
+        machine.pickUpStock();
+        return callback();
+    }
+    if (line[1] == "{"){
+        machine.releaseStock(line.substr(1));
+        return callback();
+    }
     if (line == "" || line[0] == "'" || (line[0] != "J" && line[0] != "M")) {
         return callback();
     }
     if (line[0] == "J"){
-        return this.simulateGetPosition(line, dmaGlobals.assembler.get("rapidSpeeds"), machine, wcs, callback);
+        return this._simulateGetPosition(line, dmaGlobals.assembler.get("rapidSpeeds"), machine, wcs, callback);
     } else if (line[0] == "M"){
-        return this.simulateGetPosition(line, dmaGlobals.assembler.get("feedRate"), machine, wcs, callback);
+        return this._simulateGetPosition(line, dmaGlobals.assembler.get("feedRate"), machine, wcs, callback);
     } else {
         console.warn("problem parsing sbp");
         return callback();
     }
 };
 
-ShopbotExporter.prototype.simulateGetPosition = function(line, speed, machine, wcs, callback){
+ShopbotExporter.prototype._simulateGetPosition = function(line, speed, machine, wcs, callback){
     if (line[1] == 3 || line[1] == 2) {
         var data = line.split(" ");
         for (var i=0;i<data.length;i++){
diff --git a/js/fea/DmaPart.js b/js/fea/DmaPart.js
index 17b0869f31aaaa1feee6a48a1b85969f5352a189..8c9267c4df95cda59b2606a59f4c5aff107c67e3 100644
--- a/js/fea/DmaPart.js
+++ b/js/fea/DmaPart.js
@@ -97,7 +97,7 @@ var partMaterial = new THREE.MeshLambertMaterial({ color:0xffffff, shading: THRE
     var loader = new THREE.STLLoader();
     loader.load("data/trianglePart.stl", function(geometry){
 
-        unitPartGeo1 = geometry
+        unitPartGeo1 = geometry;
         unitPartGeo1.computeBoundingBox();
         var unitScale = 1.2/unitPartGeo1.boundingBox.max.y;
         unitPartGeo1.applyMatrix(new THREE.Matrix4().makeScale(unitScale, unitScale, unitScale));
diff --git a/js/menus/AnimationMenuView.js b/js/menus/AnimationMenuView.js
index b5a553150a98300f8ca5bf0273cd4f9da5709486..89f5b748a4ba1bf1033a7b759055f86eb5d5229c 100644
--- a/js/menus/AnimationMenuView.js
+++ b/js/menus/AnimationMenuView.js
@@ -55,7 +55,7 @@ AnimationMenuView = Backbone.View.extend({
 
     _resetStockSim: function(e){
         e.preventDefault();
-        dmaGlobals.assembler.set("simLineNumber", 1);
+        dmaGlobals.assembler.set("simLineNumber", 0);
     },
 
     _changeSpeedSlider: function(e){
@@ -78,7 +78,7 @@ AnimationMenuView = Backbone.View.extend({
         <% if (stockSimulationPlaying){ %>\
         <a href="#" id="pauseStockSim" class=" btn btn-block btn-lg btn-warning">Pause</a>\
         <% } else { %>\
-            <% if (simLineNumber != 1){ %>\
+            <% if (simLineNumber != 0){ %>\
                 <a href="#" id="playStockSim" class=" btn btn-lg btn-halfWidth btn-success">Play</a>\
                 <a href="#" id="resetStockSim" class=" btn btn-lg btn-halfWidth pull-right btn-default">Reset</a><br/>\
             <% } else { %>\
diff --git a/js/models/Lattice.js b/js/models/Lattice.js
index 4b57ea3c527d955dbffa5c343010da2c92a86253..f248b9da5d694ee065e4c621c822de0f5ae88a34 100644
--- a/js/models/Lattice.js
+++ b/js/models/Lattice.js
@@ -352,6 +352,26 @@ Lattice = Backbone.Model.extend({
         this.get("basePlane").updateScale(scale);
     },
 
+    //hide show cells during stock simulation
+    hideCells: function(){
+        this._iterCells(this.get("cells"), function(cell){
+            if (cell) cell.hide();
+        })
+    },
+
+    showCells: function(){
+        this._iterCells(this.get("cells"), function(cell){
+            if (cell) cell.draw();
+        })
+    },
+
+    showCellAtIndex: function(index){
+        var latticeIndex = this._subtract(index, this.get("cellsMin"));
+        var cell = this.get("cells")[latticeIndex.x][latticeIndex.y][latticeIndex.z];
+        if (cell) cell.draw();
+        else console.warn("placing a cell that does not exist");
+    },
+
     ////////////////////////////////////////////////////////////////////////////////////
     ///////////////////////////////CONNECTION TYPE//////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////////////////