From 0e2cb98f7ba90a4e0a0cf94182ebd8543943552a Mon Sep 17 00:00:00 2001
From: Amanda Ghassaei <amandaghassaei@gmail.com>
Date: Mon, 29 Jun 2015 15:38:52 -0700
Subject: [PATCH] basic cam working again

---
 js/cam/GCodeExporter.js                   | 132 -----
 js/cam/assemblers/Assembler.js            | 494 +++++++++---------
 js/cam/assemblers/Component.js            | 160 +++---
 js/cam/assemblers/DualStaplerAssembler.js |  12 -
 js/cam/assemblers/StaplerAssembler.js     | 154 +++---
 js/cam/cam.js                             | 581 +++++++++++-----------
 js/cam/processes/GCodeExporter.js         | 137 +++++
 js/cam/{ => processes}/ShopbotExporter.js |   0
 js/cam/{ => processes}/TinyGExporter.js   |   0
 js/main.js                                |  24 +-
 js/menus/Navbar.js                        |   2 +-
 js/menus/templates/CamMenuView.html       |   4 +-
 js/models/AppState.js                     |   2 +
 js/{models => plists}/PList.js            |  30 +-
 js/simulation/electronics/eCell.js        |   3 +
 js/simulation/electronics/eSim.js         |   3 +
 js/simulation/electronics/eSimEngine.js   |   3 +
 js/three/ThreeView.js                     |   6 +-
 18 files changed, 905 insertions(+), 842 deletions(-)
 delete mode 100644 js/cam/GCodeExporter.js
 delete mode 100644 js/cam/assemblers/DualStaplerAssembler.js
 create mode 100644 js/cam/processes/GCodeExporter.js
 rename js/cam/{ => processes}/ShopbotExporter.js (100%)
 rename js/cam/{ => processes}/TinyGExporter.js (100%)
 rename js/{models => plists}/PList.js (92%)
 create mode 100644 js/simulation/electronics/eCell.js
 create mode 100644 js/simulation/electronics/eSim.js
 create mode 100644 js/simulation/electronics/eSimEngine.js

diff --git a/js/cam/GCodeExporter.js b/js/cam/GCodeExporter.js
deleted file mode 100644
index 8ccc6761..00000000
--- a/js/cam/GCodeExporter.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
- * Created by aghassaei on 3/10/15.
- */
-
-function GCodeExporter() {
-    //keep track of speeds for F commands
-    this.postSpeed = null;
-    this.animationSpeed = null;
-}
-
-GCodeExporter.prototype.makeHeader = function(){
-    var data = "";
-    if (globals.lattice.get("units") == "inches") data += this.addLine("G20", [], "units inches");
-    else data += this.addLine("G21", [], "units mm");
-//    data += this.addLine("G90", [], "absolute positioning");
-//    data += this.addLine("G54", [], "work offset");
-////    data += this.addLine("G49", [], "cancel tool length comp");
-//    data += this.addLine("G40", [], "cancel tool radius comp");
-////    data += this.addLine("M09", [], "coolant off");
-
-    data += this.goHome();
-    
-    return data;
-};
-
-GCodeExporter.prototype.addLine = function(command, params, comment){
-    var data = "";
-    data += command + " ";
-    _.each(params, function(param){
-        if (!param) return;
-        data += param + " ";
-    });
-    if (comment) data += "(" + comment + ")";
-    data += "\n";
-    return data;
-};
-
-GCodeExporter.prototype.addComment = function(comment){
-    return "(" + comment + ")" + "\n";
-};
-
-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){
-    var data = "";
-    if (this.postSpeed != globals.cam.get("rapidSpeeds").xy) data += this._setSpeed(globals.cam.get("rapidSpeeds").xy);
-    return data + this._goXYZ(x, y, null);
-};
-
-GCodeExporter.prototype.rapidZ = function(z){
-    var data = "";
-    if (this.postSpeed != globals.cam.get("rapidSpeeds").z) data += this._setSpeed(globals.cam.get("rapidSpeeds").z);
-    return data + this._goXYZ(null, null, z);
-};
-
-GCodeExporter.prototype._goXYZ = function(x, y, z){
-    if (x !== null) x = "X"+parseFloat(x).toFixed(3);
-    if (y !== null) y = "Y"+parseFloat(y).toFixed(3);
-    if (z !== null) z = "Z"+parseFloat(z).toFixed(3);
-    return this.addLine("G01", [x,y,z]);
-};
-
-GCodeExporter.prototype.moveXY = function(x, y){
-    var data = "";
-    if (this.postSpeed != globals.cam.get("feedRate").xy) data += this._setSpeed(globals.cam.get("feedRate").xy);
-    return data + this._goXYZ(x, y, null);
-};
-
-GCodeExporter.prototype.moveZ = function(z){
-    var data = "";
-    if (this.postSpeed != globals.cam.get("feedRate").z) data += this._setSpeed(globals.cam.get("feedRate").z);
-    return data + this._goXYZ(null, null, z);
-};
-
-GCodeExporter.prototype.goHome = function(){
-    var data = this._setSpeed(globals.cam.get("rapidSpeeds").z);
-    return data + this._goXYZ(0,0,globals.cam.get("rapidHeight"));
-};
-
-GCodeExporter.prototype.makeFooter = function(){
-    var data = "";
-//    data += this.addLine("M30", [], "program stop");
-    return data;
-};
-
-GCodeExporter.prototype.save = function(data){
-    var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
-    saveAs(blob, "GCodeExport" + ".nc");
-};
-
-GCodeExporter.prototype.simulate = function(line, machine, wcs,  callback){
-    if (line == "(get stock)"){
-        machine.pickUpStock();
-        return callback();
-    }
-    if (line.substr(0,2) == "({"){
-        machine.releaseStock(line.substr(1,line.length-2));
-        return callback();
-    }
-    if (line[0] == "F"){//speed
-        this.animationSpeed = line.split("F")[1];
-        return callback();
-    }
-    if (line == "" || line[0] == "(" || line.substr(0,3) != "G01"){
-        return callback();
-    }
-    if (line.substr(0,3) == "G01"){
-        return this._simulateGetPosition(line, {xy:this.animationSpeed, z:this.animationSpeed}, machine, wcs, callback);
-    } else {
-        console.warn("problem parsing gcode: " + line);
-        return callback();
-    }
-};
-
-GCodeExporter.prototype._simulateGetPosition = function(line, speed, machine, wcs, callback){
-    var data = line.split(" ");
-    var position = {x:"",y:"",z:""};
-    if (data.length<2) console.warn("problem parsing gcode " + line);
-    for (var i=1;i<data.length;i++){
-        var item = data[i];
-        if (item[0] == "X") position.x = item.substr(1);
-        if (item[0] == "Y") position.y = item.substr(1);
-        if (item[0] == "Z") position.z = item.substr(1);
-    }
-    machine.moveTo(position.x, position.y, position.z, speed, wcs, callback);
-};
diff --git a/js/cam/assemblers/Assembler.js b/js/cam/assemblers/Assembler.js
index 46bfb07c..41a0075e 100644
--- a/js/cam/assemblers/Assembler.js
+++ b/js/cam/assemblers/Assembler.js
@@ -2,252 +2,256 @@
  * Created by aghassaei on 5/28/15.
  */
 
