diff --git a/src/03-simulation/DemoSimulation.ts b/src/03-simulation/DemoSimulation.ts
index 87a1f63190ebfd4ca799e13ff4c76438d75c16d2..1f968a8053a15ac536feb88e0996734a24b9f977 100644
--- a/src/03-simulation/DemoSimulation.ts
+++ b/src/03-simulation/DemoSimulation.ts
@@ -1,10 +1,18 @@
+import * as THREE from 'three';
 import { PipelineData } from "../core/Pipeline";
+import { Particle } from "./cgPhysix/particle";
+import { SimulationSettings } from './SimulationSettings';
 
 class SimulationDemo extends PipelineData {
     public constructor() { super(); }
 
     data(): void {
-        /* INIT DATA HERE */
+        const sim = new SimulationSettings();
+        this.addGUIElement(sim);
+
+        SimulationSettings.generateTextile();
+        this.scene.add(SimulationSettings.container);
+
     }
 }
 
diff --git a/src/03-simulation/SimulationSettings.ts b/src/03-simulation/SimulationSettings.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c4b6d060c25ee9b41bd173993d7967ef9db42ccd
--- /dev/null
+++ b/src/03-simulation/SimulationSettings.ts
@@ -0,0 +1,311 @@
+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/Integrators.ts b/src/03-simulation/physics/Integrators.ts
new file mode 100644
index 0000000000000000000000000000000000000000..39da71ccb6ecd91bee3371acb85b322fdba2b1cd
--- /dev/null
+++ b/src/03-simulation/physics/Integrators.ts
@@ -0,0 +1,57 @@
+
+abstract class Integrator {
+    abstract step(x: Array<number>, h: number, f: (x: Array<number>) => Array<number>): Array<number>;
+
+    public static adaptiveStep(integrator: Integrator, x: Array<number>, h: number, 
+        f: (x: Array<number>) => Array<number>, errorMax: number): number {
+        let xFull = integrator.step(x, h, f);
+        let xHalf = integrator.step(x, h / 2, f);
+        let error: Array<number> = [];
+        for (let i = 0; i < xFull.length; i++) {
+            error.push(Math.abs(xFull[i] - xHalf[i]));
+        }
+        let errorApproxMax = error.reduce((a, b) => Math.max(a, b));
+        return h * Math.sqrt(errorMax / errorApproxMax);
+    }
+}
+
+class EulerIntegrator extends Integrator {
+    step(x: Array<number>, h: number, f: (x: Array<number>) => Array<number>): Array<number>
+    {
+        let y  = f(x);
+        let x_new = x.map((_, i) => x[i] + h * y[i]);
+        return x_new;
+    }
+}
+
+class MidpointIntegrator extends Integrator {
+
+    private euler: EulerIntegrator;
+
+    constructor() {
+        super();
+        this.euler = new EulerIntegrator();
+    }
+
+    step(x: Array<number>, h: number, f: (x: Array<number>) => Array<number>): Array<number>
+    {
+        let euler_step = this.euler.step(x, h / 2, f);
+        let y = f(euler_step);
+        let x_new = x.map((_, i) => x[i] + h * y[i]);
+        return x_new;
+    }
+}
+
+class RungeKuttaIntegrator extends Integrator {
+    step(x: Array<number>, h: number, f: (x: Array<number>) => Array<number>): Array<number>
+    {
+        let k1 = f(x);
+        let k2 = f(x.map((_, i) => x[i] + h / 2 * k1[i]));
+        let k3 = f(x.map((_, i) => x[i] + h / 2 * k2[i]));
+        let k4 = f(x.map((_, i) => x[i] + h * k3[i]));
+        let x_new = x.map((_, i) => x[i] + h / 6 * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]));
+        return x_new;
+    }
+}
+
+export { Integrator, EulerIntegrator, MidpointIntegrator, RungeKuttaIntegrator };
diff --git a/src/03-simulation/physics/Particle.ts b/src/03-simulation/physics/Particle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6b028deb40e66f86d7c98366c25a1658b68d4acc
--- /dev/null
+++ b/src/03-simulation/physics/Particle.ts
@@ -0,0 +1,63 @@
+import * as THREE from 'three';
+import { PipelineRenderable } from '../../core/Pipeline';
+import './Springs';
+import { Spring } from './Springs';
+
+export interface ParticleParameters {
+    // particle traits
+    position: THREE.Vector3;
+    velocity: THREE.Vector3;
+
+    // internal parameters
+    usePhysics: boolean;
+    mass: number;
+    references: Spring[];
+
+    // visual parameters
+    radius: number;
+    color: number;
+    wireframe: boolean;
+}
+
+export class Particle implements PipelineRenderable {
+    public position: THREE.Vector3;
+    public velocity: THREE.Vector3;
+
+    public mass: number;
+    public usePhysics: boolean;
+
+    public references: Spring[];
+    public mesh: THREE.Mesh;
+
+    constructor(params: ParticleParameters) {
+        this.position = params.position;
+        this.velocity = params.velocity;
+        this.mass = params.mass;
+        this.usePhysics = params.usePhysics;
+        this.references = params.references;
+
+        this.mesh = new THREE.Mesh(
+            new THREE.SphereGeometry(params.radius, 4, 2),
+            new THREE.MeshBasicMaterial({ color: params.color, wireframe: params.wireframe })
+        );
+        this.mesh.position.copy(this.position);
+    }
+
+    public setColor(color: number): void {
+        (this.mesh.material as THREE.MeshBasicMaterial).color.set(color);
+    }
+
+    public setPosition(x: number, y: number, z: number): void {
+        this.position.set(x, y, z);
+        this.mesh.position.copy(this.position);
+        this.references.forEach(spring => spring.notify());
+    }
+
+    public setRadius(radius: number): void {
+        this.mesh.geometry = new THREE.SphereGeometry(radius, 4, 2);
+    }
+
+    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
new file mode 100644
index 0000000000000000000000000000000000000000..e7fccd103b9b7ea594a9cf5112902c3b6e8b7174
--- /dev/null
+++ b/src/03-simulation/physics/Springs.ts
@@ -0,0 +1,105 @@
+import * as THREE from 'three';
+
+export interface SpringParameters {
+    // spring traits
+    positionA: THREE.Vector3;
+    positionB: THREE.Vector3;
+
+    // internal parameters
+    constants: SpringConstants;    
+
+    // visuals
+    color: number;
+}
+
+export abstract class Spring {
+
+    public positionA: THREE.Vector3;
+    public positionB: THREE.Vector3;
+    public restingLength: number;
+
+    public line: THREE.Line;
+
+    constructor(params: SpringParameters) {
+        this.positionA = params.positionA;
+        this.positionB = params.positionB;
+        this.restingLength = this.positionA.distanceTo(this.positionB);
+
+        this.line = new THREE.Line(
+            new THREE.BufferGeometry().setFromPoints([this.positionA, this.positionB]),
+            new THREE.LineBasicMaterial({ color: params.color })
+        );
+    }
+
+    abstract get springConstant(): number;
+
+    public force(x: number, y: number, z: number): 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);
+
+        if (this.positionA === new THREE.Vector3(x, y, z)) {
+            return result;
+        }
+
+        return result.multiplyScalar(-1);
+    }
+
+    public setColor(color: number): void {
+        (this.line.material as THREE.LineBasicMaterial).color.set(color);
+    }
+
+    notify(): void {
+        this.line.geometry.setFromPoints([this.positionA, this.positionB]);
+    }
+}
+
+export class SpringConstants {
+    public structural: number = 1;
+    public shear: number = 1;
+    public bend: number = 1;
+}
+
+export class StructuralSpring extends Spring {
+
+    public constants: SpringConstants;
+
+    constructor(params: SpringParameters) {
+        super(params);
+        this.constants = params.constants;
+    }
+
+    get springConstant(): number {
+        return this.constants.structural;
+    }
+}
+
+export class ShearSpring extends Spring {
+
+    public constants: SpringConstants;
+
+    constructor(params: SpringParameters) {
+        super(params);
+        this.constants = params.constants;
+    }
+
+    get springConstant(): number {
+        return this.constants.shear;
+    }
+}
+
+export class BendingSpring extends Spring {
+
+    public constants: SpringConstants;
+
+    constructor(params: SpringParameters) {
+        super(params);
+        this.constants = params.constants;
+    }
+
+    get springConstant(): number {
+        return this.constants.bend;
+    }
+}
diff --git a/src/core/Pipeline.ts b/src/core/Pipeline.ts
index 3546ad639de5d133cc9dbd4541b96ff6d3790f4b..08464fa52948d6ee17563633bc4f2a179eef6ed5 100644
--- a/src/core/Pipeline.ts
+++ b/src/core/Pipeline.ts
@@ -4,6 +4,8 @@ import * as THREE from "three";
 import { DragControls } from "three/examples/jsm/controls/DragControls";
 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
 
