Index: /js/standard_expdef_demo/index.html
===================================================================
--- /js/standard_expdef_demo/index.html	(revision 1325)
+++ /js/standard_expdef_demo/index.html	(revision 1326)
@@ -5,26 +5,78 @@
     <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
     <link rel="stylesheet" type="text/css" href="static/styles.css">
-		<title>Standard.expdef Animation</title>
+		<title>Standard.expdef demo animation</title>
+	<script type="importmap">
+		{
+			"imports": {
+				"three": "./node_modules/three/build/three.module.js",
+				"three/addons/OrbitControls.js": "./node_modules/three/examples/jsm/controls/OrbitControls.js",
+				"three/addons/CSS3DRenderer.js": "./node_modules/three/examples/jsm/renderers/CSS3DRenderer.js",
+				"three/addons/Sky.js": "./node_modules/three/examples/jsm/objects/Sky.js",
+				"tween": "./node_modules/three/examples/jsm/libs/tween.module.js"
+			}
+		}
+	</script>
+	<script type="module">
+		import * as TWEEN from 'tween';
+		import * as THREE from 'three';
+		import {OrbitControls} from "three/addons/OrbitControls.js";
+		import {CSS3DObject, CSS3DSprite, CSS3DRenderer} from "three/addons/CSS3DRenderer.js";
+		import {Sky} from "three/addons/Sky.js";
+
+		// this trick is done to avoid refactoring the entire app
+		window.THREE = THREE;
+		window.Sky = Sky;
+		window.OrbitControls = OrbitControls;
+		window.CSS3DRenderer = CSS3DRenderer;
+		window.CSS3DObject = CSS3DObject;
+		window.CSS3DSprite = CSS3DSprite;
+		window.TWEEN = TWEEN;
+	</script>
+
+
+    
+		
 	</head>
 	<body style="margin: 0; overflow: hidden;">
-    <!--External dependencies-->
-		<script src="js/external/threejs/three.min.js"></script>
-    <script src="js/external/threejs/CSS3DRenderer.js"></script>
-    <script src="js/external/threejs/OrbitControls.js"></script>
-    <script src="js/external/threejs/Sky.js"></script>
-    <script src="js/external/tweenjs/tween.min.js"></script>
-    <script src="../sdk/frams-sdk.js"></script>
-    <script src="js/external/framsjs/visualization/jointmeshfactory.js"></script>
-    <script src="js/external/framsjs/visualization/partmeshfactory.js"></script>
-    <script src="js/external/framsjs/visualization/transformations.js"></script>
-    <!--Project sources-->
-    <script src="js/config.js"></script>
-    <script src="js/world/core.js"></script>
-    <script src="js/world/object/framstick.js"></script>
-    <script src="js/world/object/table.js"></script>
-    <script src="js/world/object/text.js"></script>
-    <script src="js/world/object/arrow.js"></script>
-    <script src="js/simulation/core.js"></script>
-		<script src="js/app.js"></script>
+		<div class="column controls">
+			<div class="row control-container" id="fitness-rater">
+				<span>Rate creature:</span>
+			</div>
+			<div class="row control-container">
+				<span>Genotype: </span>
+				<select id="genotype-selector">
+				</select>
+			</div>
+			
+		</div>
+		<!--External dependencies-->
+		
+		<!-- <script src="js/external/threejs/three.min.js"></script>
+		<script src="js/external/threejs/CSS3DRenderer.js"></script>
+		<script src="js/external/threejs/OrbitControls.js"></script>
+		<script src="js/external/threejs/Sky.js"></script> -->
+		<!-- <script src="js/external/tweenjs/tween.min.js"></script> -->
+		<script src="sdk/frams-sdk.js"></script>
+		<script src="js/external/framsjs/visualization/jointmeshfactory.js" defer></script>
+		<script src="js/external/framsjs/visualization/partmeshfactory.js" defer></script>
+		<script src="js/external/framsjs/visualization/transformations.js" defer></script>
+		<!--Project sources-->
+		<script src="js/config.js" defer></script>
+		<script src="js/utils.js" defer></script>
+		<script src="js/world/core.js" defer></script>
+		<script src="js/world/object/framstick.js" defer></script>
+		<script src="js/world/object/table.js"></script>
+		<script src="js/world/object/text.js" defer></script>
+		<script src="js/world/object/arrow.js" defer></script>
+		<script src="js/neuroviewer/view.js" defer></script>
+		<script src="js/neuroviewer/neurofactory.js" defer></script>
+		<script src="js/neuroviewer/neurons/basedrawableneuron.js" defer></script>
+		<script src="js/neuroviewer/neurons/genericdrawableneuron.js" defer></script>
+		<script src="js/neuroviewer/neurons/receptordrawableneuron.js" defer></script>
+		<script src="js/components/slider.js" defer></script>
+		<script src="js/components/option.js" defer></script>
+		<script src="js/components/button.js" defer></script>
+		<script src="js/simulation/core.js" defer></script>
+		<script src="js/app.js" defer></script>
 	</body>
 </html>
Index: /js/standard_expdef_demo/js/app.js
===================================================================
--- /js/standard_expdef_demo/js/app.js	(revision 1325)
+++ /js/standard_expdef_demo/js/app.js	(revision 1326)
@@ -12,15 +12,103 @@
   constructor() {
     this.scene = this.Scene();
-    this.camera = this.Camera();
-    this.controls = this.Controls();
+	this.camera = this.Camera();
     this.webGLRenderer = this.WebGLRenderer();
+	this.cameraControls = this.CameraControls();
     this.css3DRenderer = this.CSS3DRenderer();
 
-    this.simulation = new Simulation(new World(this.camera, this.scene));
+	this.args = this.parseArguments();
+	Config.Simulation.GENOTYPE = this.args["genotype_format"]?this.args["genotype_format"]:Config.Simulation.GENOTYPE;
+    this.simulation = new Simulation(new World(this.camera, this.scene),this.args);
 
     document.body.appendChild(this.webGLRenderer.domElement);
     document.body.appendChild(this.css3DRenderer.domElement);
     window.addEventListener("resize", this.onWindowResize.bind(this), false);
-    return this;
+
+	this.Controls();
+	this.Options();
+	this.NeuroView();
+	this.FitnessRater();
+  }
+
+  NeuroView(){
+	var thisApp = this;
+	window.addEventListener('DOMContentLoaded',()=>{
+		var neuroViewer = NeuroViewerView( Config.NeuroViewer );
+		thisApp.simulation.neuroViewer = neuroViewer;
+		neuroViewer.make3D();
+	})
+  }
+
+  Controls(){
+	var thisApp = this;
+	window.addEventListener('DOMContentLoaded', () => {
+		const controls = document.getElementsByClassName('controls')[0];
+		thisApp.mutation_slider = new Slider(
+			controls,
+			"Mutation",
+			function(prob){
+				thisApp.simulation.setMutationProb(parseFloat(prob));
+			});
+		thisApp.crossover_slider = new Slider(
+			controls,
+			"Crossover",
+			function(prob){
+				thisApp.simulation.setCrossoverProb(parseFloat(prob));
+			});
+		thisApp.simulation.mutationListeners.push(thisApp.mutation_slider);
+		thisApp.simulation.crossoverListeners.push(thisApp.crossover_slider);
+		thisApp.simulation.reupdateListeners();
+		return this;
+	});
+  }
+
+  Options(){
+	const encodings = this.findEncodings();
+
+	var thisApp = this;
+	window.addEventListener('DOMContentLoaded', () => {
+		const selector = document.getElementById("genotype-selector");
+		for(let i=0;i<encodings.length;i++){
+			new Option(selector,encodings[i]);
+		}
+		selector.onchange = function(){
+			thisApp.simulation.setProposedGenotype(`/*${this.value}*/`);
+			// let url = new URL(window.location.href);
+			// let params = new URLSearchParams(url.search);
+			// let paramName = "genotype_format"; 
+			// let paramValue = `/*${this.value}*/`;
+
+			// if(params.has(paramName)){
+			// 	params.set(paramName,paramValue);
+			// }else{
+			// 	params.append(paramName,paramValue);
+			// }
+			// window.location.href = window.location.origin+'/?'+params.toString();
+		}
+	});
+  }
+
+  FitnessRater(){
+	var sim = this.simulation;
+	window.addEventListener('DOMContentLoaded', ()=>{
+		const rater = document.getElementById("fitness-rater");
+		const thumbUp = new Button(rater,"👍",()=>{
+			sim.updateFitness(5);
+		});
+		const thumbDown = new Button(rater,"👎",()=>{
+			sim.updateFitness(-5);
+		})
+
+		sim.buttons.push(thumbUp);
+		sim.buttons.push(thumbDown);
+	});
+  }
+
+  findEncodings(){
+	const functionName = "GenoConv_f";
+	return Object
+	.keys(Module) //framsticks module
+	.filter((k)=>{return k.startsWith(functionName);})
+	.map((k)=>{return k.replace(functionName,"")[0]});
   }
 