-
-var assemblerMaterial = new THREE.MeshLambertMaterial({color:0xaaaaaa, shading: THREE.FlatShading, transparent:true, opacity:0.5});
-
-function Assembler(){
-
-    this.stock = this._buildStock();
-    this._positionStockRelativeToEndEffector(this.stock);
-    this.object3D = new THREE.Object3D();
-    globals.three.sceneAdd(this.object3D);
-    var self = this;
-    this._buildAssemblerComponents(function(){
-        self._configureAssemblerMovementDependencies();
-        globals.three.render();
-    });
-
-    this.setVisibility(globals.cam.isVisible());
-}
-
-Assembler.prototype._buildStock = function(){
-    if (globals.lattice.makeSuperCell) return globals.lattice.makeSuperCell();
-    return globals.lattice.makeCellForLatticeType({});
-};
-
-Assembler.prototype._positionStockRelativeToEndEffector = function(){
-};
-
-Assembler.prototype._buildAssemblerComponents = function(callback){
-    var numMeshes = this._getTotalNumMeshes();
-    if (numMeshes == 0) {
-        callback();
-        return;
+define(['underscore', 'appState', 'lattice', 'three', 'threeModel', 'cam', 'component'], function(_, appState, lattice, THREE, three, cam, Component){
+    
+    var assemblerMaterial = new THREE.MeshLambertMaterial({color:0xaaaaaa, shading: THREE.FlatShading, transparent:true, opacity:0.5});
+    
+    function Assembler(){
+
+        var self = this;
+        this.stock = this._buildStock();
+        this._positionStockRelativeToEndEffector(this.stock);
+
+        this.object3D = new THREE.Object3D();
+        three.sceneAdd(this.object3D);
+        this._buildAssemblerComponents(function(){
+            self._configureAssemblerMovementDependencies();
+            three.render();
+        });
+    
+        this.setVisibility(cam.isVisible());
     }
-
-    function allLoaded(){
-        numMeshes -= 1;
-        return numMeshes <= 0;
-    }
-
-    var self = this;
-    function doAdd(geometry, name){
-        self[name] = new Component(geometry, assemblerMaterial);
-        if (allLoaded()) callback();
-    }
-
-    this._loadSTls(doAdd);
-};
-
-Assembler.prototype._getTotalNumMeshes = function(){
-    return 0;
-};
-
-Assembler.prototype._configureAssemblerMovementDependencies = function(){
-};
-
-Assembler.prototype.setVisibility = function(visible){
-    this.object3D.visible = visible;
-    this._setTranslucent();
-    globals.three.render();
-};
-
-Assembler.prototype._setTranslucent = function(){
-    //todo make stock transparent
-    if (globals.appState.get("currentTab") == "cam"){
-        assemblerMaterial.transparent = true;
-    } else {
-        assemblerMaterial.transparent = false;
-    }
-};
-
-
-
-
-
-Assembler.prototype.postProcess = function(data, exporter){//override in subclasses
-
-    var rapidHeight = globals.cam.get("rapidHeight");
-    var safeHeight = globals.cam.get("safeHeight");
-    var wcs = globals.cam.get("originPosition");
-
-    var stockPosition = globals.cam.get("stockPosition");
-    var stockNum = 0;//position of stock in stock array
-    var multStockPositions = globals.cam.get("multipleStockPositions");
-    var stockSeparation = globals.cam.get("stockSeparation");
-    var stockArraySize = globals.cam.get("stockArraySize");
-    var self = this;
-
-    globals.lattice.rasterCells(globals.cam._getOrder(globals.cam.get("camStrategy")), function(cell){
-        if (!cell) return;
-        if (this.stockAttachedToEndEffector){
-            data += self._postGetStock(exporter);
+    
+    Assembler.prototype._buildStock = function(callback){
+        lattice.makeCellForLatticeType({}, callback);
+    };
+    
+    Assembler.prototype._positionStockRelativeToEndEffector = function(stock){
+    };
+    
+    Assembler.prototype._buildAssemblerComponents = function(callback){
+        var numMeshes = this._getTotalNumMeshes();
+        if (numMeshes == 0) {
+            callback();
+            return;
+        }
+    
+        function allLoaded(){
+            numMeshes -= 1;
+            return numMeshes <= 0;
+        }
+    
+        var self = this;
+        function doAdd(geometry, name){
+            self[name] = new Component(geometry, assemblerMaterial);
+            if (allLoaded()) callback();
+        }
+    
+        this._loadSTls(doAdd);
+    };
+    
+    Assembler.prototype._getTotalNumMeshes = function(){
+        return 0;
+    };
+    
+    Assembler.prototype._configureAssemblerMovementDependencies = function(){
+    };
+    
+    Assembler.prototype.setVisibility = function(visible){
+        this.object3D.visible = visible;
+        this._setTranslucent();
+        three.render();
+    };
+    
+    Assembler.prototype._setTranslucent = function(){
+        //todo make stock transparent
+        if (appState.get("currentTab") == "cam"){
+            assemblerMaterial.transparent = true;
         } else {
-            var thisStockPosition = _.clone(stockPosition);
-            if (multStockPositions) {
-                thisStockPosition.x += stockNum % stockArraySize.y * stockSeparation;
-                thisStockPosition.y -= Math.floor(stockNum / stockArraySize.y) * stockSeparation;
-                stockNum += 1;
-                if (stockNum >= stockArraySize.x * stockArraySize.y) stockNum = 0;
+            assemblerMaterial.transparent = false;
+        }
+    };
+    
+    
+    
+    
+    
+    Assembler.prototype.postProcess = function(data, exporter){//override in subclasses
+    
+        var rapidHeight = cam.get("rapidHeight");
+        var safeHeight = cam.get("safeHeight");
+        var wcs = cam.get("originPosition");
+    
+        var stockPosition = cam.get("stockPosition");
+        var stockNum = 0;//position of stock in stock array
+        var multStockPositions = cam.get("multipleStockPositions");
+        var stockSeparation = cam.get("stockSeparation");
+        var stockArraySize = cam.get("stockArraySize");
+        var self = this;
+    
+        lattice.rasterCells(cam._getOrder(cam.get("camStrategy")), function(cell){
+            if (!cell) return;
+            if (this.stockAttachedToEndEffector){
+                data += self._postGetStock(exporter);
+            } else {
+                var thisStockPosition = _.clone(stockPosition);
+                if (multStockPositions) {
+                    thisStockPosition.x += stockNum % stockArraySize.y * stockSeparation;
+                    thisStockPosition.y -= Math.floor(stockNum / stockArraySize.y) * stockSeparation;
+                    stockNum += 1;
+                    if (stockNum >= stockArraySize.x * stockArraySize.y) stockNum = 0;
+                }
+                data += self._postMoveXY(exporter, stockPosition.x-wcs.x, stockPosition.y-wcs.y);
+                data += self._postPickUpStock(exporter, thisStockPosition, rapidHeight, wcs, safeHeight);
             }
-            data += self._postMoveXY(exporter, stockPosition.x-wcs.x, stockPosition.y-wcs.y);
-            data += self._postPickUpStock(exporter, thisStockPosition, rapidHeight, wcs, safeHeight);
+            var cellPosition = cell.getPosition();
+            data += self._postMoveXY(exporter, cellPosition.x-wcs.x, cellPosition.y-wcs.y);
+            data += self._postReleaseStock(cellPosition, cell, exporter, rapidHeight, wcs, safeHeight);
+            data += "\n";
+        });
+        return data;
+    };
+    
+    Assembler.prototype._postMoveXY = function(exporter, x, y){
+        return exporter.rapidXY(x, y);
+    };
+    
+    Assembler.prototype._postPickUpStock = function(exporter, stockPosition, rapidHeight, wcs, safeHeight){
+        var data = "";
+        data += exporter.rapidZ(stockPosition.z-wcs.z+safeHeight);
+        data += exporter.moveZ(stockPosition.z-wcs.z);
+        data += this._postGetStock(exporter);
+        data += exporter.moveZ(stockPosition.z-wcs.z+safeHeight);
+        data += exporter.rapidZ(rapidHeight);
+        return data;
+    };
+    
+    Assembler.prototype._postGetStock = function(exporter){
+        return exporter.addComment("get stock");
+    };
+    
+    Assembler.prototype._postReleaseStock = function(cellPosition, cell, exporter, rapidHeight, wcs, safeHeight){
+        var data = "";
+        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;
+    };
+    
+    
+    
+    
+    
+    
+    Assembler.prototype.updateCellMode = function(){
+    //    this.stock.setMode();//todo fix this
+        _.each(this.stock.cells, function(cell){
+            cell.setMode();
+        });
+    };
+    
+    Assembler.prototype.pickUpStock = function(){
+        this.stock.show();
+    };
+    
+    Assembler.prototype.releaseStock = function(index){
+        lattice.showCellAtIndex(JSON.parse(index));
+        this.stock.hide();
+    };
+    
+    Assembler.prototype.pause = function(){
+    };
+    
+    Assembler.prototype.moveMachine = function(){
+        var origin = cam.get("originPosition");
+        this.object3D.position.set(origin.x, origin.y, origin.z);
+        three.render();
+    };
+    
+    Assembler.prototype.moveTo = function(x, y, z, speed, wcs, callback){
+        x = this._makeAbsPosition(x, wcs.x);
+        y = this._makeAbsPosition(y, wcs.y);
+        z = this._makeAbsPosition(z, wcs.z);
+        this._moveTo(x, y, z, speed, wcs, callback);
+    };
+    
+    Assembler.prototype._moveTo = function(x, y, z, speed, wcs, callback){
+        var totalThreads = 3;
+        function sketchyCallback(){
+            totalThreads -= 1;
+            if (totalThreads > 0) return;
+            callback();
         }
-        var cellPosition = cell.getPosition();
-        data += self._postMoveXY(exporter, cellPosition.x-wcs.x, cellPosition.y-wcs.y);
-        data += self._postReleaseStock(cellPosition, cell, exporter, rapidHeight, wcs, safeHeight);
-        data += "\n";
-    });
-    return data;
-};
-
-Assembler.prototype._postMoveXY = function(exporter, x, y){
-    return exporter.rapidXY(x, y);
-};
-
-Assembler.prototype._postPickUpStock = function(exporter, stockPosition, rapidHeight, wcs, safeHeight){
-    var data = "";
-    data += exporter.rapidZ(stockPosition.z-wcs.z+safeHeight);
-    data += exporter.moveZ(stockPosition.z-wcs.z);
-    data += this._postGetStock(exporter);
-    data += exporter.moveZ(stockPosition.z-wcs.z+safeHeight);
-    data += exporter.rapidZ(rapidHeight);
-    return data;
-};
-
-Assembler.prototype._postGetStock = function(exporter){
-    return exporter.addComment("get stock");
-};
-
-Assembler.prototype._postReleaseStock = function(cellPosition, cell, exporter, rapidHeight, wcs, safeHeight){
-    var data = "";
-    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;
-};
-
-
-
-
-
-
-Assembler.prototype.updateCellMode = function(){
-//    this.stock.setMode();//todo fix this
-    _.each(this.stock.cells, function(cell){
-        cell.setMode();
-    });
-};
-
-Assembler.prototype.pickUpStock = function(){
-    this.stock.show();
-};
-
-Assembler.prototype.releaseStock = function(index){
-    globals.lattice.showCellAtIndex(JSON.parse(index));
-    this.stock.hide();
-};
-
-Assembler.prototype.pause = function(){
-};
-
-Assembler.prototype.moveMachine = function(){
-    var origin = globals.cam.get("originPosition");
-    this.object3D.position.set(origin.x, origin.y, origin.z);
-    globals.three.render();
-};
-
-Assembler.prototype.moveTo = function(x, y, z, speed, wcs, callback){
-    x = this._makeAbsPosition(x, wcs.x);
-    y = this._makeAbsPosition(y, wcs.y);
-    z = this._makeAbsPosition(z, wcs.z);
-    this._moveTo(x, y, z, speed, wcs, callback);
-};
-
-Assembler.prototype._moveTo = function(x, y, z, speed, wcs, callback){
-    var totalThreads = 3;
-    function sketchyCallback(){
-        totalThreads -= 1;
-        if (totalThreads > 0) return;
-        callback();
-    }
-    var startingPos = {x:this.xAxis.getPosition(), y:this.yAxis.getPosition(), z:this.zAxis.getPosition()};
-    speed = this._normalizeSpeed(startingPos, x, y, this._reorganizeSpeed(speed));
-    this.xAxis.moveTo(this._makeAxisVector(x, "x"), speed.x, sketchyCallback);
-    this.yAxis.moveTo(this._makeAxisVector(y, "y"), speed.y, sketchyCallback);
-    this.zAxis.moveTo(this._makeAxisVector(z, "z"), speed.z, sketchyCallback);
-};
-
-Assembler.prototype._makeAbsPosition = function(target, wcs){
-    if (target == "" || target == null || target === undefined) return null;
-    return parseFloat(target)+wcs;
-};
-
-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 == "") return speed;
-    var deltaX = x-startingPos.x;
-    var deltaY = 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;
-};
-
-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;
-    }
-};
-
-
-
-
-
-
-Assembler.prototype.destroy = function(){
-    this.stock.destroy();
-    this.zAxis.destroy();
-    this.xAxis.destroy();
-    this.yAxis.destroy();
-    this.frame.destroy();
-    this.substrate.destroy();
-    globals.three.sceneRemove(this.object3D);
-    this.stock = null;
-    this.zAxis = null;
-    this.xAxis = null;
-    this.yAxis = null;
-    this.frame = null;
-    this.substrate = null;
-    this.object3D = null;
-};
+        var startingPos = {x:this.xAxis.getPosition(), y:this.yAxis.getPosition(), z:this.zAxis.getPosition()};
+        speed = this._normalizeSpeed(startingPos, x, y, this._reorganizeSpeed(speed));
+        this.xAxis.moveTo(this._makeAxisVector(x, "x"), speed.x, sketchyCallback);
+        this.yAxis.moveTo(this._makeAxisVector(y, "y"), speed.y, sketchyCallback);
+        this.zAxis.moveTo(this._makeAxisVector(z, "z"), speed.z, sketchyCallback);
+    };
+    
+    Assembler.prototype._makeAbsPosition = function(target, wcs){
+        if (target == "" || target == null || target === undefined) return null;
+        return parseFloat(target)+wcs;
+    };
+    
+    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 == "") return speed;
+        var deltaX = x-startingPos.x;
+        var deltaY = 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;
+    };
+    
+    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;
+        }
+    };
+    
+    
+    
+    
+    
+    
+    Assembler.prototype.destroy = function(){
+        this.stock.destroy();
+        this.zAxis.destroy();
+        this.xAxis.destroy();
+        this.yAxis.destroy();
+        this.frame.destroy();
+        this.substrate.destroy();
+        three.sceneRemove(this.object3D);
+        this.stock = null;
+        this.zAxis = null;
+        this.xAxis = null;
+        this.yAxis = null;
+        this.frame = null;
+        this.substrate = null;
+        this.object3D = null;
+    };
+
+    return Assembler;
+});
diff --git a/js/cam/assemblers/Component.js b/js/cam/assemblers/Component.js
index 207f91e0..9fa4e15b 100644
--- a/js/cam/assemblers/Component.js
+++ b/js/cam/assemblers/Component.js
@@ -3,87 +3,91 @@
  */
 
 