+export let picked: THREE.Object3D | null;
+
 /**
  * PipelineObserver is an abstract class that is used to observe the renderer.
  */
@@ -27,11 +29,6 @@ interface PipelineRenderable {
      * Access the THREE.js object.
      */
     object(): THREE.Object3D;
-
-    /**
-     * Access the position of the THREE.js object directly.
-     */
-    position(): THREE.Vector3;
 }
 
 /**
@@ -102,7 +99,7 @@ abstract class PipelineData {
     /**
      * Define objects that should be added to the GUI.
      */
-    protected addGUI(guiElement: PipelineGUI) {
+    protected addGUIElement(guiElement: PipelineGUI) {
         this.guiElements.push(guiElement);
     }
 
@@ -190,6 +187,25 @@ class Pipeline {
         data.draggables.forEach(draggable => { this.addDraggable(draggable); });
         data.observers.forEach(observer => { this.addPipelineObserver(observer); });
         data.guiElements.forEach(guiElement => { this.addGUI(guiElement); });
+
+        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 );     
+                                    let raycaster =  new THREE.Raycaster();                                        
+            raycaster.setFromCamera( mouse3D, this.camera );
+            let intersects = raycaster.intersectObjects( data.scene.children );
+            if (intersects.length > 0) {
+                intersects.forEach(intersect => {
+                    if (intersect.object instanceof THREE.Mesh) {
+                        picked = intersect.object;
+                    }
+                });
+                
+            }
+            console.log(picked);
+        });
     }
 
     public addPipelineObserver(object: PipelineObserver): void {