@@ -44,9 +132,9 @@
   }
 
-  Controls() {
+  CameraControls() {
     /**
      * Creates a new Control object alowing to steer the camera.
      */
-    let controls = new THREE.OrbitControls(this.camera);
+    let controls = new OrbitControls(this.camera,this.webGLRenderer.domElement );
     controls.autoRotate = Config.Controls.AUTO_ROTATE;
     controls.autoRotateSpeed = Config.Controls.AUTO_ROTATE_SPEED;
@@ -54,4 +142,5 @@
     controls.maxDistance = Config.Controls.MAX_DISTANCE;
     controls.maxPolarAngle = Config.Controls.MAX_POLAR_ANGLE;
+	controls.enableKeys = false;
     controls.update();
     return controls
@@ -77,8 +166,9 @@
      * Creates a CSS3D Renderer object used to visualize HTML+CSS components in 3D scene.
      */
-    let renderer = new THREE.CSS3DRenderer();
+    let renderer = new CSS3DRenderer();
     renderer.setSize(Config.CSS3DRenderer.WIDTH, Config.CSS3DRenderer.HEIGHT);
     renderer.domElement.style.position = Config.CSS3DRenderer.POSITION;
     renderer.domElement.style.top = Config.CSS3DRenderer.TOP;
+	renderer.domElement.style.setProperty('pointer-events','none','');
     return renderer
   }
@@ -98,5 +188,5 @@
     requestAnimationFrame(this.render.bind(this));
     TWEEN.update();
-    this.controls.update();
+    this.cameraControls.update();
     this.webGLRenderer.render(this.scene, this.camera);
     this.css3DRenderer.render(this.scene, this.camera);
@@ -112,4 +202,18 @@
     this.css3DRenderer.setSize(window.innerWidth, window.innerHeight);
   }
+
+  parseArguments() {
+	/**
+	 * Parses URL arguemnts
+	 */
+
+	const queryString = window.location.search;
+	const urlParams = new URLSearchParams(queryString);
+	return {
+		"mutation_prob" : parseFloat(urlParams.get("mutation_prob")),
+		"crossover_prob" : parseFloat(urlParams.get("crossover_prob")),
+		"genotype_format": urlParams.get("genotype_format")
+	};
+  }
 }
 
Index: /js/standard_expdef_demo/js/components/button.js
===================================================================
--- /js/standard_expdef_demo/js/components/button.js	(revision 1326)
+++ /js/standard_expdef_demo/js/components/button.js	(revision 1326)
@@ -0,0 +1,28 @@
+class Button{
+
+	inactiveClass = "inactive";
+
+	constructor(element, text, callback){
+		this.parent = element;
+		this.text = text;
+		this.callback = callback;
+		this.htmlString = `
+			 <button type="button" class="rater-button control-container ${this.inactiveClass}">${text}</button> 
+		`
+
+		const parser = new DOMParser();
+		const doc = parser.parseFromString(this.htmlString, 'text/html');
+		this.DOMhtml = doc.body.firstChild;
+		this.parent.appendChild(this.DOMhtml);
+
+		this.DOMhtml.onclick = callback;
+	}
+
+	activate(){
+		this.DOMhtml.classList.remove(this.inactiveClass);
+	}
+
+	deactivate(){
+		this.DOMhtml.classList.add(this.inactiveClass);
+	}
+}
Index: /js/standard_expdef_demo/js/components/option.js
===================================================================
--- /js/standard_expdef_demo/js/components/option.js	(revision 1326)
+++ /js/standard_expdef_demo/js/components/option.js	(revision 1326)
@@ -0,0 +1,25 @@
+class Option{
+	constructor(element, genotype){
+		this.parent = element;
+		this.genotype = genotype;
+		this.fullGenotype = `/*${this.genotype}*/`
+
+		const funcName = Object
+			.keys(Module) //framsticks module
+			.filter((k)=>{return k.startsWith("GenoConv_f"+this.genotype);})[0];
+		const genoConv = new Module[funcName]();
+		const genoConvHelper = new Module.GenoConvHelper(genoConv);
+
+		this.genotypeDesc = genoConvHelper.getName();
+		this.htmlString = `
+			<option value="${this.genotype}" ${this.fullGenotype===Config.Simulation.GENOTYPE?"selected":""}>f${this.genotype} (${this.genotypeDesc})</option>
+		`;
+
+		const parser = new DOMParser();
+		const doc = parser.parseFromString(this.htmlString, 'text/html');
+		this.DOMhtml = doc.body.firstChild;
+		this.parent.appendChild(this.DOMhtml);
+		Module.destroy(genoConv);
+		Module.destroy(genoConvHelper);
+	}
+}
Index: /js/standard_expdef_demo/js/components/slider.js
===================================================================
--- /js/standard_expdef_demo/js/components/slider.js	(revision 1326)
+++ /js/standard_expdef_demo/js/components/slider.js	(revision 1326)
@@ -0,0 +1,41 @@
+class Slider{
+
+	constructor(element,name,setFunc){
+		this.htmlId = `${name.toLowerCase()}_slider`
+		this.htmlValueId = `${name.toLowerCase()}_value`
+		this.min = 0;
+		this.max = 1;
+		this.step = 0.01;
+		this.value = (this.min+this.max)/2;
+		this.htmlString = `
+			<div class="column control-container">
+				<div class="row"><span>${name} Probability: </span><input type="number" step="0.01" max="1" min="0" id=${this.htmlValueId} class="slider-value" value="${this.value}"></input></div>
+				<div class="row">
+					<span>${this.min}.0</span>
+					<input id="${this.htmlId}" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider" step="${this.step}">
+					<span>${this.max}.0</span>
+				</div>
+			</div>
+		`;
+		const parser = new DOMParser();
+		const doc = parser.parseFromString(this.htmlString, 'text/html');
+
+		this.DOMhtml = doc.body.firstChild;
+		this.parent = element;
+		this.parent.appendChild(this.DOMhtml);
+		this.DOMInput = document.getElementById(this.htmlId);
+		this.DOMValue = document.getElementById(this.htmlValueId);
+		this.DOMInput.oninput = function(){
+			setFunc(this.value);
+		}
+		this.DOMValue.oninput = function(){
+			setFunc(this.value);
+		}
+	}
+
+	update(value){
+		this.value = value;
+		this.DOMValue.value = roundNumber(this.value,2);
+		this.DOMInput.value = this.value;
+	}
+}
Index: /js/standard_expdef_demo/js/config.js
===================================================================
--- /js/standard_expdef_demo/js/config.js	(revision 1325)
+++ /js/standard_expdef_demo/js/config.js	(revision 1326)
@@ -11,12 +11,7 @@
     CROSSOVER_PROBABILITY: 0.3,
     EVOLUTION_MAX_REPETITIONS: 100,