-function Component(geometry, material){
-    this.object3D = new THREE.Mesh(geometry, material);
-}
-
-Component.prototype.getPosition = function(){
-    return this.object3D.position.clone();
-};
-
-Component.prototype.getObject3D = function(){
-    return this.object3D;
-};
-
-Component.prototype.addChild = function(child){
-    this.object3D.add(child.getObject3D());
-};
-
-Component.prototype.moveTo = function(target, speed, callback){
-    var currentPosition = this.getPosition();
-    var diff = _.clone(target);
-    _.each(_.keys(target), function(key){
-        diff[key] -= currentPosition[key];
-    });
-
-    var diffLength = this._getLength(diff);
-    var increment = speed/25*globals.cam.get("simSpeed");
-
-    if (increment == 0 || diffLength == 0) {
-        if (callback) callback();
-        return;
+define(['underscore', 'cam', 'three'], function(_, cam, THREE){
+
+    function Component(geometry, material){
+        this.object3D = new THREE.Mesh(geometry, material);
     }
-    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;
-};
-
-Component.prototype._incrementalMove = function(increment, target, callback){
-    var self = this;
-    setTimeout(function(){
-        var remainingDist = Math.abs(self._remainingDistanceToTarget(target));
-        var nextPos;
-        if (remainingDist == 0) {
+
+    Component.prototype.getPosition = function(){
+        return this.object3D.position.clone();
+    };
+
+    Component.prototype.getObject3D = function(){
+        return this.object3D;
+    };
+
+    Component.prototype.addChild = function(child){
+        this.object3D.add(child.getObject3D());
+    };
+
+    Component.prototype.moveTo = function(target, speed, callback){
+        var currentPosition = this.getPosition();
+        var diff = _.clone(target);
+        _.each(_.keys(target), function(key){
+            diff[key] -= currentPosition[key];
+        });
+
+        var diffLength = this._getLength(diff);
+        var increment = speed/25*cam.get("simSpeed");
+
+        if (increment == 0 || diffLength == 0) {
             if (callback) callback();
             return;
-        } else if (remainingDist < self._getLength(increment)){
-            nextPos = target;//don't overshoot
-        } else {
-            nextPos = self.getPosition();
-            _.each(_.keys(nextPos), function(key){
-                nextPos[key] += increment[key];
-            });
         }
+        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;
+    };
+
+    Component.prototype._incrementalMove = function(increment, target, callback){
+        var self = this;
+        setTimeout(function(){
+            var remainingDist = Math.abs(self._remainingDistanceToTarget(target));
+            var nextPos;
+            if (remainingDist == 0) {
+                if (callback) callback();
+                return;
+            } else if (remainingDist < self._getLength(increment)){
+                nextPos = target;//don't overshoot
+            } else {
+                nextPos = self.getPosition();
+                _.each(_.keys(nextPos), function(key){
+                    nextPos[key] += increment[key];
+                });
+            }
+
+            self.object3D.position.set(nextPos.x, nextPos.y, nextPos.z);
+            self._incrementalMove(increment, target, callback);
+        }, 10);
+    };
 
-        console.log(nextPos);
-        self.object3D.position.set(nextPos.x, nextPos.y, nextPos.z);
-        self._incrementalMove(increment, target, callback);
-    }, 10);
-};
+    Component.prototype.destroy = function(){
+        if (this.object3D && this.object3D.parent) this.object3D.parent.remove(this.object3D);
+        this.object3D = null;
+    };
 
-Component.prototype.destroy = function(){
-    if (this.object3D && this.object3D.parent) this.object3D.parent.remove(this.object3D);
-    this.object3D = null;
-};
\ No newline at end of file
+    return Component;
+});
\ No newline at end of file
diff --git a/js/cam/assemblers/DualStaplerAssembler.js b/js/cam/assemblers/DualStaplerAssembler.js
deleted file mode 100644
index a0a9fb6b..00000000
--- a/js/cam/assemblers/DualStaplerAssembler.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Created by aghassaei on 5/28/15.
- */
-
-function DualStaplerAssembler(){
-    StaplerAssembler.call(this);
-}
-DualStaplerAssembler.prototype = Object.create(StaplerAssembler.prototype);
-
-DualStaplerAssembler.prototype._headSTLFile = function(){
-    return "assets/stls/stapler/zAxisDual.stl";
-};
\ No newline at end of file
diff --git a/js/cam/assemblers/StaplerAssembler.js b/js/cam/assemblers/StaplerAssembler.js
index 1e9c5e78..70ab8dcb 100644
--- a/js/cam/assemblers/StaplerAssembler.js
+++ b/js/cam/assemblers/StaplerAssembler.js
@@ -3,84 +3,94 @@
  */
 
 
-function StaplerAssembler(){
-    this.stockAttachedToEndEffector = true;//no need for "stock position"
-    Assembler.call(this);
-}
-StaplerAssembler.prototype = Object.create(Assembler.prototype);
+define(['underscore', 'assembler', 'stlLoader', 'gikSuperCell'], function(_, Assembler, THREE, StockClass){
 
-StaplerAssembler.prototype._positionStockRelativeToEndEffector = function(stock){
-    var object3D = stock.getObject3D();
-    object3D.position.set((2.4803+0.2)*20, (-1.9471+0.36)*20, 1.7*20);
-};
+    function StaplerAssembler(){
+        this.stockAttachedToEndEffector = true;//no need for "stock position"
+        Assembler.call(this);
+    }
+    StaplerAssembler.prototype = Object.create(Assembler.prototype);
 
-StaplerAssembler.prototype._configureAssemblerMovementDependencies = function(){
-    this.zAxis.addChild(this.stock);
-    this.xAxis.addChild(this.zAxis);
-    this.frame.addChild(this.xAxis);
-    this.frame.addChild(this.yAxis);
-    this.object3D.add(this.frame.getObject3D());
-    this.object3D.add(this.substrate.getObject3D());
-};
+    StaplerAssembler.prototype._buildStock = function(){
+        return new StockClass({});
+    };
 
-StaplerAssembler.prototype._getTotalNumMeshes = function(){
-    return 5;
-};
+    StaplerAssembler.prototype._positionStockRelativeToEndEffector = function(stock){
+        var object3D = stock.getObject3D();
+        object3D.position.set((2.4803+0.2)*20, (-1.9471+0.36)*20, 1.7*20);
+    };
 
-StaplerAssembler.prototype._loadSTls = function(doAdd){
+    StaplerAssembler.prototype._configureAssemblerMovementDependencies = function(){
+        this.zAxis.addChild(this.stock);
+        this.xAxis.addChild(this.zAxis);
+        this.frame.addChild(this.xAxis);
+        this.frame.addChild(this.yAxis);
+        this.object3D.add(this.frame.getObject3D());
+        this.object3D.add(this.substrate.getObject3D());
+    };
 
-    function geometryScale(geometry){
-        geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-4.0757, -4.3432, -6.2154));
-        geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI/2));
+    StaplerAssembler.prototype._getTotalNumMeshes = function(){
+        return 5;
+    };
 
-        var unitScale = 20;
-        geometry.applyMatrix(new THREE.Matrix4().makeScale(unitScale, unitScale, unitScale));
-        geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-21, -0.63, 0));
-        return geometry;
-    }
+    StaplerAssembler.prototype._loadSTls = function(doAdd){
 
-    var loader = new THREE.STLLoader();
-    loader.load("assets/stls/stapler/frame.stl", function(geometry){
-        doAdd(geometryScale(geometry), "frame");
-    });
-    loader.load(this._headSTLFile(), function(geometry){
-        doAdd(geometryScale(geometry), "zAxis");
-    });
-    loader.load("assets/stls/stapler/yAxis.stl", function(geometry){
-        doAdd(geometryScale(geometry), "yAxis");
-    });
-    loader.load("assets/stls/stapler/xAxis.stl", function(geometry){
-        doAdd(geometryScale(geometry), "xAxis");
-    });
-    loader.load("assets/stls/stapler/substrate.stl", function(geometry){
-//        geometry.applyMatrix(new THREE.Matrix4().makeRotationY(Math.PI/2));
-//        geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, 1.8545, -1.2598));
-        doAdd(geometryScale(geometry), "substrate");
-    });
-};
+        function geometryScale(geometry){
+            geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-4.0757, -4.3432, -6.2154));
+            geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI/2));
 
