diff --git a/images/bezier.png b/images/bezier.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9d4fb929f4ec5ed66b80d64c214c9019d406637
Binary files /dev/null and b/images/bezier.png differ
diff --git a/images/quaternions.png b/images/quaternions.png
new file mode 100644
index 0000000000000000000000000000000000000000..b6b268b07be162dc7af033a059f86b176c963a55
Binary files /dev/null and b/images/quaternions.png differ
diff --git a/images/simulation.png b/images/simulation.png
new file mode 100644
index 0000000000000000000000000000000000000000..a423e85bac3e658a403a30a8d1e9df3b652bfaed
Binary files /dev/null and b/images/simulation.png differ
diff --git a/index.html b/index.html
index 632949f5f44cf5304cf74bf337f209aaed5ef1a4..0e617d63b332d759d48dd06a7c73a1fabd1f6168 100644
--- a/index.html
+++ b/index.html
@@ -15,6 +15,5 @@
       <a href="pages/quaternion.html">Quaternions</a>
       <a href="pages/simulation.html">Cloth Simulation</a>
     </nav>
-
   </body>
 </html>
diff --git a/src/02-quaternion/DemoQuaternion.ts b/src/02-quaternion/DemoQuaternion.ts
index 6751a7af8a54a9b8e3d40da8dfd8f0c49cc07089..16bf30f1e80a4a165301d316928df6f01bc01da4 100644
--- a/src/02-quaternion/DemoQuaternion.ts
+++ b/src/02-quaternion/DemoQuaternion.ts
@@ -16,9 +16,17 @@ class QuaternionDemo extends PipelineData {
         light.position.set(1, 1, 1);
         this.scene.add(light);
 
-        const pointLight = new THREE.PointLight(0x6e6e8e, 1);
-        pointLight.position.set(-1, -1, -1);
-        this.scene.add(pointLight);
+        const backLight = new THREE.PointLight(0x6e6e8e, 1);
+        backLight.position.set(-1, -1, -1);
+        this.scene.add(backLight);
+
+        const lightA = new THREE.PointLight(0x8eaa8e, 1);
+        lightA.position.set(2, 2, 0);
+        this.scene.add(lightA);
+
+        const lightC = new THREE.PointLight(0x8eaa7f, 1);
+        lightC.position.set(-2, 0, -2);
+        this.scene.add(lightC);
 
         const axes = new Axes(5);
         this.addRenderable(axes);
diff --git a/src/02-quaternion/RotatorHelper.ts b/src/02-quaternion/RotatorHelper.ts
index 74e1a4f48930b8a35540d2952c3f057d119f79aa..1dfbc94342e6aeb6ed17fca860518af22913cbd7 100644
--- a/src/02-quaternion/RotatorHelper.ts
+++ b/src/02-quaternion/RotatorHelper.ts
@@ -26,7 +26,7 @@ class RotationHelper extends Shape implements PipelineObserver, PipelineDraggabl
         // UNIT SPHERE
         //    The projection of ijk onto the sphere. The fourth dimension is the color.
         const geometrySphere = new THREE.SphereBufferGeometry(1, 32, 32);
-        const matSphere = new THREE.MeshBasicMaterial({ color: primeColor, opacity: 0.9, transparent: true });
+        const matSphere = new THREE.MeshBasicMaterial({ color: primeColor, opacity: .8, transparent: true });
         this._unitSphere = new THREE.Mesh(geometrySphere, matSphere);
 
         // POINTS AND LINES
@@ -51,6 +51,8 @@ class RotationHelper extends Shape implements PipelineObserver, PipelineDraggabl
             this._object3d.add(this._qPoints[i].object());
         for (let i = 0; i < 5; i++)
             this._object3d.add(this._qLines[i].object());
+
+        this._object3d.position.x = 2.5;
     }
 
     update(_deltaTime: number): void {
diff --git a/src/03-simulation/DemoSimulation.ts b/src/03-simulation/DemoSimulation.ts
index 1f968a8053a15ac536feb88e0996734a24b9f977..94def8985f907c323a5fa87d86078135b8671c37 100644
--- a/src/03-simulation/DemoSimulation.ts
+++ b/src/03-simulation/DemoSimulation.ts
@@ -1,18 +1,17 @@
-import * as THREE from 'three';
 import { PipelineData } from "../core/Pipeline";
-import { Particle } from "./cgPhysix/particle";
-import { SimulationSettings } from './SimulationSettings';
+import { Simulation } from "./Simulation";
+import { SimulationData } from './SimulationData';
 
 class SimulationDemo extends PipelineData {
     public constructor() { super(); }
 
     data(): void {
-        const sim = new SimulationSettings();
-        this.addGUIElement(sim);
-
-        SimulationSettings.generateTextile();
-        this.scene.add(SimulationSettings.container);
+        const data = new SimulationData();
+        this.addGUIElement(data);
+        this.addRenderable(data);
 
+        const simulation = new Simulation();
+        this.addObserver(simulation);
     }
 }
 
diff --git a/src/03-simulation/Simulation.ts b/src/03-simulation/Simulation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4fafe54d74051d2fa01768bf31ca45eab62176af
--- /dev/null
+++ b/src/03-simulation/Simulation.ts
@@ -0,0 +1,72 @@
+import * as THREE from 'three';
+import { PipelineObserver } from "../core/Pipeline";
+import { Particle } from './physics/particle';
+import { SimulationData } from "./SimulationData";
+
+export class Simulation implements PipelineObserver {
+
+    public static readonly G = new THREE.Vector3(0, -9.807, 0);
+    public static current: Particle;
+
+    constructor() { 
+        SimulationData.generateTextile();
+    }
+
+
+    update(_deltaTime: number): void {
+        const h = _deltaTime / 100;
+        for (let t = 0; t < _deltaTime; t += h) {
+            SimulationData.pList.forEach(pSub => {
+                pSub.forEach(p => {
+                    if (p.usePhysics) {
+                        Simulation.current = p;
+                        let x = [p.position.x, p.position.y, p.position.z,
+                            p.velocity.x, p.velocity.y, p.velocity.z];
+                        x = SimulationData.INTEGRATORS[SimulationData.integratorType].step(x, h, Simulation.derivation);
+                        p.setState(x[0], x[1], x[2], x[3], x[4], x[5]);
+                    }
+                });
+            })
+        }
+    }
+
+
+    public static derivation(x: Array<number>): Array<number> {
+
+        // 1. create new array to store derivatives
+        let xDot = new Array<number>(x.length);
+
+        // 2. derivative of position => velocity
+        xDot[0] = x[3];
+        xDot[1] = x[4];
+        xDot[2] = x[5];
+
+        // 3. derivative of velocity => acceleration
+
+        // 3.1 accumulate forces
+        let totalForce = new THREE.Vector3(0, 0, 0);
+        totalForce.add(SimulationData.externalForce);
+
+        // 3.2 accumulate spring forces
+        Simulation.current.references.forEach(spring => {
+            const force = spring.force(Simulation.current.position);
+            totalForce.add(force);
+        });
+
+        // 3.3 damping force
+        const dampingForce = Simulation.current.velocity.clone().multiplyScalar(-SimulationData.damping);
+        totalForce.add(dampingForce);
+
+        // 3.3 acceleration = force / mass
+        let totalAcceleration = totalForce.divideScalar(Simulation.current.mass);
+        totalAcceleration.add(Simulation.G);
+
+        // 4. derivative of acceleration => velocity
+        xDot[3] = totalAcceleration.x;
+        xDot[4] = totalAcceleration.y;
+        xDot[5] = totalAcceleration.z;
+
+        return xDot;
+    }
+
+}
\ No newline at end of file
diff --git a/src/03-simulation/SimulationData.ts b/src/03-simulation/SimulationData.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f297342ce8494fd3e7207022e6fa29d6bd3805a8
--- /dev/null
+++ b/src/03-simulation/SimulationData.ts
@@ -0,0 +1,376 @@
+import * as THREE from 'three';
+import { GUI } from 'dat.gui';
+import { picked, PipelineGUI, PipelineRenderable } from '../core/Pipeline';
+import { BendingSpring, ShearSpring, Spring, SpringConstants, StructuralSpring,  } from './physics/Springs';
+import { Particle } from './physics/particle';
+import { EulerIntegrator, Integrator, MidpointIntegrator, RungeKuttaIntegrator } from './physics/Integrators';
+
+class SimulationData implements PipelineGUI, PipelineRenderable {
+
+    public static container: THREE.Group = new THREE.Group();
+
+    // cloth settings
+    public static readonly MAX_TOTAL_MASS = 10;
+    public static readonly MIN_TOTAL_MASS = 0.1;
+
+    public static readonly MAX_WIDTH = 5;
+    public static readonly MIN_WIDTH = 0.01;
+
+    public static readonly MAX_HEIGHT = 2;
+    public static readonly MIN_HEIGHT = 0.01;
+
+    public static readonly MAX_RESOLUTION = 20;
+    public static readonly MIN_RESOLUTION = 2;
+
+    public static totalMass: number = 1;
+    public static width: number = .2;
+    public static height: number = .2;
+    public static resolution: number = 5;
+    public static damping: number = .1;
+    public static externalForce: THREE.Vector3 = new THREE.Vector3(0, 0, 0);
+
+    // particls
+    public static pList = new Array<Array<Particle>>();
+    public static pColorDefault: number = 0xffffff;
+    public static pColorNoPhysix: number = 0xff00ff;
+
+    // springs
+    public static readonly MAX_CONSTANT = 10;
+    public static readonly MIN_CONSTANT = 0.1;
+
+    public static sList = new Array<Spring>();
+    public static sConstants: SpringConstants = { structural: 10, shear: 2, bend: 4 };
+    public static sColorStructural: number = 0xff0000;
+    public static sColorShear: number = 0x00ff00;
+    public static sColorBend: number = 0x0000ff;
+
+    // integrator
+    public static readonly STEP_SIZE = {Fixed:0, Adaptive:1};
+    public static readonly INTEGRATORS: Integrator[] = [
+        new EulerIntegrator(),
+        new MidpointIntegrator(),
+        new RungeKuttaIntegrator
+    ]
+
+    public static integratorType: number = 2;
+    public static stepSize: number = 0;
+
+    public static setEuler = () => { SimulationData.integratorType = 0; }
+    public static setMidpoint = () => { SimulationData.integratorType = 1; }
+    public static setRungeKutta = () => { SimulationData.integratorType = 2; }
+
+
+    public static generateTextile(): void {
+        // 1. reset pList
+        SimulationData.pList = new Array<Array<Particle>>();
+
+        // 2. generate particles
+        for (let i = 0; i < SimulationData.resolution; i++) {
+            SimulationData.pList[i] = new Array<Particle>();
+            for (let j = 0; j < SimulationData.resolution; j++) {
+
+                const p = new Particle({
+                    position: new THREE.Vector3(
+                        SimulationData.width * (i / SimulationData.resolution) - SimulationData.width / 2,
+                        SimulationData.height * (j / SimulationData.resolution) - SimulationData.height / 2,
+                        0),
+                    velocity: new THREE.Vector3(0, 0, 0),
+                    mass: SimulationData.totalMass / (SimulationData.resolution * SimulationData.resolution),
+                    usePhysics: true,
+                    references: [],
+                    radius: 0,
+                    color: SimulationData.pColorDefault,
+                    wireframe: true
+                });
+                SimulationData.pList[i][j] = p;
+            }
+        }
+
+        for (let i = 0; i < SimulationData.resolution; i++) {
+            SimulationData.pList[i][SimulationData.resolution - 1].usePhysics = false;
+        }
+
+        // 3. set particle mass and color
+        SimulationData.changedParticleSize();
+        SimulationData.changedParticleColor();
+
+        // 4. add particles to container
+        const pLinList = new Array<THREE.Mesh>();
+        SimulationData.pList.forEach(pSub => {
+            pSub.forEach(p => {
+                pLinList.push(p.mesh);
+            });
+        });
+
+        // 5. reset sList
+        SimulationData.sList = new Array<Spring>();
+
+        // 6. generate springs
+        for (let i = 0; i < SimulationData.resolution; i++) {
+            for (let j = 0; j < SimulationData.resolution; j++) {
+
+                // structural springs (horizontal)
+                if (i < SimulationData.resolution - 1) {
+                    const pA = SimulationData.pList[i][j];
+                    const pB = SimulationData.pList[i + 1][j];
+
+                    const s = new StructuralSpring({
+                        positionA: pA.position,
+                        positionB: pB.position,
+                        constants: SimulationData.sConstants,
+                        color: SimulationData.sColorStructural,
+                    });
+                    SimulationData.sList.push(s);
+                    s.line.renderOrder = 2;
+
+                    pA.references.push(s);
+                    pB.references.push(s);
+                }
+
+                // structural springs (vertical)
+                if (j < SimulationData.resolution - 1) {
+                    const pA = SimulationData.pList[i][j];
+                    const pB = SimulationData.pList[i][j + 1];
+
+                    const s = new StructuralSpring({
+                        positionA: pA.position,
+                        positionB: pB.position,
+                        constants: SimulationData.sConstants,
+                        color: SimulationData.sColorStructural,
+                    });
+                    SimulationData.sList.push(s);
+                    s.line.renderOrder = 2;
+
+                    pA.references.push(s);
+                    pB.references.push(s);
+                }
+
+
+                // shear springs (bottom-left to top-right)
+                if (i < SimulationData.resolution - 1 && j < SimulationData.resolution - 1) {
+                    const pA = SimulationData.pList[i][j];
+                    const pB = SimulationData.pList[i + 1][j + 1];
+
+                    const s = new ShearSpring({
+                        positionA: pA.position,
+                        positionB: pB.position,
+                        constants: SimulationData.sConstants,
+                        color: SimulationData.sColorShear,
+                    });
+                    SimulationData.sList.push(s);
+                    s.line.renderOrder = 1;
+
+                    pA.references.push(s);
+                    pB.references.push(s);
+                }
+
+                // shear springs (top-left to bottom-right)
+                if (i < SimulationData.resolution - 1 && j > 0) {
+                    const pA = SimulationData.pList[i][j];
+                    const pB = SimulationData.pList[i + 1][j - 1];
+
+                    const s = new ShearSpring({
+                        positionA: pA.position,
+                        positionB: pB.position,
+                        constants: SimulationData.sConstants,
+                        color: SimulationData.sColorShear,
+                    });
+                    SimulationData.sList.push(s);
+                    s.line.renderOrder = 1;
+
+                    pA.references.push(s);
+                    pB.references.push(s);
+                }
+
+                // bend springs (horizontal)
+                if (i < SimulationData.resolution - 2) {
+                    const pA = SimulationData.pList[i][j];
+                    const pB = SimulationData.pList[i + 2][j];
+
+                    const s = new BendingSpring({
+                        positionA: pA.position,
+                        positionB: pB.position,
+                        constants: SimulationData.sConstants,
+                        color: SimulationData.sColorBend,
+                    });
+                    SimulationData.sList.push(s);
+                    s.line.renderOrder = 0;
+
+                    pA.references.push(s);
+                    pB.references.push(s);
+                }
+
+                // bend springs (vertical)
+                if (j < SimulationData.resolution - 2) {
+                    const pA = SimulationData.pList[i][j];
+                    const pB = SimulationData.pList[i][j + 2];
+
+                    const s = new BendingSpring({
+                        positionA: pA.position,
+                        positionB: pB.position,
+                        constants: SimulationData.sConstants,
+                        color: SimulationData.sColorBend,
+                    });
+                    SimulationData.sList.push(s);
+                    s.line.renderOrder = 0;
+
+                    pA.references.push(s);
+                    pB.references.push(s);
+                }
+            }
+        }
+
+        // 7. add springs to container
+        const sLinList = new Array<THREE.Line>();
+        SimulationData.sList.forEach(s => {
+            sLinList.push(s.line);
+        });
+
+        // 8. add particles and springs to container
+        while (SimulationData.container.children.length > 0) {
+            SimulationData.container.children.pop();
+        }
+
+        SimulationData.container.add(...pLinList, ...sLinList);
+    }
+
+    public static changedParticleSize(): void {
+        // 1. calculate current mass
+        const pCount = SimulationData.resolution * SimulationData.resolution;
+        const pMass = SimulationData.totalMass / pCount;
+
+        // 1.1 update particle mass
+        SimulationData.pList.forEach(pSub => {
+            pSub.forEach(p => {
+                p.mass = pMass;
+            });
+        });
+
+        // 2. calculate max pSize
+        const maxSize = Math.min(SimulationData.width, SimulationData.height);
+
+        // 3. normalize pMass
+        const pMassNorm = (pMass + SimulationData.MIN_TOTAL_MASS) /
+            (SimulationData.MAX_TOTAL_MASS + SimulationData.MIN_TOTAL_MASS);
+
+        // 4. calculate pSize
+        const pSize = maxSize * pMassNorm;
+
+        // 5. set pSize
+        SimulationData.pList.forEach(pSub => { pSub.forEach(p => p.setRadius(pSize)) });
+    }
+
+    public static changedDimensions(): void {
+        // 1. reset positions of particles
+        for (let i = 0; i < SimulationData.resolution; i++) {
+            for (let j = 0; j < SimulationData.resolution; j++) {
+                SimulationData.pList[i][j].setPosition(
+                    SimulationData.width * (i / SimulationData.resolution) - SimulationData.width / 2,
+                    SimulationData.height * (j / SimulationData.resolution) - SimulationData.height / 2,
+                    0);
+            }
+        }
+
+        // 2. set size based on particle mass
+        SimulationData.changedParticleSize();
+    }
+
+    public static changedParticleColor(): void {
+        // iterate over all particles and set color based on current internal state
+        SimulationData.pList.forEach(pSub => {
+            pSub.forEach(p => {
+                if (p.usePhysics) {
+                    p.setColor(SimulationData.pColorDefault);
+                } else {
+                    p.setColor(SimulationData.pColorNoPhysix);
+                }
+            })
+        });
+    }
+
+    public static changedSpringColor(): void {
+        // iterate over all particles and set color based on current internal state
+        SimulationData.sList.forEach(s => {
+            if (s instanceof StructuralSpring) {
+                s.setColor(SimulationData.sColorStructural);
+            } else if (s instanceof ShearSpring) {
+                s.setColor(SimulationData.sColorShear);
+            } else if (s instanceof BendingSpring) {
+                s.setColor(SimulationData.sColorBend);
+            }
+        });
+    }
+
+    public static switchParticlePhysics(): void {
+        // 1. is picked object not null
+        if (!picked) {
+            return;
+        }
+
+        // 2. compare mesh to all particles => find particle and change usePhysics
+        SimulationData.pList.forEach(pSub => {
+            pSub.forEach(p => {
+                if (p.mesh === picked) {
+                    p.usePhysics = !p.usePhysics;
+                    p.setColor(p.usePhysics ? SimulationData.pColorDefault 
+                        : SimulationData.pColorNoPhysix);
+                }
+            })
+        });
+    }
+
+    gui(gui: GUI): void {
+
+
+        const general = gui.addFolder('General');
+        general.add(SimulationData, 'totalMass', SimulationData.MIN_TOTAL_MASS, SimulationData.MAX_TOTAL_MASS)
+            .step(0.1).name('Total Mass').onChange(SimulationData.changedParticleSize);
+        general.add(SimulationData, 'width', SimulationData.MIN_WIDTH, SimulationData.MAX_WIDTH)
+            .step(0.1).name('Width').onChange(SimulationData.changedDimensions);
+        general.add(SimulationData, 'height', SimulationData.MIN_HEIGHT, SimulationData.MAX_HEIGHT)
+            .step(0.1).name('Height').onChange(SimulationData.changedDimensions);
+        general.add(SimulationData, 'resolution', SimulationData.MIN_RESOLUTION, SimulationData.MAX_RESOLUTION)
+            .step(1).name('Resolution').onChange(SimulationData.generateTextile);
+        general.open();
+        
+
+        const integration = gui.addFolder('Integrator');
+        integration.add(SimulationData, 'setEuler').name('Euler').onChange(()=>{console.log(SimulationData.integratorType)});
+        integration.add(SimulationData, 'setMidpoint').name('Midpoint').onChange(()=>{console.log(SimulationData.integratorType)});
+        integration.add(SimulationData, 'setRungeKutta').name('Runge Kutta (4th order)').onChange(()=>{console.log(SimulationData.integratorType)});
+        integration.open();
+
+        const extForce = general.addFolder('External Force');
+        extForce.add(SimulationData.externalForce, 'x',).step(0.01);
+        extForce.add(SimulationData.externalForce, 'y',).step(0.01);
+        extForce.add(SimulationData.externalForce, 'z',).step(0.01);
+        extForce.open();
+
+        const particles = gui.addFolder('Particles');
+        particles.add(SimulationData, 'switchParticlePhysics').name('Switch Particle Physics');
+        particles.addColor(SimulationData, 'pColorDefault').name('Default').onChange(SimulationData.changedParticleColor);
+        particles.addColor(SimulationData, 'pColorNoPhysix').name('No Phyisx').onChange(SimulationData.changedParticleColor);
+        particles.open();
+
+        const springs = gui.addFolder('Springs');
+        springs.add(SimulationData, 'damping', 0, 1, 0.001).name('Damping Factor');
+        springs.add(SimulationData.sConstants, 'structural', SimulationData.MIN_CONSTANT, SimulationData.MAX_CONSTANT)
+            .step(0.1).name('Structural');
+        springs.add(SimulationData.sConstants, 'shear', SimulationData.MIN_CONSTANT, SimulationData.MAX_CONSTANT)
+            .step(0.1).name('Shear');
+        springs.add(SimulationData.sConstants, 'bend', SimulationData.MIN_CONSTANT, SimulationData.MAX_CONSTANT)
+            .step(0.1).name('Bend');
+        springs.addColor(SimulationData, 'sColorStructural').name('Structural').onChange(SimulationData.changedSpringColor);
+        springs.addColor(SimulationData, 'sColorShear').name('Shear').onChange(SimulationData.changedSpringColor);
+        springs.addColor(SimulationData, 'sColorBend').name('Bend').onChange(SimulationData.changedSpringColor);
+        springs.open();
+    }
+
+    object(): THREE.Object3D<THREE.Event> {
+        return SimulationData.container;
+    }
+}
+
+export { SimulationData };
+
+
diff --git a/src/03-simulation/SimulationSettings.ts b/src/03-simulation/SimulationSettings.ts
deleted file mode 100644
index c4b6d060c25ee9b41bd173993d7967ef9db42ccd..0000000000000000000000000000000000000000
--- a/src/03-simulation/SimulationSettings.ts
+++ /dev/null
@@ -1,311 +0,0 @@
-import * as THREE from 'three';
-import { GUI } from 'dat.gui';
-import { picked, PipelineGUI } from '../core/Pipeline';
-import { BendingSpring, ShearSpring, Spring, SpringConstants, StructuralSpring,  } from './cgPhysix/Springs';
-import { Particle } from './cgPhysix/particle';
-
-
-class World {
-    public static readonly G = 9.807;
-
-    public static derivation(x: Array<number>): Array<number> {
-
-        let xDot = new Array<number>(x.length);
-
-        for (let i = 0; i < x.length; i += 6) {
-            xDot[i] = x[i + 3];
-            xDot[i + 1] = x[i + 4];
-            xDot[i + 2] = x[i + 5];
-            xDot[i + 3] = 0;
-            xDot[i + 4] = -.01;
-            xDot[i + 5] = 0;
-        }
-
-        return xDot;
-    }
-
-
-}
-
-
-class SimulationSettings implements PipelineGUI {
-
-    public static container: THREE.Group = new THREE.Group();
-
-    // cloth settings
-    public static readonly MAX_TOTAL_MASS = 10;
-    public static readonly MIN_TOTAL_MASS = 0.1;
-
-    public static readonly MAX_WIDTH = 5;
-    public static readonly MIN_WIDTH = 0.01;
-
-    public static readonly MAX_HEIGHT = 2;
-    public static readonly MIN_HEIGHT = 0.01;
-
-    public static readonly MAX_RESOLUTION = 20;
-    public static readonly MIN_RESOLUTION = 2;
-
-    public static totalMass: number = 1;
-    public static width: number = 1;
-    public static height: number = 1;
-    public static resolution: number = 5;
-    public static externalForce: THREE.Vector3 = new THREE.Vector3(0, 0, 0);
-
-    // particls
-    public static pList = new Array<Array<Particle>>();
-    public static pColorDefault: number = 0xffffff;
-    public static pColorNoPhysix: number = 0xff00ff;
-
-    // springs
-    public static readonly MAX_CONSTANT = 10;
-    public static readonly MIN_CONSTANT = 0.1;
-
-    public static sList = new Array<Spring>();
-    public static sConstants: SpringConstants = { structural: 1, shear: 1, bend: 1 };
-    public static sColorStructural: number = 0xff0000;
-    public static sColorShear: number = 0x00ff00;
-    public static sColorBend: number = 0x0000ff;
-
-    // integrator
-    public static readonly INTEGRATOR_TYPES = ['Euler', 'Midpoint', 'RungeKutta'];
-    public static readonly STEP_SIZE = ['Fixed', 'Adaptive'];
-
-    public static integratorType: string = 'Euler';
-    public static stepSize: string = 'Fixed';
-
-    public static generateTextile(): void {
-        // 1. reset pList
-        SimulationSettings.pList = new Array<Array<Particle>>();
-
-        // 2. generate particles
-        for (let i = 0; i < SimulationSettings.resolution; i++) {
-            SimulationSettings.pList[i] = new Array<Particle>();
-            for (let j = 0; j < SimulationSettings.resolution; j++) {
-
-                const p = new Particle({
-                    position: new THREE.Vector3(
-                        SimulationSettings.width * (i / SimulationSettings.resolution) - SimulationSettings.width / 2,
-                        SimulationSettings.height * (j / SimulationSettings.resolution) - SimulationSettings.height / 2,
-                        0),
-                    velocity: new THREE.Vector3(0, 0, 0),
-                    mass: SimulationSettings.totalMass / (SimulationSettings.resolution * SimulationSettings.resolution),
-                    usePhysics: true,
-                    references: [],
-                    radius: 0,
-                    color: SimulationSettings.pColorDefault,
-                    wireframe: true
-                });
-                SimulationSettings.pList[i][j] = p;
-            }
-        }
-
-        for (let i = 0; i < SimulationSettings.resolution; i++) {
-            SimulationSettings.pList[i][SimulationSettings.resolution - 1].usePhysics = false;
-        }
-
-        // 3. set particle mass and color
-        SimulationSettings.changedParticleSize();
-        SimulationSettings.changedParticleColor();
-
-        // 4. add particles to container
-        const pLinList = new Array<THREE.Mesh>();
-        SimulationSettings.pList.forEach(pSub => {
-            pSub.forEach(p => {
-                pLinList.push(p.mesh);
-            });
-        });
-
-        // 5. reset sList
-        SimulationSettings.sList = new Array<Spring>();
-
-        // 6. generate springs
-        for (let i = 0; i < SimulationSettings.resolution; i++) {
-            for (let j = 0; j < SimulationSettings.resolution; j++) {
-
-                // structural springs (horizontal)
-                if (i < SimulationSettings.resolution - 1) {
-                    const pA = SimulationSettings.pList[i][j];
-                    const pB = SimulationSettings.pList[i + 1][j];
-
-                    const s = new StructuralSpring({
-                        positionA: pA.position,
-                        positionB: pB.position,
-                        constants: SimulationSettings.sConstants,
-                        color: SimulationSettings.sColorStructural,
-                    });
-                    SimulationSettings.sList.push(s);
-
-                    pA.references.push(s);
-                    pB.references.push(s);
-                }
-
-                // structural springs (vertical)
-                if (j < SimulationSettings.resolution - 1) {
-                    const pA = SimulationSettings.pList[i][j];
-                    const pB = SimulationSettings.pList[i][j + 1];
-
-                    const s = new StructuralSpring({
-                        positionA: pA.position,
-                        positionB: pB.position,
-                        constants: SimulationSettings.sConstants,
-                        color: SimulationSettings.sColorStructural,
-                    });
-                    SimulationSettings.sList.push(s);
-
-                    pA.references.push(s);
-                    pB.references.push(s);
-                }
-
-
-                // // shear springs
-                // if (j < SimulationSettings.resolution - 1) {
-                //     const s = new ShearSpring(SimulationSettings.pList[i][j], SimulationSettings.pList[i][j + 1], SimulationSettings.sConstants.shear);
-                //     SimulationSettings.sList.push(s);
-                // }
-
-                // // bending springs
-                // if (i < SimulationSettings.resolution - 1 && j < SimulationSettings.resolution - 1) {
-                //     const s = new BendingSpring(SimulationSettings.pList[i][j], SimulationSettings.pList[i + 1][j + 1], SimulationSettings.sConstants.bend);
-                //     SimulationSettings.sList.push(s);
-                // }
-            }
-        }
-
-        // 7. add springs to container
-        const sLinList = new Array<THREE.Line>();
-        SimulationSettings.sList.forEach(s => {
-            sLinList.push(s.line);
-        });
-
-        // 8. add particles and springs to container
-        while (SimulationSettings.container.children.length > 0) {
-            SimulationSettings.container.children.pop();
-        }
-
-        SimulationSettings.container.add(...pLinList, ...sLinList);
-    }
-
-    public static changedParticleSize(): void {
-        // 1. calculate current mass
-        const pCount = SimulationSettings.resolution * SimulationSettings.resolution;
-        const pMass = SimulationSettings.totalMass / pCount;
-
-        // 2. calculate max pSize
-        const maxSize = Math.min(SimulationSettings.width, SimulationSettings.height);
-
-        // 3. normalize pMass
-        const pMassNorm = (pMass + SimulationSettings.MIN_TOTAL_MASS) /
-            (SimulationSettings.MAX_TOTAL_MASS + SimulationSettings.MIN_TOTAL_MASS);
-
-        // 4. calculate pSize
-        const pSize = maxSize * pMassNorm;
-
-        // 5. set pSize
-        SimulationSettings.pList.forEach(pSub => { pSub.forEach(p => p.setRadius(pSize)) });
-    }
-
-    public static changedDimensions(): void {
-        // 1. reset positions of particles
-        for (let i = 0; i < SimulationSettings.resolution; i++) {
-            for (let j = 0; j < SimulationSettings.resolution; j++) {
-                SimulationSettings.pList[i][j].setPosition(
-                    SimulationSettings.width * (i / SimulationSettings.resolution) - SimulationSettings.width / 2,
-                    SimulationSettings.height * (j / SimulationSettings.resolution) - SimulationSettings.height / 2,
-                    0);
-            }
-        }
-
-        // 2. set size based on particle mass
-        SimulationSettings.changedParticleSize();
-    }
-
-    public static changedParticleColor(): void {
-        // iterate over all particles and set color based on current internal state
-        SimulationSettings.pList.forEach(pSub => {
-            pSub.forEach(p => {
-                if (p.usePhysics) {
-                    p.setColor(SimulationSettings.pColorDefault);
-                } else {
-                    p.setColor(SimulationSettings.pColorNoPhysix);
-                }
-            })
-        });
-    }
-
-    public static changedSpringColor(): void {
-        // iterate over all particles and set color based on current internal state
-        SimulationSettings.sList.forEach(s => {
-            if (s instanceof StructuralSpring) {
-                s.setColor(SimulationSettings.sColorStructural);
-            } else if (s instanceof ShearSpring) {
-                s.setColor(SimulationSettings.sColorShear);
-            } else if (s instanceof BendingSpring) {
-                s.setColor(SimulationSettings.sColorBend);
-            }
-        });
-    }
-
-    public static switchParticlePhysics(): void {
-        // 1. is picked object not null
-        if (!picked) {
-            return;
-        }
-
-        // 2. compare mesh to all particles => find particle and change usePhysics
-        SimulationSettings.pList.forEach(pSub => {
-            pSub.forEach(p => {
-                if (p.mesh === picked) {
-                    p.usePhysics = !p.usePhysics;
-                    p.setColor(p.usePhysics ? SimulationSettings.pColorDefault 
-                        : SimulationSettings.pColorNoPhysix);
-                }
-            })
-        });
-    }
-
-    // callback overrides by other classes
-    public callbackSpringColorStructural(_value: number): void { }
-    public callbackSpringColorShear(_value: number): void { }
-    public callbackSpringColorBend(_value: number): void { }
-
-    gui(gui: GUI): void {
-        const general = gui.addFolder('General');
-        general.add(SimulationSettings, 'totalMass', SimulationSettings.MIN_TOTAL_MASS, SimulationSettings.MAX_TOTAL_MASS)
-            .step(0.1).name('Total Mass').onChange(SimulationSettings.changedParticleSize);
-        general.add(SimulationSettings, 'width', SimulationSettings.MIN_WIDTH, SimulationSettings.MAX_WIDTH)
-            .step(0.1).name('Width').onChange(SimulationSettings.changedDimensions);
-        general.add(SimulationSettings, 'height', SimulationSettings.MIN_HEIGHT, SimulationSettings.MAX_HEIGHT)
-            .step(0.1).name('Height').onChange(SimulationSettings.changedDimensions);
-        general.add(SimulationSettings, 'resolution', SimulationSettings.MIN_RESOLUTION, SimulationSettings.MAX_RESOLUTION)
-            .step(1).name('Resolution').onChange(SimulationSettings.generateTextile);
-        general.open();
-
-        const extForce = general.addFolder('External Force');
-        extForce.add(SimulationSettings.externalForce, 'x',).step(0.01);
-        extForce.add(SimulationSettings.externalForce, 'y',).step(0.01);
-        extForce.add(SimulationSettings.externalForce, 'z',).step(0.01);
-        extForce.open();
-
-        const particles = gui.addFolder('Particles');
-        particles.add(SimulationSettings, 'switchParticlePhysics').name('Switch Particle Physics');
-        particles.addColor(SimulationSettings, 'pColorDefault').name('Default').onChange(SimulationSettings.changedParticleColor);
-        particles.addColor(SimulationSettings, 'pColorNoPhysix').name('No Phyisx').onChange(SimulationSettings.changedParticleColor);
-        particles.open();
-
-        const springs = gui.addFolder('Springs');
-        springs.add(SimulationSettings.sConstants, 'structural', SimulationSettings.MIN_CONSTANT, SimulationSettings.MAX_CONSTANT)
-            .step(0.1).name('Structural');
-        springs.add(SimulationSettings.sConstants, 'shear', SimulationSettings.MIN_CONSTANT, SimulationSettings.MAX_CONSTANT)
-            .step(0.1).name('Shear');
-        springs.add(SimulationSettings.sConstants, 'bend', SimulationSettings.MIN_CONSTANT, SimulationSettings.MAX_CONSTANT)
-            .step(0.1).name('Bend');
-        springs.addColor(SimulationSettings, 'sColorStructural').name('Structural').onChange(SimulationSettings.changedSpringColor);
-        springs.addColor(SimulationSettings, 'sColorShear').name('Shear').onChange(SimulationSettings.changedSpringColor);
-        springs.addColor(SimulationSettings, 'sColorBend').name('Bend').onChange(SimulationSettings.changedSpringColor);
-        springs.open();
-    }
-}
-
-export { SimulationSettings };
-
-
diff --git a/src/03-simulation/physics/Particle.ts b/src/03-simulation/physics/Particle.ts
index 6b028deb40e66f86d7c98366c25a1658b68d4acc..acc081fc19d55d2382c9ecdab39a41adf5c72d62 100644
--- a/src/03-simulation/physics/Particle.ts
+++ b/src/03-simulation/physics/Particle.ts
@@ -47,6 +47,11 @@ export class Particle implements PipelineRenderable {
         (this.mesh.material as THREE.MeshBasicMaterial).color.set(color);
     }
 
+    public setState(px: number, py: number, pz: number, vx: number, vy: number, vz: number): void {
+        this.velocity.set(vx, vy, vz);
+        this.setPosition(px, py, pz);
+    }
+
     public setPosition(x: number, y: number, z: number): void {
         this.position.set(x, y, z);
         this.mesh.position.copy(this.position);
@@ -60,4 +65,4 @@ export class Particle implements PipelineRenderable {
     public object(): THREE.Object3D<THREE.Event> {
         return this.mesh;
     }
-}
\ No newline at end of file
+}
diff --git a/src/03-simulation/physics/Springs.ts b/src/03-simulation/physics/Springs.ts
index e7fccd103b9b7ea594a9cf5112902c3b6e8b7174..0b0d05e1b7a3e12c8b95bf4f00574d45ed27a460 100644
--- a/src/03-simulation/physics/Springs.ts
+++ b/src/03-simulation/physics/Springs.ts
@@ -33,14 +33,14 @@ export abstract class Spring {
 
     abstract get springConstant(): number;
 
-    public force(x: number, y: number, z: number): THREE.Vector3 {
+    public force(p: THREE.Vector3): THREE.Vector3 {
         let direction = this.positionB.clone().sub(this.positionA);
         const distance = direction.length();
         direction.normalize();
-        const sign = distance / Math.abs(distance);
-        const result = direction.multiplyScalar(this.springConstant * (distance - this.restingLength) * sign);
+        //const sign = distance / Math.abs(distance);
+        const result = direction.multiplyScalar(this.springConstant * (distance - this.restingLength));
 
-        if (this.positionA === new THREE.Vector3(x, y, z)) {
+        if (this.positionA === p) {
             return result;
         }
 
diff --git a/src/core/Pipeline.ts b/src/core/Pipeline.ts
index 08464fa52948d6ee17563633bc4f2a179eef6ed5..0e1b2c6e5e62a8495c09a1b03660775f40ee2cb1 100644
--- a/src/core/Pipeline.ts
+++ b/src/core/Pipeline.ts
@@ -188,8 +188,8 @@ class Pipeline {
         data.observers.forEach(observer => { this.addPipelineObserver(observer); });
         data.guiElements.forEach(guiElement => { this.addGUI(guiElement); });
 
+        // picking stuff
         document.addEventListener( 'mousedown', (event) => {
-            event.preventDefault();
             let mouse3D = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1,   
                                     -( event.clientY / window.innerHeight ) * 2 + 1,  
                                     0.5 );