-    GENOTYPES: [
-      "/*4*/ #5,<<X><<X>X>X>>LLX",
-      "/*4*/ <X>l<X>l<<X>X>LLLX",
-      "/*4*/ <,<,,<,X,,>X>X>X",
-      "/*4*/ <X><X><<X>X><X>X",
-      "/*4*/ <<X>RR<<X>X>X>X",
-      "/*4*/ <<X><<X>X>X>X",
-    ],
+	NUMBER_OF_GENOTYPES: 6,
+	INITIAL_MUTATIONS: 10,
+	GENOTYPE: "/*4*/",
 
     Timing: {
@@ -38,4 +33,5 @@
         FITNESS_TEXT: {x: 400, y: 300, z: 485},
         EVOLVED_GENOTYPE_PLANK: {x: 400, y: 240, z: 0},
+		NEURAL_NETWORK: {x: 400, y: 100, z: 300},
         EVOLVED_FITNESS_PLANK: {x: 400, y: 240, z: 380},
         MUTATION_GENOTYPE_PLANK: {x: 400, y: 400, z: 0},
@@ -83,10 +79,10 @@
   Light: {
     Ambient: {
-      COLOR: 0x8a8a8a
+      COLOR: 0xffffff
     },
 
     Directional: {
-      COLOR: 0xdfebff,
-      INTENSITY: 1,
+      COLOR: 0xffffff,
+      INTENSITY: 2,
       X_POS: 50,
       Y_POS: 200,
@@ -167,4 +163,15 @@
   },
 
+  NeuroViewer: {
+	layoutType: 2,
+	emptyLabel: "No neural network",
+	canvas: {
+	  id: "neuro-viewer-canvas",
+	  drawMarginInPx: 20,
+	  font: "14px Lucida Grande, sans-serif",
+	  strokeStyle: '#DEDEDE'
+	},
+  },
+
   Framstick: {
     COLOR: 0xcacaca,
@@ -174,4 +181,6 @@
     CAST_SHADOW: true,
 
+	
+
     Tween: {
       Scale: {
@@ -196,5 +205,5 @@
       PART: {
         defaultShape: {
-          radius: 0.213,
+          radius: Module.Part.prototype.BALL_AND_STICK_RADIUS,
           segments: 16
         },
@@ -206,5 +215,6 @@
       JOINT: {
         cylinderShape: {
-          radius: 0.1,
+		  thickness: 0.8,
+          radius: undefined, // if undefined -> depends on Part radius
           radiusSegments: 10,
           isTransparent: false,
@@ -239,5 +249,5 @@
       HEIGHT: 65,
       THICKNESS: 10,
-      TEXTURE: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/hardwood2_diffuse.jpg",
+      TEXTURE: "js/hardwood2_diffuse_brighter.jpg",
       REPEAT: 3,
       ANISOTROPY: 8,
@@ -264,5 +274,5 @@
       HEIGHT: 65,
       THICKNESS: 10,
-      TEXTURE: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/hardwood2_diffuse.jpg",
+      TEXTURE: "js/hardwood2_diffuse_brighter.jpg",
       REPEAT: 1,
       ANISOTROPY: 8,
@@ -288,5 +298,5 @@
     LENGTH: 100,
     FACES: 32,
-    TEXTURE:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/hardwood2_diffuse.jpg",
+    TEXTURE: "js/hardwood2_diffuse_brighter.jpg",
     REPEAT: 1,
     ANISOTROPY: 8,
@@ -323,2 +333,7 @@
   }
 };
+
+
+if (!Config.Framstick.Geometry.JOINT.cylinderShape.radius) {
+	Config.Framstick.Geometry.JOINT.cylinderShape.radius = Config.Framstick.Geometry.PART.defaultShape.radius * Config.Framstick.Geometry.JOINT.cylinderShape.thickness;
+}
Index: /js/standard_expdef_demo/js/external/framsjs/visualization/jointmeshfactory.js
===================================================================
--- /js/standard_expdef_demo/js/external/framsjs/visualization/jointmeshfactory.js	(revision 1325)
+++ /js/standard_expdef_demo/js/external/framsjs/visualization/jointmeshfactory.js	(revision 1326)
@@ -102,8 +102,8 @@
         let shape = joint.get_shape();
 
-        if (this.jointShapes['SHAPE_FIXED'].value == shape) {
-            result = this.getNewJointMesh(joint, this.config.linkShape);
+        if (this.jointShapes['SHAPE_STICK'].value == shape) {
+            result = this.getNewJointMesh(joint, this.config.cylinderShape);
         } else {
-            result = this.getNewJointMesh(joint, this.config.cylinderShape);
+			result = this.getNewJointMesh(joint, this.config.linkShape);
         }
 
Index: /js/standard_expdef_demo/js/external/framsjs/visualization/transformations.js
===================================================================
--- /js/standard_expdef_demo/js/external/framsjs/visualization/transformations.js	(revision 1325)
+++ /js/standard_expdef_demo/js/external/framsjs/visualization/transformations.js	(revision 1326)
@@ -17,5 +17,5 @@
     getPartShapes() {
         let shapes = [];
-        shapes["SHAPE_BALL_AND_STICK"] = { name: "Ball & Stick", value: Module.Part["SHAPE_BALL_AND_STICK"] };
+        shapes["SHAPE_BALL"] = { name: "Ball", value: Module.Part["SHAPE_BALL"] };
         shapes["SHAPE_ELLIPSOID"] = { name: "Elipsoid", value: Module.Part["SHAPE_ELLIPSOID"] };
         shapes["SHAPE_CUBOID"] = { name: "Cuboid", value: Module.Part["SHAPE_CUBOID"] };
@@ -30,6 +30,8 @@
     getJointShapes() {
         let shapes = [];
-        shapes["SHAPE_BALL_AND_STICK"] = { name: "Ball & Stick", value: Module.Joint["SHAPE_BALL_AND_STICK"] };
+        shapes["SHAPE_STICK"] = { name: "Stick", value: Module.Joint["SHAPE_STICK"] };
         shapes["SHAPE_FIXED"] = { name: "Fixed", value: Module.Joint["SHAPE_FIXED"] };
+		shapes["SHAPE_HINGE_X"] = { name: "Fixed", value: Module.Joint["SHAPE_HINGE_X"] };
+		shapes["SHAPE_HINGE_XY"] = { name: "Fixed", value: Module.Joint["SHAPE_HINGE_XY"] };
         return shapes;
     }
@@ -100,5 +102,5 @@
      */
     calcColorComponent(value) {
-        return THREE.Math.clamp(value, 0, 1);
+        return THREE.MathUtils.clamp(value, 0, 1);
     }
 
@@ -151,5 +153,5 @@
 
         let m = new THREE.Matrix4();
-        m.makeRotationZ(THREE.Math.degToRad(90));
+        m.makeRotationZ(THREE.MathUtils.degToRad(90));
 
         let m2 = new THREE.Matrix4();
@@ -242,5 +244,5 @@
                 part.get_scale().get_x(),
                 part.get_scale().get_z());
-        } else if (this.partShapes['SHAPE_BALL_AND_STICK'].value != shape) {
+        } else if (this.partShapes['SHAPE_BALL'].value != shape) {
             bodyElement.mesh.scale.set(
                 part.get_scale().get_x(),
Index: /js/standard_expdef_demo/js/neuroviewer/neurofactory.js
===================================================================
--- /js/standard_expdef_demo/js/neuroviewer/neurofactory.js	(revision 1326)
+++ /js/standard_expdef_demo/js/neuroviewer/neurofactory.js	(revision 1326)
@@ -0,0 +1,33 @@
+var NeuroFactory = function( config ) {
+
+  var neuroClassHints = getNeuroClassHints();
+
+  function getNeuroClassHints() {
+    var hints = [ ];
+    hints["Invisible"] = { name: "Invisible", value: Module.NeuroClass["Invisible"] };
+    hints["DontShowClass"] = { name: "DontShowClass", value: Module.NeuroClass["DontShowClass"] };
+    hints["AtFirstPart"] = { name: "AtFirstPart", value: Module.NeuroClass["AtFirstPart"] };
+    hints["AtSecondPart"] = { name: "AtSecondPart", value: Module.NeuroClass["AtSecondPart"] };
+    hints["EffectorClass"] = { name: "EffectorClass", value: Module.NeuroClass["EffectorClass"] };
+    hints["ReceptorClass"] = { name: "ReceptorClass", value: Module.NeuroClass["ReceptorClass"] };
+    hints["IsV1BendMuscle"] = { name: "V1BendMuscle", value: Module.NeuroClass["IsV1BendMuscle"] };
+    hints["IsV1RotMuscle"] = { name: "V1RotMuscle", value: Module.NeuroClass["IsV1RotMuscle"] };
+    hints["IsLinearMuscle"] = { name: "LinearMuscle", value: Module.NeuroClass["IsLinearMuscle"] };
+    return hints;
+  }
+
+  function create( x, y, w, h, neuroData ) {
+
+    var neuroClass = neuroData.getClass();
+    if( neuroClass.getVisualHints() === neuroClassHints["ReceptorClass"].value ) {
+      return new ReceptorDrawableNeuron(  x, y, w, h, neuroData, config );
+    }
+
+    return new GenericDrawableNeuron(  x, y, w, h, neuroData, config );
+
+  }
+
+  return {
+    create: create
+  }
+};
Index: /js/standard_expdef_demo/js/neuroviewer/neurons/basedrawableneuron.js
===================================================================
--- /js/standard_expdef_demo/js/neuroviewer/neurons/basedrawableneuron.js	(revision 1326)
+++ /js/standard_expdef_demo/js/neuroviewer/neurons/basedrawableneuron.js	(revision 1326)
@@ -0,0 +1,91 @@
+function BaseDrawableNeuron ( x, y, w, h, neuroData, config ) {
+
+  this.drawCoords = null;
+  this.inputsLayoutPositions = [];
+  this.inputLinkDrawPositions = [];
+  this.neuroData = neuroData;
+
+  this.layoutCoords = {
+    x: x,
+    y: y,
+    w: w,
+    h: h
+  };
+
+  this.calcConnectionLineCoords = function () {
+
+    return {
+      inputEndLineX: this.drawCoords.x + this.drawCoords.w * 0.2,
+      outputBeginLineX: this.drawCoords.x + this.drawCoords.w * 0.8,
+      outputLineY: this.drawCoords.y + this.drawCoords.h * 0.5
+    }
+
+  }
+
+  this.drawInputLines = function ( context, inputEndLineX ) {
+
+    var inputCount = neuroData.getInputCount();
+    for ( var i = 0; i < inputCount; ++i ) {
+
+      var inputH = (1 / (inputCount + 1) * this.drawCoords.h);
+      var inputLineY = this.drawCoords.y + inputH * (i + 1);
+      context.beginPath();
+      context.moveTo( inputEndLineX, inputLineY );
+      context.lineTo( this.drawCoords.x, inputLineY );
+      context.lineTo( this.inputLinkDrawPositions[ i ].x, this.inputLinkDrawPositions[ i ].y );
+      context.stroke();
+
+    }
+
+  }
+
+  this.update = function ( canvasWidth, canvasHeight, bounds ) {
+
+    var offset = config.drawMarginInPx * 2;
+
+    var scaleW = (canvasWidth - offset) / bounds.width;
+    var scaleH = (canvasHeight - offset) / bounds.height;
+    var scale = Math.min( scaleW, scaleH );
+
+    var posX = (Math.abs(this.layoutCoords.x - bounds.minX) / bounds.width) * scale * bounds.width;
+    var posY = (Math.abs(this.layoutCoords.y - bounds.minY) / bounds.height) * scale * bounds.height;
+
+    this.drawCoords = {
+      x: posX + config.drawMarginInPx,
+      y: posY + config.drawMarginInPx,
+      w: this.layoutCoords.w * scale,
+      h: this.layoutCoords.h * scale
+    }
+
+    this.inputLinkDrawPositions = [];
+    for ( var i = 0; i < this.inputsLayoutPositions.length; ++i ) {
+
+      var inputX = (Math.abs( this.inputsLayoutPositions[ i ].x - bounds.minX ) / bounds.width) * scale * bounds.width;
+      var inputY = (Math.abs( this.inputsLayoutPositions[ i ].y - bounds.minY ) / bounds.height) * scale * bounds.height;
+
+      this.inputLinkDrawPositions[ i ] = {
+        x: inputX + this.inputsLayoutPositions[ i ].w * scale + config.drawMarginInPx,
+        y: inputY + this.inputsLayoutPositions[ i ].h * 0.5 * scale + config.drawMarginInPx,
+      }
+
+    }
+
+  }
+
+  this.draw = function ( context ) {
+
+    if ( this.drawCoords != null ) {
+      context.strokeStyle = config.strokeStyle;
+
+      var connCoords = this.calcConnectionLineCoords();
+      this.drawInputLines( context, connCoords.inputEndLineX );
+
+      if( typeof this.drawNeuron === "function" ) {
+        this.drawNeuron( context, connCoords );
+      }
+
+    }
+
+  }
+
+};
Index: /js/standard_expdef_demo/js/neuroviewer/neurons/genericdrawableneuron.js
===================================================================
--- /js/standard_expdef_demo/js/neuroviewer/neurons/genericdrawableneuron.js	(revision 1326)
+++ /js/standard_expdef_demo/js/neuroviewer/neurons/genericdrawableneuron.js	(revision 1326)
@@ -0,0 +1,20 @@
+function GenericDrawableNeuron ( x, y, w, h, neuroData, config ) {
+
+  BaseDrawableNeuron.call( this, x, y, w, h, neuroData, config );
+
+  this.drawNeuron = function ( context, connCoords ) {
+
+    context.beginPath();
+    context.moveTo( connCoords.outputBeginLineX, connCoords.outputLineY );
+    context.lineTo( connCoords.inputEndLineX, this.drawCoords.y );
+    context.lineTo( connCoords.inputEndLineX, this.drawCoords.y + this.drawCoords.h );
+    context.lineTo( connCoords.outputBeginLineX, connCoords.outputLineY );
+    context.lineTo( this.drawCoords.x + this.drawCoords.w, connCoords.outputLineY );
+    context.stroke();
+
+  }
+
+};
+
+GenericDrawableNeuron.prototype = Object.create( BaseDrawableNeuron.prototype );
+GenericDrawableNeuron.prototype.constructor = GenericDrawableNeuron;
Index: /js/standard_expdef_demo/js/neuroviewer/neurons/receptordrawableneuron.js
===================================================================
--- /js/standard_expdef_demo/js/neuroviewer/neurons/receptordrawableneuron.js	(revision 1326)
+++ /js/standard_expdef_demo/js/neuroviewer/neurons/receptordrawableneuron.js	(revision 1326)
@@ -0,0 +1,22 @@
+function ReceptorDrawableNeuron ( x, y, w, h, neuroData, config ) {
+
+  BaseDrawableNeuron.call( this, x, y, w, h, neuroData, config );
+
+  this.drawNeuron = function ( context, connCoords ) {
+      context.beginPath();
+      context.moveTo( connCoords.outputBeginLineX, this.drawCoords.y + this.drawCoords.h * 0.25 );
+      context.lineTo( connCoords.outputBeginLineX, this.drawCoords.y + this.drawCoords.h * 0.75 );
+      context.lineTo( this.drawCoords.x + this.drawCoords.w * 0.25, this.drawCoords.y + this.drawCoords.h * 0.75 );
+      context.lineTo( this.drawCoords.x + this.drawCoords.w * 0.5, this.drawCoords.y + this.drawCoords.h * 0.5 );
+      context.lineTo( this.drawCoords.x + this.drawCoords.w * 0.25, this.drawCoords.y + this.drawCoords.h * 0.25 );
+      context.lineTo( connCoords.outputBeginLineX, this.drawCoords.y + this.drawCoords.h * 0.25 );
+
+      context.moveTo( connCoords.outputBeginLineX, connCoords.outputLineY );
+      context.lineTo( this.drawCoords.x + this.drawCoords.w, connCoords.outputLineY );
+      context.stroke();
+  }
+
+};
+
+ReceptorDrawableNeuron.prototype = Object.create( BaseDrawableNeuron.prototype );
+ReceptorDrawableNeuron.prototype.constructor = ReceptorDrawableNeuron;
Index: /js/standard_expdef_demo/js/neuroviewer/view.js
===================================================================
--- /js/standard_expdef_demo/js/neuroviewer/view.js	(revision 1326)
+++ /js/standard_expdef_demo/js/neuroviewer/view.js	(revision 1326)
@@ -0,0 +1,165 @@
+var NeuroViewerView = (function( config )
+{
+
+  var objectsToDraw = [];
+  var bounds = null;
+
+  var container = document.createElement( 'div' );
+  container.className = "neuro-viewer-container";
+  var canvas = document.createElement( 'canvas' );
+  canvas.id = config.canvas.id;
+  var context = canvas.getContext( '2d' );
+  container.appendChild( canvas );
+
+  var screenWidth = canvas.width;
+  var screenHeight = canvas.height;
+  var devicePixelRatio = (window.devicePixelRatio || 1);
+  var backingStoreRatio = context.webkitBackingStorePixelRatio ||
+      context.mozBackingStorePixelRatio ||
+      context.msBackingStorePixelRatio ||
+      context.oBackingStorePixelRatio ||
+      context.backingStorePixelRatio || 1;
+
+  var screenRatio = devicePixelRatio / backingStoreRatio;
+
+  var mesh = create3DContainer();
+
+  function resize( width, height ) {
+    screenWidth = width;
+    screenHeight = height;
+
+    canvas.width = width * screenRatio;
+    canvas.height = height * screenRatio;
+
+    canvas.style.width = width + 'px';
+    canvas.style.height = height + 'px';
+
+    context.scale(screenRatio, screenRatio);
+
+    render();
+  }
+  function make2D(){
+	container.id = "neuro-viewer-2d";
+	document.body.appendChild(container);
+  }
+
+  function make3D(){
+	container.id = "neuro-viewer-3d";
+  }
+
+  function render() {
+    clear();
+	context.fillStyle = "transparent";
+	context.fillRect(0, 0, canvas.width, canvas.height);
+
+    if( objectsToDraw.length === 0 ) {
+      context.font = config.canvas.font;
+      context.fillStyle = config.canvas.strokeStyle;
+      context.fillText( config.emptyLabel, 12, 22 );
+    }
+
+    if( bounds != null ) {
+      for( var i=0; i<objectsToDraw.length; ++i ) {
+        objectsToDraw[i].update( screenWidth, screenHeight, bounds );
+        objectsToDraw[i].draw( context );
+      }
+    }
+  }
+
+  function getNeuroLayoutBounds( data ) {
+
+    var result = { minX: null, maxX: null, minY: null, maxY: null };
+
+    for( var i=0; i<data.getElements(); i++ ) {
+
+      var xywh=data.getValueXYWH(i);
+      if( (result.minX == null) || (result.minX > xywh.get_x()) ) {
+        result.minX = xywh.get_x();
+      }
+      var xw = xywh.get_x() + xywh.get_w();
+      if( (result.maxX == null) || (result.maxX < xw)  ) {
+        result.maxX = xw;
+      }
+      if( (result.minY == null) || (result.minY > xywh.get_y()) ) {
+        result.minY = xywh.get_y();
+      }
+      var yh = xywh.get_y() + xywh.get_h();
+      if( (result.maxY == null) || (result.maxY < yh)  ) {
+        result.maxY = yh;
+      }
+
+    }
+
+    result.width = Math.abs( result.maxX - result.minX );
+    result.height = Math.abs( result.maxY - result.minY );
+    return result;
+  }
+
+  function updateBrain( data ) {
+
+    objectsToDraw = [];
+    bounds = getNeuroLayoutBounds( data );
+
+    var neuroFactory = new NeuroFactory( config.canvas );
+    for( var i=0; i<data.getElements(); i++ ) {
+
+      var xywh=data.getValueXYWH(i);
+      var neuro = neuroFactory.create( xywh.get_x(), xywh.get_y(), xywh.get_w(), xywh.get_h(), data.getNeuro(i) );
+      objectsToDraw.push( neuro );
+
+      for( var j=0; j<data.getNeuro(i).getInputCount(); j++ ) {
+        var inputRefNo = data.getNeuro(i).getInput(j).get_refno();
+        var inputCoords = data.getValueXYWH(inputRefNo);
+
+        neuro.inputsLayoutPositions.push( {
+          x: inputCoords.get_x(),
+          y: inputCoords.get_y(),
+          w: inputCoords.get_w(),
+          h: inputCoords.get_h()
+        } );
+      }
+    }
+
+    render();
+  }
+
+  function create3DContainer(){
+	var neuro3d = new CSS3DObject(container);
+	neuro3d.position.set(0,0,0);
+	neuro3d.rotation.set(0,0,0);
+	return neuro3d;
+  }
+
+  function move(position) {
+    let tweenPlank = new TWEEN.Tween(mesh.position).to(position, Config.Table.GenotypePlank.Tween.Move.SPEED);
+    tweenPlank.easing(Config.Table.GenotypePlank.Tween.Move.EASING);
+    tweenPlank.start();
+  }
+
+  function rotate(angle) {
+    let tweenPlank = new TWEEN.Tween(mesh.rotation).to(angle, Config.Table.GenotypePlank.Tween.Rotate.SPEED);
+    tweenPlank.easing(Config.Table.GenotypePlank.Tween.Rotate.EASING);
+    tweenPlank.start();
+  }
+
+
+  function clear(){
+	context.clearRect(0, 0, canvas.width, canvas.height);
+  }
+
+  function get3DContainer(){
+	return mesh;
+  }
+
+  return {
+    resize: resize,
+	clear: clear,
+	updateBrain: updateBrain,
+	get3DContainer: get3DContainer,
+	make2D: make2D,
+	make3D: make3D,
+	move: move,
+	rotate: rotate,
+  }
+
+});
Index: /js/standard_expdef_demo/js/simulation/core.js
===================================================================
--- /js/standard_expdef_demo/js/simulation/core.js	(revision 1325)
+++ /js/standard_expdef_demo/js/simulation/core.js	(revision 1326)
@@ -10,6 +10,7 @@
    */
 
-  constructor(world) {
+  constructor(world, args) {
     this.world = world;
+	this.buttons = [];
 
     this.genPoolText = this.getText("Genotype Pool", EVOLUTION_METHOD_TEXT_POSITION);
@@ -22,4 +23,7 @@
     this.fitnessText = this.getText("Fitness", Config.Simulation.Element.Position.FITNESS_TEXT);
 
+	this.genotypeEncoding = Config.Simulation.GENOTYPE;
+	this.proposedGenotypeEncoding = undefined;
+
     this.world.scene.add(this.genPoolText);
     this.world.scene.add(this.mutationText);
@@ -31,6 +35,107 @@
     this.world.scene.add(this.fitnessText);
 
+	this.world.createTable(this.createGenotypes(Config.Simulation.NUMBER_OF_GENOTYPES,Config.Simulation.INITIAL_MUTATIONS),this.genotypeEncoding);
+
     this.state = State.INITIAL;
     this.timing = Config.Simulation.Timing.INITIAL;
+
+	this.mutationProb = 0;
+	this.mutationListeners = [];
+	this.setMutationProb(args.mutation_prob?args.mutation_prob:Config.Simulation.MUTATION_PROBABILITY);
+	
+	this.crossoverProb = 0;
+	this.crossoverListeners = [];
+	this.setCrossoverProb(args.crossover_prob?args.crossover_prob:Config.Simulation.CROSSOVER_PROBABILITY);
+
+	this.neuroLayoutModel = undefined;
+	this.neuroLayoutFunctionHelper = new Module.NNLayoutFunctionHelper();
+	this.neuroViewer = undefined;
+
+	this.evolvedFitness = 0;
+
+	this.lastTimeout = undefined;
+  }
+
+  activateButtons(){
+	for(let i=0;i<this.buttons.length;i++){
+		this.buttons[i].activate();
+	}
+  }
+
+  deactivateButtons(){
+	for(let i=0;i<this.buttons.length;i++){
+		this.buttons[i].deactivate();
+	}
+  }
+
+  updateListeners(list,value){
+	for(let i=0;i<list.length;i++){
+		list[i].update(value);
+	}
+  }
+
+  reupdateListeners(){
+	this.updateListeners(this.mutationListeners,this.mutationProb);
+	this.updateListeners(this.crossoverListeners,this.crossoverProb);
+  }
+
+  getMutationProb(){
+	return this.mutationProb;
+  }
+  setMutationProb(prob){
+	this.mutationProb = Math.min(Math.max(prob,0),1);
+	if(this.crossoverProb + this.mutationProb > 1){
+		this.setCrossoverProb(1 - this.mutationProb);
+	}
+	this.updateListeners(this.mutationListeners,this.mutationProb);
+  }
+
+  getCrossoverProb(){
+	return this.crossoverProb;
+  }
+  setCrossoverProb(prob){
+	this.crossoverProb = Math.min(Math.max(prob,0),1);
+	if(this.crossoverProb + this.mutationProb > 1){
+		this.setMutationProb(1 - this.crossoverProb);
+	}
+	this.updateListeners(this.crossoverListeners,this.crossoverProb);
+  }
+
+  updateNeuroLayoutModel(model) {
+    if( this.neuroLayoutModel ) {
+      Module.destroy( this.neuroLayoutModel );
+    }
+    this.neuroLayoutModel = new Module.NNLayoutState_Model_Fred( model );
+    this.neuroLayoutFunctionHelper.doLayout( Config.NeuroViewer.layoutType , this.neuroLayoutModel );
+  }
+
+  getBrainData (model) {
+	var thisSim = this;
+    return {
+      getElements: function () {
+        return thisSim.neuroLayoutModel.GetElements();
+      },
+      getValueXYWH: function ( i ) {
+        return thisSim.neuroLayoutModel.GetValueXYWH( i );
+      },
+      getNeuro: function ( i ) {
+        return model.getNeuro( i );
+      }
+    };
+  }
+
+  updateFitness(value){
+	// if (this.state !== State.SHOW_FRAMSTICK && this.state !== State.DESTROY_FRAMSTICK){
+	// 	return;
+	// }
+	this.evolvedFitness += value;
+	this.evolvedFitness = Math.max(this.evolvedFitness,0);
+	if(this.evolvedFitnessPlank){
+		this.evolvedFitnessPlank.updateFitness(this.evolvedFitness);
+	}
+  }
+
+  isGenotypeChanging(){
+	return this.proposedGenotypeEncoding && this.proposedGenotypeEncoding !== this.genotypeEncoding;
   }
 
@@ -43,4 +148,9 @@
         this.state = State.EVOLUTION_METHOD_SELECTION;
         this.timing = Config.Simulation.Timing.INITIAL;
+
+		if(this.isGenotypeChanging()){
+			this.state = State.CHANGE_GENOTYPE;
+		}
+
         break;
 
@@ -50,8 +160,8 @@
         this.timing = Config.Simulation.Timing.EVOLUTION_METHOD_SELECTION;
         let randomVal = Math.random()
-        if (randomVal < Config.Simulation.MUTATION_PROBABILITY) {
+        if (randomVal < this.mutationProb) {
           this.state = State.MUTATION_GENOTYPE_SELECTION;
-        } else if (randomVal < Config.Simulation.MUTATION_PROBABILITY +
-                               Config.Simulation.CROSSOVER_PROBABILITY){
+        } else if (randomVal < this.mutationProb +
+                               this.crossoverProb){
           this.state = State.CROSSOVER_GENOTYPE_SELECTION;
         } else {
@@ -65,5 +175,5 @@
         this.hideText(this.genPoolText);
 
-        this.mutationIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
+        this.mutationIdx = this.chooseIdx();
         this.mutationArrow = this.getArrow(this.mutationIdx).mesh;
         this.world.scene.add(this.mutationArrow);
@@ -100,5 +210,5 @@
         this.hideText(this.genPoolText);
 
-        this.cloningIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
+        this.cloningIdx = this.chooseIdx();
         this.cloningArrow = this.getArrow(this.cloningIdx).mesh;
         this.world.scene.add(this.cloningArrow);
@@ -135,7 +245,7 @@
         this.hideText(this.genPoolText);
 
-        this.crossoverIdx1 = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
+        this.crossoverIdx1 = this.chooseIdx();
         do {
-          this.crossoverIdx2 = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
+          this.crossoverIdx2 = this.chooseIdx();
         } while (this.crossoverIdx1 == this.crossoverIdx2);
 
@@ -175,9 +285,14 @@
 
       case State.SHOW_FRAMSTICK:
+		this.activateButtons();
         this.moveCamera(Config.Simulation.Camera.Position.FRAMSTICK);
-
+		
         this.evolvedFramstick = new Framstick(this.evolvedGenotype);
+		const model = this.evolvedFramstick.getModelFromGenotype(this.evolvedGenotype);
         this.world.scene.add(this.evolvedFramstick.mesh);
-
+		
+		this.updateNeuroLayoutModel(model);
+		this.neuroViewer.updateBrain(this.getBrainData(model));
+		Module.destroy(model);
         this.timing = Config.Simulation.Timing.SHOW_FRAMSTICK;
         this.state = State.DESTROY_FRAMSTICK;
@@ -187,4 +302,6 @@
         this.evolvedFramstick.scaleUpSize = 0.01;
         this.evolvedFramstick.scaleDownSize = 0.01;
+		this.neuroViewer.clear();
+		this.world.scene.remove(this.neuroViewer.get3DContainer());
 
         this.showText(this.fitnessText);
@@ -195,6 +312,7 @@
         this.evolvedFitnessPlank.move(Config.Simulation.Element.Position.EVOLVED_FITNESS_PLANK);
         this.evolvedFitnessPlank.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
-        this.world.scene.add(this.evolvedFitnessPlank.mesh)
-        this.world.scene.add(this.evolvedFitnessPlank.textMesh)
+        this.world.scene.add(this.evolvedFitnessPlank.mesh);
+        this.world.scene.add(this.evolvedFitnessPlank.textMesh);
+
 
         this.timing = Config.Simulation.Timing.DESTROY_FRAMSTICK;
@@ -207,19 +325,134 @@
         }
         break;
+	case State.CHANGE_GENOTYPE:
+		this.genotypeEncoding = this.proposedGenotypeEncoding;
+		this.world.setGenotypes(this.createGenotypes(Config.Simulation.NUMBER_OF_GENOTYPES,Config.Simulation.INITIAL_MUTATIONS),this.genotypeEncoding);
+		this.proposedGenotypeEncoding = undefined;
+
+		this.state = State.INITIAL;
+		break;
     }
-
-    setTimeout(this.run.bind(this), this.timing);
-  }
-
-  getMutatedGenotype(genotype) {
-    let genoF4 = new Module.Geno_f4();
-    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoF4);
+	if(this.isGenotypeChanging()){
+		this.timing = 0;
+	}
+    this.lastTimeout = setTimeout(this.run.bind(this), this.timing);
+  }
+
+  setProposedGenotype(proposed){
+	this.proposedGenotypeEncoding = proposed;
+	if (this.lastTimeout){
+		clearTimeout(this.lastTimeout);
+		this.run();
+	}
+  }
+
+  chooseIdx(){
+	return this.weightedChoice();
+  }
+
+  randomChoice(){
+	return parseInt(Math.random() * Config.Simulation.NUMBER_OF_GENOTYPES);
+  }
+
+  weightedChoice(){
+	const fitness = this.world.table.fitnessPlanks
+					.map((k)=>{
+						return parseFloat(k.fitness)+0.0001;
+					});
+	const fitness_sum = fitness.reduce((partialSum, a) => partialSum + a, 0);
+	const probs = fitness
+					.map((k)=>{
+						return k/fitness_sum;
+					});
+
+	var prob = Math.random();
+	for(let i=0;i<probs.length;i++){
+		if(prob < probs[i]){
+			return i;
+		}
+		prob -= probs[i];
+	}
+	return -1;
+  }
+
+  createGenotypes(n,mutation_count){
+	var func = this.getOperator(this.genotypeEncoding);
+    let genoOper = new func();
+    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoOper);
+	var genotypes = [];
+
+	for(let i=0;i<n;i++){
+		var genotype = genoOperatorsHelper.getSimplest();
+		genotypes.push(this.mutate(genotype,genoOperatorsHelper,mutation_count));
+	}
+
+	return genotypes;
+  }
+
+  getOperator(genoName){
+	const genoType = genoName.replace("/*","").replace("*/","");
+	var func = Module[`Geno_f${genoType}`];
+	func = func?func:Module[`GenoOper_f${genoType}`];
+	return func;
+  }
+
+  getMutatedGenotype(genotype){
+	var func = this.getOperator(this.genotypeEncoding);
+    let genoOper = new func();
+    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoOper);
+	genotype = this.mutate(genotype,genoOperatorsHelper,1);
+	Module.destroy(genoOper);
+    Module.destroy(genoOperatorsHelper);
+    return genotype;
+  }
+
+  mutate(genotype,genoOperatorsHelper,times) {
+	for(let i = 0;i<times;i++){
+		genotype = this.tryMutation(genotype,genoOperatorsHelper);
+	}
+	return genotype;
+  }
+
+  tryMutation(genotype,genoOperatorsHelper){
+	let genetics = new Module.PreconfiguredGenetics();
+    let iteration = 0;
+	do {
+		if (genoOperatorsHelper.mutate(genotype.replace(this.genotypeEncoding, "")) == 0) {
+		  let mutated = genoOperatorsHelper.getLastMutateGeno().c_str();
+	  let newGenotype = `${this.genotypeEncoding}` + mutated;
+  
+		  let stringObj = new Module.SString();
+		  stringObj.set(newGenotype);
+		  let genoObj = new Module.Geno(stringObj);
+  
+		  if (genoObj.isValid()) {
+			genotype = newGenotype;
+			iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
+		  }
+  
+		  Module.destroy(stringObj);
+		  Module.destroy(genoObj);
+		} else {
+		  iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
+		}
+		iteration += 1;
+	  } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
+
+	  return genotype;
+  }
+
+  getCrossoveredGenotype(genotype1, genotype2) {
+	var func = this.getOperator(this.genotypeEncoding);
+    let genoOper = new func();
+    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoOper);
     let genetics = new Module.PreconfiguredGenetics();
     let iteration = 0;
 
     do {
-      if (genoOperatorsHelper.mutate(genotype.replace("/*4*/", "")) == 0) {
-        let mutated = genoOperatorsHelper.getLastMutateGeno();
-	let newGenotype = "/*4*/ " + mutated;
+      if (genoOperatorsHelper.crossOver(genotype1.replace(this.genotypeEncoding, ""),
+                                        genotype2.replace(this.genotypeEncoding, "")) == 0) {
+        let crossovered = genoOperatorsHelper.getLastCrossGeno1().c_str();
+        let newGenotype = `${this.genotypeEncoding}` + crossovered;
+
 
         let stringObj = new Module.SString();
@@ -228,5 +461,5 @@
 
         if (genoObj.isValid()) {
-          genotype = newGenotype;
+          genotype1 = newGenotype;
           iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
         }
@@ -240,39 +473,5 @@
     } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
 
-    Module.destroy(genoF4);
-    Module.destroy(genoOperatorsHelper);
-    return genotype;
-  }
-
-  getCrossoveredGenotype(genotype1, genotype2) {
-    let genoF4 = new Module.Geno_f4();
-    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoF4);
-    let genetics = new Module.PreconfiguredGenetics();
-    let iteration = 0;
-
-    do {
-      if (genoOperatorsHelper.crossOver(genotype1.replace("/*4*/", ""),
-                                        genotype2.replace("/*4*/", "")) == 0) {
-        let crossovered = genoOperatorsHelper.getLastCrossGeno1();
-        let newGenotype = "/*4*/ " + crossovered;
-
-        let stringObj = new Module.SString();
-        stringObj.set(newGenotype);
-        let genoObj = new Module.Geno(stringObj);
-
-        if (genoObj.isValid()) {
-          genotype1 = newGenotype;
-          iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
-        }
-
-        Module.destroy(stringObj);
-        Module.destroy(genoObj);
-      } else {
-        iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
-      }
-      iteration += 1;
-    } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
-
-    Module.destroy(genoF4);
+    Module.destroy(genoOper);
     Module.destroy(genoOperatorsHelper);
     return genotype1;
@@ -280,9 +479,13 @@
 
   showEvolutionResult() {
-    this.evolvedGenotypePlank = new GenotypePlank(this.evolvedGenotype, 10);
+    this.evolvedGenotypePlank = new GenotypePlank(this.evolvedGenotype, this.genotypeEncoding, 10);
     this.evolvedGenotypePlank.move(Config.Simulation.Element.Position.EVOLVED_GENOTYPE_PLANK);
     this.evolvedGenotypePlank.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
+
+	this.neuroViewer.move(Config.Simulation.Element.Position.NEURAL_NETWORK);
+    this.neuroViewer.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
     this.world.scene.add(this.evolvedGenotypePlank.mesh);
     this.world.scene.add(this.evolvedGenotypePlank.textMesh);
+	this.world.scene.add(this.neuroViewer.get3DContainer());
 
     if (this.evolutionMethod == State.MUTATION_GENOTYPE_SELECTION) {
@@ -302,5 +505,5 @@
 
   evolutionReturn() {
-    let replaceIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
+    let replaceIdx = parseInt(Math.random() * Config.Simulation.NUMBER_OF_GENOTYPES);
     let genotypePlank = this.world.table.genotypePlanks[replaceIdx];
     let fitnessPlank = this.world.table.fitnessPlanks[replaceIdx];
@@ -322,5 +525,7 @@
     this.world.table.genotypePlanks[replaceIdx] = this.evolvedGenotypePlank;
     this.world.table.fitnessPlanks[replaceIdx] = this.evolvedFitnessPlank;
+	this.evolvedFitnessPlank = undefined;
     this.hideText(this.fitnessText);
+	this.deactivateButtons();
   }
 
@@ -378,10 +583,11 @@
   "CROSSOVER_SIDE_VIEW": 9, "CROSSOVER_RESULT": 10, "CROSSOVER_RETURN": 11,
   "DESTROY_FRAMSTICK": 12, "CLONING_GENOTYPE_SELECTION": 13,
-  "CLONING_SIDE_VIEW": 14, "CLONING_RESULT": 15, "CLONING_RETURN": 16
+  "CLONING_SIDE_VIEW": 14, "CLONING_RESULT": 15, "CLONING_RETURN": 16,
+  "CHANGE_GENOTYPE": 17
 };
 
 var EVOLUTION_METHOD_TEXT_POSITION = {
   x: -210,
-  y: 80 + (Config.Table.FitnessPlank.HEIGHT + Config.Table.Board.SPACING) * (Config.Simulation.GENOTYPES.length + 1),
+  y: 80 + (Config.Table.FitnessPlank.HEIGHT + Config.Table.Board.SPACING) * (Config.Simulation.NUMBER_OF_GENOTYPES + 1),
   z: -500
 };
Index: /js/standard_expdef_demo/js/utils.js
===================================================================
--- /js/standard_expdef_demo/js/utils.js	(revision 1326)
+++ /js/standard_expdef_demo/js/utils.js	(revision 1326)
@@ -0,0 +1,9 @@
+function roundNumber(value,prec){
+	let number = parseFloat(value);
+	if (isNaN(number)) return value;
+
+	let factor = Math.pow(10, prec);
+	number = Math.round(number * factor) / factor;
+
+	return number;
+};
Index: /js/standard_expdef_demo/js/world/core.js
===================================================================
--- /js/standard_expdef_demo/js/world/core.js	(revision 1325)
+++ /js/standard_expdef_demo/js/world/core.js	(revision 1326)
@@ -17,5 +17,4 @@
     this.sky = this.Sky();
     this.sun = this.Sun();
-    this.table = this.Table();
   }
 
@@ -25,6 +24,7 @@
     texture.repeat.set(Config.Ground.REPEAT, Config.Ground.REPEAT);
     texture.anisotropy = Config.Ground.ANISOTROPY;
+	texture.colorSpace = THREE.SRGBColorSpace;
 
-    let geometry = new THREE.PlaneBufferGeometry(Config.Ground.WIDTH, Config.Ground.WIDTH);
+    let geometry = new THREE.PlaneGeometry(Config.Ground.WIDTH, Config.Ground.WIDTH);
     let material = new THREE.MeshLambertMaterial({map: texture});
     let ground = new THREE.Mesh(geometry, material);
@@ -36,6 +36,21 @@
   }
 
-  Table() {
-    let table = new Table(Config.Simulation.GENOTYPES);
+  createTable(genotypes,genotypeEncoding){
+	this.table = this.Table(genotypes,genotypeEncoding);
+  }
+
+  setGenotypes(genotypes, genotypeEncoding){
+	this.table.genotypes = genotypes;
+	for (let i = 0; i < this.table.genotypes.length; i++) {
+		this.scene.remove(this.table.genotypePlanks[i].textMesh);
+		// this.table.genotypePlanks[i] = new GenotypePlank(genotypes[i],genotypeEncoding,i);
+		this.table.genotypePlanks[i].updateGenotype(genotypes[i],genotypeEncoding);
+		this.scene.add(this.table.genotypePlanks[i].textMesh);
+		this.table.fitnessPlanks[i].updateFitness((Math.random() * 100).toFixed(2));
+	}
+  }
+
+  Table(genotypes,genotypeEncoding) {
+    let table = new Table(genotypes,genotypeEncoding);
     this.scene.add(table.board);
     this.scene.add(table.genotypeHeader.mesh);
@@ -76,9 +91,9 @@
 
   Sky() {
-    let sky = new THREE.Sky()
+    let sky = new Sky()
     sky.scale.setScalar(Config.Sky.SCALE);
     sky.material.uniforms.turbidity.value = Config.Sky.TURBIDITY;
     sky.material.uniforms.rayleigh.value = Config.Sky.RAYLEIGH;
-    sky.material.uniforms.luminance.value = Config.Sky.LUMINANCE;
+  	// sky.material.uniforms.luminance.value = Config.Sky.LUMINANCE;
     sky.material.uniforms.mieCoefficient.value = Config.Sky.MIE_COEFFICIENT;
     sky.material.uniforms.mieDirectionalG.value = Config.Sky.MIE_DIRECTIONAL_G;
@@ -89,5 +104,5 @@
   Sun() {
     let sun = new THREE.Mesh(
-      new THREE.SphereBufferGeometry(Config.Sun.RADIUS, Config.Sun.WIDTH_SEGMENTS, Config.Sun.HEIGHT_SEGMENTS),
+      new THREE.SphereGeometry(Config.Sun.RADIUS, Config.Sun.WIDTH_SEGMENTS, Config.Sun.HEIGHT_SEGMENTS),
       new THREE.MeshBasicMaterial({color: Config.Sun.COLOR})
     );
Index: /js/standard_expdef_demo/js/world/object/arrow.js
===================================================================
--- /js/standard_expdef_demo/js/world/object/arrow.js	(revision 1325)
+++ /js/standard_expdef_demo/js/world/object/arrow.js	(revision 1326)
@@ -22,5 +22,5 @@
     let material = new THREE.MeshLambertMaterial({map: texture});
     material.opacity = 0;
-    material.blending = THREE.NoBlending;
+    // material.blending = THREE.NoBlending;
 
     this.mesh = new THREE.Mesh(geometry, material);
Index: /js/standard_expdef_demo/js/world/object/framstick.js
===================================================================
--- /js/standard_expdef_demo/js/world/object/framstick.js	(revision 1325)
+++ /js/standard_expdef_demo/js/world/object/framstick.js	(revision 1326)
@@ -112,5 +112,7 @@
     }
 
-    let model = new Module.Model(genoObj, true);
+    let model = new Module.Model(genoObj, Module.Model["SHAPETYPE_UNKNOWN"], true);
+	model.open();
+	model.close();
     Module.destroy(stringObj);
     Module.destroy(genoObj);
Index: /js/standard_expdef_demo/js/world/object/table.js
===================================================================
--- /js/standard_expdef_demo/js/world/object/table.js	(revision 1325)
+++ /js/standard_expdef_demo/js/world/object/table.js	(revision 1326)
@@ -10,6 +10,7 @@
    */
 
-  constructor(genotypes) {
-    this.genotypes = genotypes
+  constructor(genotypes,genotypeType) {
+    this.genotypes = genotypes;
+	this.genotypeType = genotypeType;
 
     this.board = this.Board();
@@ -25,4 +26,5 @@
     texture.repeat.set(Config.Table.Board.REPEAT, Config.Table.Board.REPEAT);
     texture.anisotropy = Config.Table.Board.ANISOTROPY;
+	texture.colorSpace = THREE.SRGBColorSpace;
 
     let geometry = new THREE.BoxGeometry(Config.Table.Board.WIDTH,
@@ -32,5 +34,5 @@
     let material = new THREE.MeshLambertMaterial({map: texture});
     material.opacity = 0;
-    material.blending = THREE.NoBlending;
+    // material.blending = THREE.NoBlending;
 
     let board = new THREE.Mesh(geometry, material);
@@ -46,5 +48,5 @@
     let planks = []
     for (let i = 0; i < this.genotypes.length; i++) {
-      planks.push(new GenotypePlank(this.genotypes[i], i));
+      planks.push(new GenotypePlank(this.genotypes[i],this.genotypeType, i));
     }
     return planks
@@ -60,5 +62,5 @@
 
   GenotypeHeader() {
-    return new GenotypePlank("Genotype", this.genotypes.length, true)
+    return new GenotypePlank("Genotype",this.genotypeType, this.genotypes.length, true)
   }
 
@@ -71,5 +73,5 @@
 class GenotypePlank {
 
-  constructor(genotype, position, bold) {
+  constructor(genotype, genotypeEncoding, position, bold) {
     this.genotype = genotype;
     this.position = {
@@ -83,4 +85,5 @@
     texture.repeat.set(Config.Table.GenotypePlank.REPEAT, Config.Table.GenotypePlank.REPEAT);
     texture.anisotropy = Config.Table.GenotypePlank.ANISOTROPY;
+	texture.colorSpace = THREE.SRGBColorSpace;
 
     let geometry = new THREE.BoxGeometry(Config.Table.GenotypePlank.WIDTH,
@@ -94,9 +97,17 @@
     this.mesh.receiveShadow = Config.Table.GenotypePlank.RECEIVE_SHADOW;
 
-    this.textMesh = Text.getGenotypeMesh(this.genotype.replace("/*4*/ ", ""));
+	this.genotypeType = genotypeEncoding;
+    this.textMesh = Text.getGenotypeMesh(this.genotype,this.genotypeType);
     if (bold == true) {
-      this.textMesh = Text.getFitnessMesh(this.genotype.replace("/*4*/ ", ""));
+      this.textMesh = Text.getFitnessMesh(this.genotype.replace(`${this.genotypeType} `, ""));
     }
     this.textMesh.position.set(this.position.x, this.position.y, this.position.z + 1);
+  }
+
+  updateGenotype(genotype,genotypeType){
+	this.genotype = genotype;
+	this.genotypeType = genotypeType;
+	this.textMesh = Text.getGenotypeMesh(this.genotype,this.genotypeType);
+	this.textMesh.position.set(this.position.x, this.position.y, this.position.z + 1);
   }
 
@@ -137,4 +148,5 @@
     texture.repeat.set(Config.Table.FitnessPlank.REPEAT, Config.Table.FitnessPlank.REPEAT);
     texture.anisotropy = Config.Table.FitnessPlank.ANISOTROPY;
+	texture.colorSpace = THREE.SRGBColorSpace;
 
     let geometry = new THREE.BoxGeometry(Config.Table.FitnessPlank.WIDTH,
@@ -150,4 +162,9 @@
     this.textMesh = Text.getFitnessMesh(this.fitness);
     this.textMesh.position.set(this.position.x, this.position.y, this.position.z + 1);
+  }
+
+  updateFitness(value){
+	this.fitness = value;
+	this.textMesh.element.innerHTML = roundNumber(this.fitness,2);
   }
 
Index: /js/standard_expdef_demo/js/world/object/text.js
===================================================================
--- /js/standard_expdef_demo/js/world/object/text.js	(revision 1325)
+++ /js/standard_expdef_demo/js/world/object/text.js	(revision 1326)
@@ -6,12 +6,22 @@
 
 var Text = {
-  getGenotypeMesh: function(genotype) {
+	styleRegex: /<style>.*<\/style>/,
+	numberRegex : /-?\d+(\.\d+)?/g,
+	roundMatch: function(match) {
+        return roundNumber(match,2).toString();
+    },
+
+  getGenotypeMesh: function(genotype,genotypeType) {
+	const genman = new Module.GenMan();
+	genotype = genotype.replace(this.numberRegex, this.roundMatch);
+	genotype = genotype.replaceAll("\n","⤶");
     if (genotype.length > 20) {
-      genotype = genotype.slice(0, 20) + "..."
+       genotype = genotype.slice(0,30) + "..."
     }
     var element = document.createElement("div");
-    element.className = "genotype";
-    element.textContent = genotype;
-    return new THREE.CSS3DObject(element);
+    element.innerHTML = genman.HTMLize(genotype).c_str();
+	element.innerHTML = element.innerHTML.replace(this.styleRegex,"").replace(genotypeType,"");
+	Module.destroy(genman);
+    return new CSS3DObject(element);
   },
 
@@ -20,5 +30,5 @@
     element.className = "fitness";
     element.textContent = fitness;
-    return new THREE.CSS3DObject(element);
+    return new CSS3DObject(element);
   },
 
@@ -27,5 +37,5 @@
     element.className = "info";
     element.textContent = info;
-    return new THREE.CSS3DObject(element);
+    return new CSS3DObject(element);
   }
 }
Index: /js/standard_expdef_demo/package.json
===================================================================
--- /js/standard_expdef_demo/package.json	(revision 1326)
+++ /js/standard_expdef_demo/package.json	(revision 1326)
@@ -0,0 +1,14 @@
+{
+  "name": "standard_expdef_demo",
+  "version": "1.0.0",
+  "main": "index.html",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC",
+  "description": "",
+  "dependencies": {
+    "three": "^0.167.0"
+  }
+}
Index: /js/standard_expdef_demo/static/styles.css
===================================================================
--- /js/standard_expdef_demo/static/styles.css	(revision 1325)
+++ /js/standard_expdef_demo/static/styles.css	(revision 1326)
@@ -1,7 +1,9 @@
-.genotype {
+.geno {
   font-size: 40px;
   font-weight: 500;
   font-family: "Helvetica", "Arial", "Verdana", serif;
   text-align: center;
+  /* white outline to help when displayed on darker background: */
+  /* text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white */
 }
 
@@ -20,2 +22,93 @@
   width: 8em;
 }
+
+.neuro-viewer-container{
+	background-color: black;
+	border-radius: 0px 30px 0px 0px;
+	border-color: white;
+	border-style: double double none none;
+	border-width: 5px;
+	pointer-events: none;
+}
+
+#neuro-viewer-2d{
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	width: 25%;
+	height: 25%;
+}
+
+#neuro-viewer-3d{
+	background-color: black;
+	border-radius: 30px 30px 30px 30px;
+	border-color: white;
+	border-style: double double double double;
+	border-width: 5px;
+	pointer-events: none;
+}
+
+#neuro-viewer-canvas{
+	width: 100%;
+	height: 100%;	
+}
+
+.controls {
+	position: absolute;
+	bottom: 0;
+	right: 0;
+	background-color: gainsboro;
+	border-radius: 30px 0px 0px 0px;
+	border-color: gray;
+	border-style: double none none double;
+	border-width: 5px;
+	font-family: "Sans-serif", Verdana, Geneva, Tahoma, sans-serif;
+
+	display: flex;
+  	justify-content: center;
+	align-items: safe center;
+}
+
+.column {
+	display: flex;
+	flex-direction: column;
+}
+
+.row {
+	display: flex;
+	flex-direction: row;
+}
+
+.slider-value{
+	margin-left: 5%;
+}
+
+.slider{
+	margin-left: 2%;
+	margin-right: 2%;
+}
+
+.control-container{
+	margin-top: 2%;
+	width: 70%;
+}
+
+.rater-button{
+	padding: 0;
+	border: none;
+	background: none;
+	font-size: 30px;
+	margin-left: 2%;
+}
+
+button.inactive{
+	opacity: 0.33;
+}
+
+button:active{
+	transform: translateY(4px); 
+}
+
+button.inactive:active{
+	transform: translateY(0px); 
+}