-StaplerAssembler.prototype._headSTLFile = function(){
-    return "assets/stls/stapler/zAxis.stl";
-};
+            var unitScale = 20;
+            geometry.applyMatrix(new THREE.Matrix4().makeScale(unitScale, unitScale, unitScale));
+            geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-21, -0.63, 0));
+            return geometry;
+        }
 
-StaplerAssembler.prototype._moveXAxis = function(startingPos, target, axis, speed, callback){
-    if (target == null || target === undefined) {
-        callback();
-        return;
-    }
-    this._animateObjects([this.xAxis], axis, speed, startingPos, target, callback);
-};
-StaplerAssembler.prototype._moveYAxis = function(startingPos, target, axis, speed, callback){
-    if (target == null || target === undefined) {
-        callback();
-        return;
-    }
-    this._animateObjects([this.yAxis], axis, speed, startingPos, target, callback);
-};
-StaplerAssembler.prototype._moveZAxis = function(startingPos, target, axis, speed, callback){
-    if (target == null || target === undefined) {
-        callback();
-        return;
-    }
-    this._animateObjects([this.zAxis], axis, speed, startingPos, target, callback);
-};
\ No newline at end of file
+        var loader = new THREE.STLLoader();
+        loader.load("assets/stls/stapler/frame.stl", function(geometry){
+            doAdd(geometryScale(geometry), "frame");
+        });
+        loader.load(this._headSTLFile(), function(geometry){
+            doAdd(geometryScale(geometry), "zAxis");
+        });
+        loader.load("assets/stls/stapler/yAxis.stl", function(geometry){
+            doAdd(geometryScale(geometry), "yAxis");
+        });
+        loader.load("assets/stls/stapler/xAxis.stl", function(geometry){
+            doAdd(geometryScale(geometry), "xAxis");
+        });
+        loader.load("assets/stls/stapler/substrate.stl", function(geometry){
+    //        geometry.applyMatrix(new THREE.Matrix4().makeRotationY(Math.PI/2));
+    //        geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, 1.8545, -1.2598));
+            doAdd(geometryScale(geometry), "substrate");
+        });
+    };
+
+    StaplerAssembler.prototype._headSTLFile = function(){
+        return "assets/stls/stapler/zAxis.stl";
+    };
+
+    StaplerAssembler.prototype._moveXAxis = function(startingPos, target, axis, speed, callback){
+        if (target == null || target === undefined) {
+            callback();
+            return;
+        }
+        this._animateObjects([this.xAxis], axis, speed, startingPos, target, callback);
+    };
+    StaplerAssembler.prototype._moveYAxis = function(startingPos, target, axis, speed, callback){
+        if (target == null || target === undefined) {
+            callback();
+            return;
+        }
+        this._animateObjects([this.yAxis], axis, speed, startingPos, target, callback);
+    };
+    StaplerAssembler.prototype._moveZAxis = function(startingPos, target, axis, speed, callback){
+        if (target == null || target === undefined) {
+            callback();
+            return;
+        }
+        this._animateObjects([this.zAxis], axis, speed, startingPos, target, callback);
+    };
+
+
+    return StaplerAssembler;
+});
\ No newline at end of file
diff --git a/js/cam/cam.js b/js/cam/cam.js
index 3d3d69ca..3cadcdea 100644
--- a/js/cam/cam.js
+++ b/js/cam/cam.js
@@ -2,289 +2,314 @@
  * Created by aghassaei on 3/10/15.
  */
 
-Cam = Backbone.Model.extend({
-
-    defaults: {
-        camStrategy: "raster",
-        placementOrder: "XYZ",//used for raster strategy entry
-        camProcess: "gcode",
-        machineName: "stapler",
-        assembler: null,
-        exporter: null,
-
-        dataOut: "",
-        needsPostProcessing: true,
-        editsMadeToProgram: false,//warn the user that they will override changes
-
-        rapidHeight: 6,//always store relative to origin
-        rapidHeightRelative: true,
-        safeHeight: 0.5,//inches above stock or assembly, when feed rate should slow
-
-        origin: null,
-        originPosition: new THREE.Vector3(20,0,0),//in abs coordinates
-        stock: null,
-        stockPosition: new THREE.Vector3(20,0,0),//in abs coordinates
-        stockPositionRelative: true,
-        stockFixed: false,//stock is fixed position from origin
-        multipleStockPositions: false,
-        stockArraySize: {x:4, y:4},
-        stockSeparation: 2.78388,
-
-        rapidSpeeds:{xy: 3, z: 2},//rapids at clearance height
-        feedRate:{xy: 0.1, z: 0.1},//speed when heading towards assembly
-
-        simLineNumber: 0,//used for stock simulation, reading through gcode
-        simSpeed: 4//#X times real speed
-    },
-
-    initialize: function(){
-
-        _.bindAll(this, "postProcess");
-
-        //bind events
-        this.listenTo(globals.appState, "change:currentTab", this._tabChanged);
-        this.listenTo(this, "change:originPosition", this._moveOrigin);
-        this.listenTo(this, "change:stockPosition", this._moveStock);
-        this.listenTo(this,
-                "change:originPosition " +
-                "change:stockPosition " +
-                "change:feedRate " +
-                "change:rapidSpeeds " +
-                "change:camProcess " +
-                "change:camStrategy " +
-                "change:placementOrder " +
-                "change:safeHeight " +
-                "change:stockArraySize " +
-                "change:stockSeparation " +
-                "change:multipleStockPositions " +
-                "change:rapidHeight " +
-                "change:machineName",
-            this._setNeedsPostProcessing);
-        this.listenTo(globals.lattice,
-                "change:numCells " +
-                "change:units " +
-                "change:scale " +
-                "change:cellType " +
-                "change:connectionType",
-            this._setNeedsPostProcessing);
-        this.listenTo(globals.appState, "change:stockSimulationPlaying", this._stockSimulation);
-
-        this.listenTo(globals.lattice, "change:partType", this._updatePartType);
-        this.listenTo(globals.lattice, "change:cellType change:connectionType", this._updateCellType);
-        this.listenTo(globals.appState, "change:cellMode", this._updateCellMode);
-        this.listenTo(this, "change:machineName", this.selectMachine);
-
-//        this._initOriginAndStock();
-    },
-
-    selectMachine: function(){
-        var machineName = this.get("machineName");
-        if (this.get("assembler")) this.get("assembler").destroy();
-        this.set("assembler", null);
-        this._setMachineDefaults(machineName);
-        if (machineName == "shopbot"){
-            this.set("assembler", new Shopbot());
-        } else if (machineName == "handOfGod"){
-            this.set("assembler", new God());
-        } else if (machineName == "oneBitBot"){
-            this.set("assembler", new OneBitBot());
-        } else if (machineName == "stapler"){
-            this.set("assembler", new StaplerAssembler());
-        } else if (machineName == "staplerDual"){
-            this.set("assembler", new DualStaplerAssembler());
-        } else{
-            console.warn("selected assembler not recognized");
-        }
-    },
-
-    _setMachineDefaults: function(machineName){
-        if (globals.plist.allMachineDefaults[machineName]){
-            _.each(_.keys(globals.plist.allMachineDefaults[machineName]), function(key){
-                globals.cam.set(key, globals.plist.allMachineDefaults[machineName][key], {silent:true});
+define(['underscore', 'backbone', 'appState', 'latticeCAM', 'threeModel', 'plist'], function(_, Backbone, appState, lattice, three, plist){
+
+    var Cam = Backbone.Model.extend({
+
+        defaults: {
+            camStrategy: "raster",
+            placementOrder: "XYZ",//used for raster strategy entry
+            camProcess: "gcode",
+            machineName: "stapler",
+            assembler: null,
+            exporter: null,
+
+            dataOut: "",
+            needsPostProcessing: true,
+            editsMadeToProgram: false,//warn the user that they will override changes
+
+            rapidHeight: 6,//always store relative to origin
+            rapidHeightRelative: true,
+            safeHeight: 0.5,//inches above stock or assembly, when feed rate should slow
+
+            origin: null,
+            originPosition: new THREE.Vector3(20,0,0),//in abs coordinates
+            stock: null,
+            stockPosition: new THREE.Vector3(20,0,0),//in abs coordinates
+            stockPositionRelative: true,
+            stockFixed: false,//stock is fixed position from origin
+            multipleStockPositions: false,
+            stockArraySize: {x:4, y:4},
+            stockSeparation: 2.78388,
+
+            rapidSpeeds:{xy: 3, z: 2},//rapids at clearance height
+            feedRate:{xy: 0.1, z: 0.1},//speed when heading towards assembly
+
+            simLineNumber: 0,//used for stock simulation, reading through gcode
+            simSpeed: 4//#X times real speed
+        },
+
+        initialize: function(){
+
+            _.bindAll(this, "postProcess");
+
+            //bind events
+            this.listenTo(appState, "change:currentTab", this._tabChanged);
+            this.listenTo(appState, "change:currentNav", this._navChanged);
+            this.listenTo(this, "change:originPosition", this._moveOrigin);
+            this.listenTo(this, "change:stockPosition", this._moveStock);
+            this.listenTo(this,
+                    "change:originPosition " +
+                    "change:stockPosition " +
+                    "change:feedRate " +
+                    "change:rapidSpeeds " +
+                    "change:camProcess " +
+                    "change:camStrategy " +
+                    "change:placementOrder " +
+                    "change:safeHeight " +
+                    "change:stockArraySize " +
+                    "change:stockSeparation " +
+                    "change:multipleStockPositions " +
+                    "change:rapidHeight " +
+                    "change:machineName",
+                this._setNeedsPostProcessing);
+            this.listenTo(lattice,
+                    "change:numCells " +
+                    "change:units " +
+                    "change:scale " +
+                    "change:cellType " +
+                    "change:connectionType",
+                this._setNeedsPostProcessing);
+            this.listenTo(appState, "change:stockSimulationPlaying", this._stockSimulation);
+
+            this.listenTo(lattice, "change:partType", this._updatePartType);
+            this.listenTo(lattice, "change:cellType change:connectionType", this._updateCellType);
+            this.listenTo(appState, "change:cellMode", this._updateCellMode);
+            this.listenTo(this, "change:machineName", this.selectMachine);
+
+    //        this._initOriginAndStock();
+        },
+
+
+
+
+
+
+
+        selectMachine: function(){
+            var machineName = this.get("machineName");
+            if (this.get("assembler")) this.get("assembler").destroy();
+            this.set("assembler", null);
+            this._setMachineDefaults(machineName);
+            var self = this;
+            require([machineName], function(MachineClass){
+                self.set('assembler', new MachineClass());
             });
-        }
-    },
-
-    makeProgramEdits: function(data){
-        this.set("dataOut", data, {silent:true});
-        this.set("editsMadeToProgram", true, {silent: true});
-    },
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////VISUALIZATION//////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-    isVisible: function(){
-        var currentTab = globals.appState.get("currentTab");
-        return (currentTab == "cam" || currentTab == "animate" || currentTab == "send");
-    },
-
-    _updateCellType: function(){
-        if (this.get("assembler")) this.get("assembler").updateCellType();
-        this.set("machineName", "handOfGod");//todo this should go away with dynamic allocation of this model
-
-    },
-
-    _updatePartType: function(){
-        if (this.get("assembler")) this.get("assembler").updatePartType();
-    },
-
-    _updateCellMode: function(){
-        if (this.get("assembler")) this.get("assembler").updateCellMode();
-        globals.three.render();
-    },
-
-    _tabChanged: function(){
-        this._setCAMVisibility();
-        if (globals.appState.get("currentTab") != "animate") this.resetSimulation();
-    },
-
-    _setCAMVisibility: function(){
-        var visible = this.isVisible();
-//        this.get("origin").visible = visible;
-//        this.get("stock").visible = visible;
-        if (visible && !this.get("assembler")) this.selectMachine();
-        if (this.get("assembler")) this.get("assembler").setVisibility(visible);
-        if (globals.appState.get("currentNav") == "navAssemble") {
-            globals.appState.set("basePlaneIsVisible", !visible);
-            globals.appState.set("highlighterIsVisible", !visible);
-        }
-        globals.three.render();
-    },
-
-    _initOriginAndStock: function(){//todo this is ugly
-        var origin = new THREE.Mesh(new THREE.SphereGeometry(1),
-            new THREE.MeshBasicMaterial({color:0xff0000}));
-        globals.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}));
-        globals.three.sceneAdd(stock);
-        this.set("stock", stock);
-        this._moveStock();
-        this._setCAMVisibility();
-    },
-
-    _moveOrigin: function(){
-        var position = this.get("originPosition");
-//        this.get("origin").position.set(position.x, position.y, position.z);
-        if (this.get("stockFixed")) this._updateStockPosToOrigin(position, this.previous("originPosition"));
-        globals.three.render();
-        if (this.get("assembler")) this.get("assembler").moveMachine();
-    },
-
-    _updateStockPosToOrigin: function(newOrigin, lastOrigin){
-        var newStockPosition = _.clone(this.get("stockPosition"));
-        _.each(_.keys(newStockPosition), function(key){
-            newStockPosition[key] += newOrigin[key] - lastOrigin[key];
-            newStockPosition[key] = parseFloat(newStockPosition[key].toFixed(4));
-        });
-        this.set("stockPosition", newStockPosition);
-    },
-
-    _moveStock: function(){
-        var position = this.get("stockPosition");
-        this.get("stock").position.set(position.x, position.y, position.z);
-        globals.three.render();
-    },
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-///////////////////////////////SIMULATION//////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-    resetSimulation: function(){
-        this.set("simLineNumber", 0, {silent:true});
-        globals.appState.set("stockSimulationPlaying", false);
-        globals.three.stopAnimationLoop();
-        globals.lattice.showCells();
-    },
-
-    _stockSimulation: function(){
-        if (globals.appState.get("stockSimulationPlaying")){
-            globals.three.startAnimationLoop();
-            var currentLine = this.get("simLineNumber");
-            if (currentLine == 0) globals.lattice.hideCells();
-            var allLines = this.get("dataOut").split("\n");
-            if(currentLine<allLines.length){
-                var self = this;
-                this.get("exporter").simulate(allLines[currentLine], this.get("assembler"),
-                    this.get("originPosition"), function(){
-                    currentLine++;
-                    self.set("simLineNumber", currentLine);
-                    self._stockSimulation();
+        },
+
+        _setMachineDefaults: function(machineName){
+            var self = this;
+            if (plist.allMachineDefaults[machineName]){
+                _.each(_.keys(plist.allMachineDefaults[machineName]), function(key){
+                    self.set(key, plist.allMachineDefaults[machineName][key], {silent:true});
                 });
+            }
+        },
+
+        makeProgramEdits: function(data){
+            this.set("dataOut", data, {silent:true});
+            this.set("editsMadeToProgram", true, {silent: true});
+        },
+
+
+
+
+
+
+        //events
+
+        _navChanged: function(){
+            if (appState.get("currentNav") == "navAssemble") this._setToDefaults();
+        },
+
+        _setToDefaults: function(){
+            //call this each time we switch to assemble tab
+            var availableMachines = _.keys(plist.allMachineTypes[lattice.get("cellType")][lattice.get("connectionType")]);
+            if (availableMachines.indexOf(this.get("machineName")) < 0){
+                this.set("machineName", availableMachines[0]);
+            }
+        },
+
+        _tabChanged: function(){
+            this._setCAMVisibility();
+            if (appState.get("currentTab") != "animate") this.resetSimulation();
+        },
+
+        _setCAMVisibility: function(){
+            var visible = this.isVisible();
+    //        this.get("origin").visible = visible;
+    //        this.get("stock").visible = visible;
+            if (visible && !this.get("assembler")) this.selectMachine();
+            if (this.get("assembler")) this.get("assembler").setVisibility(visible);
+            if (appState.get("currentNav") == "navAssemble") {
+                appState.set("basePlaneIsVisible", !visible);
+                appState.set("highlighterIsVisible", !visible);
+            }
+            three.render();
+        },
+
+        _updateCellType: function(){
+            if (this.get("assembler")) this.get("assembler").updateCellType();
+            this.set("machineName", "handOfGod");//todo this should go away with dynamic allocation of this model
+
+        },
+
+        _updatePartType: function(){
+            if (this.get("assembler")) this.get("assembler").updatePartType();
+        },
+
+        _updateCellMode: function(){
+            if (this.get("assembler")) this.get("assembler").updateCellMode();
+            three.render();
+        },
+
+
+
+
+
+
+
+
+
+        //visualization
+
+        isVisible: function(){
+            var currentTab = appState.get("currentTab");
+            return (currentTab == "cam" || currentTab == "animate" || currentTab == "send");
+        },
+
+
+        _initOriginAndStock: function(){//todo this is ugly
+            var origin = new THREE.Mesh(new THREE.SphereGeometry(1),
+                new THREE.MeshBasicMaterial({color:0xff0000}));
+            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}));
+            three.sceneAdd(stock);
+            this.set("stock", stock);
+            this._moveStock();
+            this._setCAMVisibility();
+        },
+
+        _moveOrigin: function(){
+            var position = this.get("originPosition");
+    //        this.get("origin").position.set(position.x, position.y, position.z);
+            if (this.get("stockFixed")) this._updateStockPosToOrigin(position, this.previous("originPosition"));
+            three.render();
+            if (this.get("assembler")) this.get("assembler").moveMachine();
+        },
+
+        _updateStockPosToOrigin: function(newOrigin, lastOrigin){
+            var newStockPosition = _.clone(this.get("stockPosition"));
+            _.each(_.keys(newStockPosition), function(key){
+                newStockPosition[key] += newOrigin[key] - lastOrigin[key];
+                newStockPosition[key] = parseFloat(newStockPosition[key].toFixed(4));
+            });
+            this.set("stockPosition", newStockPosition);
+        },
+
+        _moveStock: function(){
+            var position = this.get("stockPosition");
+            this.get("stock").position.set(position.x, position.y, position.z);
+            three.render();
+        },
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    ///////////////////////////////SIMULATION//////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+        resetSimulation: function(){
+            this.set("simLineNumber", 0, {silent:true});
+            appState.set("stockSimulationPlaying", false);
+            three.stopAnimationLoop();
+            lattice.showCells();
+        },
+
+        _stockSimulation: function(){
+            if (appState.get("stockSimulationPlaying")){
+                three.startAnimationLoop();
+                var currentLine = this.get("simLineNumber");
+                if (currentLine == 0) lattice.hideCells();
+                var allLines = this.get("dataOut").split("\n");
+                if(currentLine<allLines.length){
+                    var self = this;
+                    this.get("exporter").simulate(allLines[currentLine], this.get("assembler"),
+                        this.get("originPosition"), function(){
+                        currentLine++;
+                        self.set("simLineNumber", currentLine);
+                        self._stockSimulation();
+                    });
+                } else {
+                    //finished simulation
+                    this.resetSimulation();
+                }
             } else {
-                //finished simulation
-                this.resetSimulation();
+                three.stopAnimationLoop();
+                this.get("assembler").pause();
             }
-        } else {
-            globals.three.stopAnimationLoop();
-            this.get("assembler").pause();
-        }
 
-    },
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////POST PROCESSING////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-    _setNeedsPostProcessing: function(){
-        this.set("needsPostProcessing", true);
-    },
-
-    postProcess: function(){
-        this.set("needsPostProcessing", false);
-        var exporter = this._getExporter();
-
-        var data = "";
-        data += exporter.makeHeader();
-        data += "\n\n";
-        data += exporter.addComment("begin program");
-        data += "\n";
-
-        data = this.get("assembler").postProcess(data, exporter);
-
-        data += "\n\n";
-        data += exporter.addComment("end program");
-        data += "\n";
-        data += exporter.makeFooter();
-
-        this.set("dataOut", data);
-        this.set("editsMadeToProgram", false);
-        this.set("exporter", exporter);
-        if (!globals.appState.get("stockSimulationPlaying")) this.resetSimulation();
-        return {data:data, exporter:exporter};
-    },
-
-    _getExporter: function(){
-//        var currentExporter = this.get("exporter");
-        var camProcess = this.get("camProcess");
-        if (camProcess == "shopbot") {
-            return new ShopbotExporter();
-        } else if (camProcess == "gcode") {
-            return new GCodeExporter();
-        } else if (camProcess == "tinyG"){
-            return new TinyGExporter();
-        }
-        console.warn("cam process not supported");
-        return null;
-    },
-
-    _getOrder: function(strategy){
-        if (strategy == "raster") return this.get("placementOrder");
-        console.warn("strategy not recognized");
-        return "";
-    },
-
-    save: function(){
-        if (this.get("needsPostProcessing")){
-            var output = this.postProcess();
-            output.exporter.save(output.data);
-            return;
+        },
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////POST PROCESSING////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+        _setNeedsPostProcessing: function(){
+            this.set("needsPostProcessing", true);
+        },
+
+        postProcess: function(){
+            this.set("needsPostProcessing", false);
+            var self = this;
+            this._getExporter(function(exporter){
+                var data = "";
+                data += exporter.makeHeader();
+                data += "\n\n";
+                data += exporter.addComment("begin program");
+                data += "\n";
+
+                data = self.get("assembler").postProcess(data, exporter);
+
+                data += "\n\n";
+                data += exporter.addComment("end program");
+                data += "\n";
+                data += exporter.makeFooter();
+
+                self.set("dataOut", data);
+                self.set("editsMadeToProgram", false);
+                self.set("exporter", exporter);
+                if (!appState.get("stockSimulationPlaying")) self.resetSimulation();
+            });
+//            return {data:data, exporter:exporter};//todo this breaks save
+        },
+
+        _getExporter: function(callback){
+    //        var currentExporter = this.get("exporter");
+            var camProcess = this.get("camProcess");
+            require([camProcess], function(ProcessClass){
+                if (callback) callback(new ProcessClass());
+            });
+        },
+
+        _getOrder: function(strategy){
+            if (strategy == "raster") return this.get("placementOrder");
+            console.warn("strategy not recognized");
+            return "";
+        },
+
+        save: function(){
+            if (this.get("needsPostProcessing")){
+                var output = this.postProcess();
+                output.exporter.save(output.data);
+                return;
+            }
+            this.get("exporter").save(this.get("dataOut"));
         }
-        this.get("exporter").save(this.get("dataOut"));
-    }
 
+    });
+
+    return new Cam();
 });
\ No newline at end of file
diff --git a/js/cam/processes/GCodeExporter.js b/js/cam/processes/GCodeExporter.js
new file mode 100644
index 00000000..feb519a0
--- /dev/null
+++ b/js/cam/processes/GCodeExporter.js
@@ -0,0 +1,137 @@
+/**
+ * Created by aghassaei on 3/10/15.
+ */
+
+define(['underscore', 'cam', 'lattice'], function(_, cam, lattice){
+
+    function GCodeExporter() {
+        //keep track of speeds for F commands
+        this.postSpeed = null;
+        this.animationSpeed = null;
+    }
+
+    GCodeExporter.prototype.makeHeader = function(){
+        var data = "";
+        if (lattice.get("units") == "inches") data += this.addLine("G20", [], "units inches");
+        else data += this.addLine("G21", [], "units mm");
+    //    data += this.addLine("G90", [], "absolute positioning");
+    //    data += this.addLine("G54", [], "work offset");
+    ////    data += this.addLine("G49", [], "cancel tool length comp");
+    //    data += this.addLine("G40", [], "cancel tool radius comp");
+    ////    data += this.addLine("M09", [], "coolant off");
+
+        data += this.goHome();
+
+        return data;
+    };
+
+    GCodeExporter.prototype.addLine = function(command, params, comment){
+        var data = "";
+        data += command + " ";
+        _.each(params, function(param){
+            if (!param) return;
+            data += param + " ";
+        });
+        if (comment) data += "(" + comment + ")";
+        data += "\n";
+        return data;
+    };
+
+    GCodeExporter.prototype.addComment = function(comment){
+        return "(" + comment + ")" + "\n";
+    };
+
+    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){
+        var data = "";
+        if (this.postSpeed != cam.get("rapidSpeeds").xy) data += this._setSpeed(cam.get("rapidSpeeds").xy);
+        return data + this._goXYZ(x, y, null);
+    };
+
+    GCodeExporter.prototype.rapidZ = function(z){
+        var data = "";
+        if (this.postSpeed != cam.get("rapidSpeeds").z) data += this._setSpeed(cam.get("rapidSpeeds").z);
+        return data + this._goXYZ(null, null, z);
+    };
+
+    GCodeExporter.prototype._goXYZ = function(x, y, z){
+        if (x !== null) x = "X"+parseFloat(x).toFixed(3);
+        if (y !== null) y = "Y"+parseFloat(y).toFixed(3);
+        if (z !== null) z = "Z"+parseFloat(z).toFixed(3);
+        return this.addLine("G01", [x,y,z]);
+    };
+
+    GCodeExporter.prototype.moveXY = function(x, y){
+        var data = "";
+        if (this.postSpeed != cam.get("feedRate").xy) data += this._setSpeed(cam.get("feedRate").xy);
+        return data + this._goXYZ(x, y, null);
+    };
+
+    GCodeExporter.prototype.moveZ = function(z){
+        var data = "";
+        if (this.postSpeed != cam.get("feedRate").z) data += this._setSpeed(cam.get("feedRate").z);
+        return data + this._goXYZ(null, null, z);
+    };
+
+    GCodeExporter.prototype.goHome = function(){
+        var data = this._setSpeed(cam.get("rapidSpeeds").z);
+        return data + this._goXYZ(0,0,cam.get("rapidHeight"));
+    };
+
+    GCodeExporter.prototype.makeFooter = function(){
+        var data = "";
+    //    data += this.addLine("M30", [], "program stop");
+        return data;
+    };
+
+    GCodeExporter.prototype.save = function(data){
+        var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
+        saveAs(blob, "GCodeExport" + ".nc");
+    };
+
+    GCodeExporter.prototype.simulate = function(line, machine, wcs,  callback){
+        if (line == "(get stock)"){
+            machine.pickUpStock();
+            return callback();
+        }
+        if (line.substr(0,2) == "({"){
+            machine.releaseStock(line.substr(1,line.length-2));
+            return callback();
+        }
+        if (line[0] == "F"){//speed
+            this.animationSpeed = line.split("F")[1];
+            return callback();
+        }
+        if (line == "" || line[0] == "(" || line.substr(0,3) != "G01"){
+            return callback();
+        }
+        if (line.substr(0,3) == "G01"){
+            return this._simulateGetPosition(line, {xy:this.animationSpeed, z:this.animationSpeed}, machine, wcs, callback);
+        } else {
+            console.warn("problem parsing gcode: " + line);
+            return callback();
+        }
+    };
+
+    GCodeExporter.prototype._simulateGetPosition = function(line, speed, machine, wcs, callback){
+        var data = line.split(" ");
+        var position = {x:"",y:"",z:""};
+        if (data.length<2) console.warn("problem parsing gcode " + line);
+        for (var i=1;i<data.length;i++){
+            var item = data[i];
+            if (item[0] == "X") position.x = item.substr(1);
+            if (item[0] == "Y") position.y = item.substr(1);
+            if (item[0] == "Z") position.z = item.substr(1);
+        }
+        machine.moveTo(position.x, position.y, position.z, speed, wcs, callback);
+    };
+
+    return GCodeExporter;
+});
diff --git a/js/cam/ShopbotExporter.js b/js/cam/processes/ShopbotExporter.js
similarity index 100%
rename from js/cam/ShopbotExporter.js
rename to js/cam/processes/ShopbotExporter.js
diff --git a/js/cam/TinyGExporter.js b/js/cam/processes/TinyGExporter.js
similarity index 100%
rename from js/cam/TinyGExporter.js
rename to js/cam/processes/TinyGExporter.js
diff --git a/js/main.js b/js/main.js
index f8ba4ef3..b464bbbb 100644
--- a/js/main.js
+++ b/js/main.js
@@ -11,6 +11,7 @@ require.config({
         underscore: '../dependencies/underscore',
         backbone: '../dependencies/backbone',
         flatUI: '../dependencies/flatUI/js/flat-ui',
+        bootstrapSlider: '../dependencies/bootstrap-slider/bootstrap-slider',
         fileSaverLib: '../dependencies/loaders/FileSaver.min',
 
         //three
@@ -21,9 +22,11 @@ require.config({
         threeView: 'three/ThreeView',
         fillGeometry: 'three/FillGeometry',
 
+        //plists
+        plist: 'plists/PList',
+
         //models
         globals: 'models/Globals',
-        plist: 'models/PList',
         appState: 'models/AppState',
         fileSaver: 'models/FileSaver',
 
@@ -131,7 +134,7 @@ require.config({
         optimizeMenuTemplate: 'menus/templates/OptimizationMenuView.html',
         assemblerMenuTemplate: 'menus/templates/AssemblerMenuView.html',
         camMenuTemplate: 'menus/templates/CamMenuView.html',
-        animateMenuTemplate: 'menus/templates/AnimationMenuView.html',
+        animationMenuTemplate: 'menus/templates/AnimationMenuView.html',
         sendMenuTemplate: 'menus/templates/SendMenuView.html',
         compositeMenuTemplate: 'menus/templates/CompositeMenuView.html',
         materialEditorMenuTemplate: 'menus/templates/MaterialEditorMenuView.html',
@@ -139,11 +142,20 @@ require.config({
         discoveryMenuTemplate: 'menus/templates/DiscoveryMenuView.html',
 
         //cam
-        cam: 'cam/cam.js',
+        cam: 'cam/cam',
 
         //assemblers
+        assembler: 'cam/assemblers/Assembler',
+        component: 'cam/assemblers/Component',
+        stapler: 'cam/assemblers/StaplerAssembler',
+        dualStapler: 'cam/assemblers/DualStaplerAssembler',
         crab: 'cam/assemblers/crab',
 
+        //processes
+        gcode: 'cam/processes/GCodeExporter',
+        shopbot: 'cam/processes/ShopbotExporter',
+        tinyG: 'cam/processes/TinyGExporter',
+
         //stls (not sure why ../ is not working here?)
         octaFaceTrianglePartSTL: 'assets/stls/parts/OctaFaceTrianglePart.stl',
         octaEdgeVoxPartSTL: 'assets/stls/parts/OctaEdgeVoxPart.stl',
@@ -177,6 +189,10 @@ require.config({
         flatUI: {
             deps: ['jquery']
         },
+        bootstrapSlider:{
+            deps: ['jquery'],
+            exports: '$'
+        },
         'socketio': {
             exports: 'io'
         }
@@ -191,7 +207,7 @@ require.config({
 //};
 
 //init stuff
-require(['appState', 'lattice', 'navbar', 'threeModel', 'threeView', 'flatUI', 'ribbon', 'menuWrapper'],
+require(['appState', 'lattice', 'navbar', 'threeModel', 'threeView', 'flatUI', 'bootstrapSlider', 'ribbon', 'menuWrapper'],
     function(appState, lattice, Navbar, three, ThreeView){
 
     new Navbar({model:appState});
diff --git a/js/menus/Navbar.js b/js/menus/Navbar.js
index 715544ae..9e90c18d 100644
--- a/js/menus/Navbar.js
+++ b/js/menus/Navbar.js
@@ -50,7 +50,7 @@ define(['jquery', 'underscore', 'backbone', 'fileSaver', 'navViewMenu'], functio
 
         _setNavSelection: function(e){
             var navSelection = $(e.target).data("menuId");
-            if (navSelection == "about" || navSelection == "navAssemble") {
+            if (navSelection == "about") {
                 $(e.target).blur();
                 return;
             }
diff --git a/js/menus/templates/CamMenuView.html b/js/menus/templates/CamMenuView.html
index 074f235a..c2df6444 100644
--- a/js/menus/templates/CamMenuView.html
+++ b/js/menus/templates/CamMenuView.html
@@ -15,14 +15,14 @@ Units: &nbsp;&nbsp;<div class="btn-group">
             <% }); %>
         </ul>
     </div><br/><br/>
-Origin (xyz): &nbsp;&nbsp;
+Origin (xyz):&nbsp;&nbsp;
     <input data-property="originPosition" data-key="x" value="<%= originPosition.x %>" placeholder="X" class="form-control floatInput assembler" type="text">&nbsp;
     <input data-property="originPosition" data-key="y" value="<%= originPosition.y %>" placeholder="Y" class="form-control floatInput assembler" type="text">&nbsp;
     <input data-property="originPosition" data-key="z" value="<%= originPosition.z %>" placeholder="Z" class="form-control floatInput assembler" type="text">
 <% if (!(machineName == "handOfGod")){ %><br/>
     <a id="manualSelectOrigin" class=" btn btn-lg btn-default btn-imageCustom<% if (manualSelectOrigin){ %> btn-selected<% } %>"><img src="assets/imgs/cursor.png"></a>
     <label>&nbsp;&nbsp;&nbsp;Manually select origin from existing cell</label><br/><br/>
-    <% if (!assembler.stockAttachedToEndEffector){ %>
+    <% if (assembler && !assembler.stockAttachedToEndEffector){ %>
         Stock (xyz): &nbsp;&nbsp;
             <input data-property="stockPosition" data-key="x" value="<%= stockPosition.x %>" placeholder="X" class="form-control floatInput assembler" type="text">&nbsp;
             <input data-property="stockPosition" data-key="y" value="<%= stockPosition.y %>" placeholder="Y" class="form-control floatInput assembler" type="text">&nbsp;
diff --git a/js/models/AppState.js b/js/models/AppState.js
index fa11e4e5..d83de728 100644
--- a/js/models/AppState.js
+++ b/js/models/AppState.js
@@ -106,6 +106,8 @@ define(['underscore', 'backbone', 'threeModel', 'three', 'plist', 'globals'], fu
             if (navSelection == "navDesign") {
                 this.set("basePlaneIsVisible", true);
                 this.set("highlighterIsVisible", true);
+            } else if (navSelection == "navAssemble"){
+                require(['cam']);
             }
         },
 
diff --git a/js/models/PList.js b/js/plists/PList.js
similarity index 92%
rename from js/models/PList.js
rename to js/plists/PList.js
index 2c236ee7..969fc919 100644
--- a/js/models/PList.js
+++ b/js/plists/PList.js
@@ -222,8 +222,7 @@ define(['three'], function(THREE){
             cube:{
                 face:{handOfGod: "Hand of God"},
                 gik: {
-                    stapler: "Stapler",
-                        staplerDual: "Dual Head Stapler"
+                    stapler: "Dual Head Stapler"
 //                handOfGod: "Hand of God"
                 }
             },
@@ -240,12 +239,12 @@ define(['three'], function(THREE){
         allCamProcesses: {
             shopbot:{
                 shopbot: "Shopbot (sbp)",
-                    gcode: "G-Code"
+                gcode: "G-Code"
             },
             handOfGod:{gcode: "G-Code"},
             oneBitBot:{
                 gcode: "G-Code",
-                    tinyG: "TinyG"
+                tinyG: "TinyG"
             },
             stapler: {gcode: "G-Code"},
             staplerDual: {gcode: "G-Code"}
@@ -253,20 +252,19 @@ define(['three'], function(THREE){
 
         allMachineDefaults: {
             shopbot:null,
-                handOfGod:null,
-                oneBitBot:null,
-                stapler: {
+            handOfGod:null,
+            oneBitBot:null,
+            stapler: {
                 camStrategy: "raster",
-                    placementOrder: "XYZ",//used for raster strategy entry
-                    camProcess: "gcode",
-                    rapidHeight:3,
-                    rapidHeightRelative: true,
-                    safeHeight: 0.05,
-                    originPosition: new THREE.Vector3(0,0,0),
-                    rapidSpeeds:{xy: 3, z: 2},
+                placementOrder: "XYZ",//used for raster strategy entry
+                camProcess: "gcode",
+                rapidHeight:3,
+                rapidHeightRelative: true,
+                safeHeight: 0.05,
+                originPosition: new THREE.Vector3(0,0,0),
+                rapidSpeeds:{xy: 3, z: 2},
                 feedRate:{xy: 0.1, z: 0.1}
-            },
-            staplerDual: null
+            }
         },
 
         allScripts: {
diff --git a/js/simulation/electronics/eCell.js b/js/simulation/electronics/eCell.js
new file mode 100644
index 00000000..9ae6b0d7
--- /dev/null
+++ b/js/simulation/electronics/eCell.js
@@ -0,0 +1,3 @@
+/**
+ * Created by aghassaei on 6/29/15.
+ */
diff --git a/js/simulation/electronics/eSim.js b/js/simulation/electronics/eSim.js
new file mode 100644
index 00000000..9ae6b0d7
--- /dev/null
+++ b/js/simulation/electronics/eSim.js
@@ -0,0 +1,3 @@
+/**
+ * Created by aghassaei on 6/29/15.
+ */
diff --git a/js/simulation/electronics/eSimEngine.js b/js/simulation/electronics/eSimEngine.js
new file mode 100644
index 00000000..9ae6b0d7
--- /dev/null
+++ b/js/simulation/electronics/eSimEngine.js
@@ -0,0 +1,3 @@
+/**
+ * Created by aghassaei on 6/29/15.
+ */
diff --git a/js/three/ThreeView.js b/js/three/ThreeView.js
index 242fb786..86b6285d 100644
--- a/js/three/ThreeView.js
+++ b/js/three/ThreeView.js
@@ -68,8 +68,10 @@ define(['underscore', 'backbone', 'three', 'appState', 'globals', 'lattice', 'or
             if (appState.get("currentTab") == "cam" && appState.get("manualSelectOrigin")){
                 var position = globals.highlighter.getHighlightedObjectPosition();
                 if (position){
-                    globals.cam.set("originPosition", position);
-                    appState.set("manualSelectOrigin", false);
+                    require(['cam'], function(cam){
+                        cam.set("originPosition", position);
+                        appState.set("manualSelectOrigin", false);
+                    });
                     return;
                 }
             }
-- 
GitLab