diff --git a/QPongApp/CMakeLists.txt b/App/CMakeLists.txt
similarity index 64%
rename from QPongApp/CMakeLists.txt
rename to App/CMakeLists.txt
index 99d4a3cc077976f3b64dbce5d42dfc07e3bb778f..97fee2d3e586a17c77fad8cc24d5f61a4b8c5305 100644
--- a/QPongApp/CMakeLists.txt
+++ b/App/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_executable( QPongApp 
+add_executable( QPongGame 
     GameLayer.cpp
     Log.cpp
     MainMenuLayer.cpp
@@ -6,20 +6,21 @@ add_executable( QPongApp
     Window.cpp
 )
 
-target_include_directories( QPongApp PUBLIC
+target_include_directories( QPong PUBLIC
     .
     ..
     ../libs
     ../libs/imgui/examples/libs/gl3w
 )
 
-target_link_libraries( QPongApp PUBLIC 
+target_link_libraries( QPongGame PUBLIC 
     GuiCore
+    QPong
     fftw3
     fftw3_omp
 )
 
-add_custom_command(TARGET QPongApp
+add_custom_command(TARGET QPongGame
     POST_BUILD
     COMMAND ln -sf ${PROJECT_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}/QPongApp
 )
\ No newline at end of file
diff --git a/QPongApp/GameLayer.cpp b/App/GameLayer.cpp
similarity index 60%
rename from QPongApp/GameLayer.cpp
rename to App/GameLayer.cpp
index c2bcbd0b159d0bc854f923f88cb20023c94a8917..eccb93e116b4bee556b189aac48f25e36bc5c555 100644
--- a/QPongApp/GameLayer.cpp
+++ b/App/GameLayer.cpp
@@ -22,8 +22,22 @@
 #include <thread>
 
 
+void calculatePointPositions(float *points, int arraySize);
+void calculateMomentumViewPositions(float *points, int arraySize);
+void calculateTriangleIndices(uint32_t *indices, int arraySize);
+void calculateBorderPotential(float *potential, double *yAt, int arrayElements);
 
-double QPong::GameLayer::GameLayer::Bat::s_speedStepSize = 0.005;
+
+const std::string vertexShaderPath = "assets/shaders/particle.vert.glsl";
+const std::string fragmentShaderPath = "assets/shaders/particle.frag.glsl";
+
+const QPong::ParticleProps initialParticleSettings = {
+    .position = {0.0, 0.0, 0.0},
+    .momentum = {0.0, 0.0, 0.0},
+    .pointUnsharpness = 100.0,
+    .startValue = 0.01,
+    .hbar = 0.000125
+};
 
 template <typename T>
 const T pow2(const T v)
@@ -31,111 +45,8 @@ const T pow2(const T v)
     return v * v;
 }
 
-QPong::GameLayer::GameLayer::Bat::Bat(double x, double y, int keyUp, int keyDown)
-    : m_x{x}
-    , m_y{y}
-    , m_vx{0.0}
-    , m_vy{0.0}
-    , m_height{0.21}
-    , m_width{0.0}
-    , m_keyUp{keyUp}
-    , m_keyDown{keyDown}
-{
-
-}
-
-void QPong::GameLayer::GameLayer::Bat::onUpdate(GuiCore::Timestep ts)
-{
-    constexpr double speed = 20.0;
-    if (GuiCore::Input::isKeyPressed(m_keyDown))
-    {
-        m_vy += s_speedStepSize * speed; 
-    }
-    else if (GuiCore::Input::isKeyPressed(m_keyUp))
-    {
-        m_vy -= s_speedStepSize * speed;
-    }
-    else
-    {
-        m_vy = 0.0;
-    }
-
-    constexpr double maxSpeedFactor = 300.0;
-    if (m_vy > s_speedStepSize * maxSpeedFactor)
-    {
-        m_vy = s_speedStepSize * maxSpeedFactor;
-    }
-    if (m_vy < -s_speedStepSize * maxSpeedFactor)
-    {
-        m_vy = -s_speedStepSize * maxSpeedFactor;
-    }
-    m_y += (m_vy * ts.getSeconds());
-
-    constexpr double maxY {1.3};
-    if (m_y > maxY)
-    {
-        m_y = maxY;
-    }
-    if (m_y < -maxY)
-    {
-        m_y = -maxY;
-    }
-}
-
-double QPong::GameLayer::Bat::getPotential(double x, double y) const
-{
-    y -= m_y;
-    double dist = 0.0;
-    double scale = 0.0000001;
-
-    if (y >= m_height)
-    {
-        dist = pow2(x - m_x) + pow2(y - m_height) + m_width;
-    }
-    else if (y <= (-m_height))
-    {
-        dist = pow2(x - m_x) + pow2((-y) - m_height) + m_width;
-    }
-    else
-    {
-        dist = pow2(m_x - x) + m_width;
-    }
-    return 1.0 / (pow2(dist) ) * scale;
-}
-
-double QPong::GameLayer::Bat::getX() const
-{
-    return m_x;
-}
-
-QPong::GameLayer::GameLayer(QPong::GameLayer::Properties props)
-    :Layer("GameLayer")
-    , m_vertexShaderPath{"assets/shaders/particle.vert.glsl"}
-    , m_fragmentShaderPath{"assets/shaders/particle.frag.glsl"}
-    , m_arraySize{props.resolution}
-    , m_propagate{false}
-    , m_leftBat(-0.8, 0.0, Key::W, Key::S)
-    , m_rightBat(0.8, 0.0, Key::Up, Key::Down)
-    , m_speedScale{3.0f}
-    , m_randomMomentum {true}
-{
-    srand (time(NULL));
-    m_arrayElements = m_arraySize * m_arraySize;
-    m_numberOfQuads = (m_arraySize - 1) * (m_arraySize - 1);
-    m_numberOfIndices = m_numberOfQuads * 6;
-
-    m_initialParticleProperties.position.x = 0.0;
-    m_initialParticleProperties.position.y = 0.0;
-    m_initialParticleProperties.position.z = 0.0;
-    m_initialParticleProperties.momentum.x = 1.0;
-    m_initialParticleProperties.momentum.y = 0.5;
-    m_initialParticleProperties.momentum.z = 0.00;
-    m_initialParticleProperties.pointUnsharpness = 60.0;
-    m_initialParticleProperties.startValue = 0.01;
-    m_initialParticleProperties.hbar = 0.0002;
-}
 
-void QPong::GameLayer::calculatePointPositions(float *positions)
+void QPong::calculatePointPositions(float *positions, int arraySize)
 {
     constexpr float size{3.175f};
     constexpr float xOffset{0.0f};
@@ -148,35 +59,35 @@ void QPong::GameLayer::calculatePointPositions(float *positions)
     constexpr float yMin{-height / 2.0};
     constexpr float yMax{(height / 2.0)};
 
-    float dx = (xMax - xMin) / (m_arraySize - 1.0f); // "spacing"
-    float dy = (yMax - yMin) / (m_arraySize - 1.0f);
+    float dx = (xMax - xMin) / (arraySize - 1.0f); // "spacing"
+    float dy = (yMax - yMin) / (arraySize - 1.0f);
     
     uint32_t i {0}; // array index
-    for (int yId{0}; yId < m_arraySize; ++yId)
+    for (int yId{0}; yId < arraySize; ++yId)
     {
-        for (int xId{0}; xId < m_arraySize; ++xId)
+        for (int xId{0}; xId < arraySize; ++xId)
         {
-            positions[i++] = xMin + xOffset + (static_cast<float>(xId) * dx); // x-Pos
-            positions[i++] = yMax + yOffset - (static_cast<float>(yId) * dy); // y-Pos
-            positions[i++] = 0.0f;             // z-Pos
+            positions[i++] = xMin + xOffset + (static_cast<float>(xId) * dx);   // x-Pos
+            positions[i++] = yMax + yOffset - (static_cast<float>(yId) * dy);   // y-Pos
+            positions[i++] = 0.0f;                                              // z-Pos
         }
     }
 }
 
-void QPong::GameLayer::calculateMomentumViewPositions(float *positions)
+void QPong::calculateMomentumViewPositions(float *positions, int arraySize)
 {
     constexpr float xOffset {1.5f}; // has to be the same as in the shader
     float xMin {2.2f + xOffset};
     float xMax {0.2f + xOffset};
     float yMin {-1.0f};
     float yMax {1.0f};
-    float dx = (xMax - xMin) / (m_arraySize - 1.0f); // "spacing"
-    float dy = (yMax - yMin) / (m_arraySize - 1.0f);
+    float dx = (xMax - xMin) / (arraySize - 1.0f); // "spacing"
+    float dy = (yMax - yMin) / (arraySize - 1.0f);
     {
         uint32_t i {0}; // array index
-        for (int yId{0}; yId < m_arraySize; ++yId)
+        for (int yId{0}; yId < arraySize; ++yId)
         {
-            for (int xId{0}; xId < m_arraySize; ++xId)
+            for (int xId{0}; xId < arraySize; ++xId)
             {
                 positions[i++] = xMin + (static_cast<float>(xId) * dx); // x-Pos
                 positions[i++] = yMax - (static_cast<float>(yId) * dy); // y-Pos
@@ -186,82 +97,65 @@ void QPong::GameLayer::calculateMomentumViewPositions(float *positions)
     }
 }
 
-void QPong::GameLayer::calculateTriangleIndices(uint32_t *indices)
+void QPong::calculateTriangleIndices(uint32_t *indices, int arraySize)
 {
     uint32_t i{0};
-    for (int row {0}; row < (m_arraySize - 1); ++row)
+    for (int row {0}; row < (arraySize - 1); ++row)
     {
-        for (int k {0}; k < (m_arraySize - 1); ++k)
+        for (int k {0}; k < (arraySize - 1); ++k)
         {
-            int offset = row * m_arraySize;
+            int offset = row * arraySize;
             indices[i++] = offset + k;
             indices[i++] = offset + k + 1;
-            indices[i++] = offset + k + m_arraySize;
+            indices[i++] = offset + k + arraySize;
             indices[i++] = offset + k + 1;
-            indices[i++] = offset + k + m_arraySize;
-            indices[i++] = offset + k + m_arraySize + 1;
+            indices[i++] = offset + k + arraySize;
+            indices[i++] = offset + k + arraySize + 1;
         }
     }
 }
 
-void QPong::GameLayer::calculateBorderPotential(float *potential)
+void QPong::calculateBorderPotential(float *potential, double *yAt, int arrayElements)
 {
     double y {0.0};
-    for (int i {0}; i < m_arrayElements; ++i)
+    for (int i {0}; i < arrayElements; ++i)
     {
-        y = m_yAt[i];
+        y = yAt[i];
         float pot = pow2(y) * pow2(y) * pow2(y) * pow2(y) * pow2(y) * pow2(y) * pow2(y) * 0.02;
         potential[i] = pot;
     }
 }
 
-double QPong::GameLayer::posAt(int pos) const
-{
-    return 2.0 * pos / m_arraySize - 1.0;
-}
 
-double  QPong::GameLayer::xAtIndex(int i) const
-{
-    return posAt(i % m_arraySize);
-}
 
-double QPong::GameLayer::yAtIndex(int i) const
-{
-    return posAt(i / m_arraySize);
-}
-
-     
-double QPong::GameLayer::potentialAt(int pos) const
-{
-    if (pos > m_arraySize / 2)
-    {
-        pos -= m_arraySize;
-    }
-    return pos * M_PI * m_initialParticleProperties.hbar;
-}
-
-double QPong::GameLayer::pxAtIndex(int i) const
-{
-    return potentialAt(i % m_arraySize);
-}
-
-double QPong::GameLayer::pyAtIndex(int i) const
+QPong::GameLayer::GameLayer(int resolution)
+    :Layer("GameLayer")
+    , m_arraySize{resolution}
+    , m_propagate{false}
+    , m_leftBat(-0.8, 0.0, Key::W, Key::S)
+    , m_rightBat(0.8, 0.0, Key::Up, Key::Down)
+    , m_particleProperties {initialParticleSettings}
+    , m_speedScale{5.0f}
+    , m_randomMomentum {true}
+    , m_useThreads {false}
 {
-    return potentialAt(i / m_arraySize);
+    srand (time(NULL));
+    m_arrayElements = m_arraySize * m_arraySize;
+    m_numberOfQuads = (m_arraySize - 1) * (m_arraySize - 1);
+    constexpr int indicesPerQuad {6}; // two triangles
+    m_numberOfIndices = m_numberOfQuads * indicesPerQuad;
 }
 
-
-
 void QPong::GameLayer::initialiseParticleMomentum()
 {
     constexpr std::complex<double> ci {0.0, 1.0}; // complex number
-    const double hbar = m_initialParticleProperties.hbar;
-    const double A0 = m_initialParticleProperties.startValue;
-    const double px0 = m_initialParticleProperties.momentum.x / 20.0;
-    const double py0 = m_initialParticleProperties.momentum.y / 20.0;
-    const double x0 = m_initialParticleProperties.position.x;
-    const double y0 = m_initialParticleProperties.position.y;
-    const double lambda = m_initialParticleProperties.pointUnsharpness;
+    const double hbar = m_particleProperties.hbar;
+    const double A0 = m_particleProperties.startValue;
+    const double px0 = m_particleProperties.momentum.x / 20.0;
+    const double py0 = m_particleProperties.momentum.y / 20.0;
+    const double x0 = m_particleProperties.position.x;
+    const double y0 = m_particleProperties.position.y;
+    const double lambda = m_particleProperties.pointUnsharpness;
 
     double sum {0.0};
     m_particleAbsouluteSumStart = 0.0;
@@ -294,7 +188,7 @@ double QPong::GameLayer::absorbParticle(int i, double c)
 void QPong::GameLayer::applyPotentials(int indexBegin, int indexEnd, double dt)
 {
     constexpr std::complex<double> ci {0.0, 1.0};
-    const double hbar = m_initialParticleProperties.hbar;
+    const double hbar = m_particleProperties.hbar;
     double x {0.0};
     double y {0.0};
     const double potential = 1.0;
@@ -337,22 +231,17 @@ void QPong::GameLayer::applyPotentials(int indexBegin, int indexEnd, double dt)
 void QPong::GameLayer::moveForward(int indexBegin, int indexEnd, double dt)
 {
     constexpr std::complex<double> ci {0.0, 1.0};
-    const double hbar = m_initialParticleProperties.hbar;
-    double px {0.0};
-    double py {0.0};
-    constexpr double m = 1.0;   
+    const double hbar = m_particleProperties.hbar;
     const double N = 1.0 / static_cast<double>(m_arrayElements);
     for (int i{indexBegin}; i<indexEnd; ++i)
     {
-        px = m_pxAt[i];
-        py = m_pyAt[i];
-        double E = (pow2(px) + pow2(py)) / (2.0 * m);
-        m_psi[i] *= exp(-ci * dt / hbar * E) * N;
+        m_psi[i] *= exp(-ci * dt / hbar * m_E_At[i]) * N;
     }
 }
 
 void QPong::GameLayer::updateMomentumView(int indexBegin, int indexEnd)
 {
+    GuiCore::Timer timer("updateMomentumView");
     int x {0};
     int y {0};
     for (int i {indexBegin}; i< indexEnd; ++i)
@@ -386,36 +275,31 @@ void QPong::GameLayer::propagateStep(double dt)
 {
     applyPotentials(0, m_arrayElements, dt);
 
-    {
-        GuiCore::Timer t("fftw_execute(forward)");
-        fftw_execute(m_planForward);
-    }
-
+    fftw_execute(m_planForward);
+    
     moveForward(0, m_arrayElements, dt);
 
-    updateMomentumView(0, m_arrayElements);
+    if (m_renderMomentum)
     {
-        GuiCore::Timer t("fftw_execute(backwards");
-        fftw_execute(m_planBackwards);
+        updateMomentumView(0, m_arrayElements);
     }
+
+    fftw_execute(m_planBackwards);
 }
 
 void QPong::GameLayer::onAttach()
 {
-    GuiCore::Timer timer("GameLayer::onAttach()");
     GuiCore::Glyphs::setup();
 
     m_xAt = new double[m_arrayElements];
     m_yAt = new double[m_arrayElements];
-    m_pxAt = new double[m_arrayElements];
-    m_pyAt = new double[m_arrayElements];
+    m_E_At = new double[m_arrayElements];
 
     for (int i {0}; i < m_arrayElements; ++i)
     {
-        m_xAt[i] = xAtIndex(i);
-        m_yAt[i] = yAtIndex(i);
-        m_pxAt[i] = pxAtIndex(i);
-        m_pyAt[i] = pyAtIndex(i);
+        m_xAt[i] = xAtIndex(i, m_arraySize);
+        m_yAt[i] = yAtIndex(i, m_arraySize);
+        m_E_At[i] = (pow2(pxAtIndex(i, m_arraySize, m_particleProperties.hbar)) + pow2(pyAtIndex(i, m_arraySize, m_particleProperties.hbar))) / (2.0 * 1.0);
     }
 
     m_renderMomentum = false;
@@ -425,13 +309,13 @@ void QPong::GameLayer::onAttach()
     m_playerTwo.totalScore = 0;
 
     m_shader = GuiCore::Shader::fromGLSLTextFiles(
-        m_vertexShaderPath,
-        m_fragmentShaderPath
+        vertexShaderPath,
+        fragmentShaderPath
     );
 
     // static verticie positions
     m_particleViewPositions = new float[m_arrayElements * 3];
-    calculatePointPositions(m_particleViewPositions);
+    calculatePointPositions(m_particleViewPositions, m_arraySize);
 
     // Vertex array to store all buffers
     glGenVertexArrays(1, &m_vertexArray);
@@ -446,7 +330,7 @@ void QPong::GameLayer::onAttach()
 
     // Setup indies buffer
     uint32_t *indices = new uint32_t[m_numberOfIndices];
-    calculateTriangleIndices(indices);
+    calculateTriangleIndices(indices, m_arraySize);
 
     glGenBuffers(1, &m_indicesBuffer);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indicesBuffer);
@@ -466,11 +350,12 @@ void QPong::GameLayer::onAttach()
 
     // Setup momentum view
     m_momentumViewPositions = new float[m_arrayElements * 3];
-    calculateMomentumViewPositions(m_momentumViewPositions);
+    calculateMomentumViewPositions(m_momentumViewPositions, m_arraySize);
 
     // Initialise Borders
     m_staticBorderPotential = new float[m_arrayElements];
-    calculateBorderPotential(m_staticBorderPotential);
+    calculateBorderPotential(m_staticBorderPotential, m_yAt, m_arrayElements);
+
     m_dynamicPotential = new float[m_arrayElements];
     glGenBuffers(1, &m_potentialBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, m_potentialBuffer);
@@ -479,7 +364,9 @@ void QPong::GameLayer::onAttach()
     glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(float), 0);
 
     // Set orthografic view projectin "camera" which will not change.
-    m_viewProjectionPosition = glm::ortho(-3.2f, 3.2f, -1.8f, 1.8f, -1.0f, 1.0f);
+    constexpr float viewWidth {3.2f};
+    constexpr float viewHeight {1.8f};
+    m_viewProjectionPosition = glm::ortho(-viewWidth, viewWidth, -viewHeight, viewHeight, -1.0f, 1.0f);
     m_viewProjectionLocation = glGetUniformLocation(m_shader->getRendererID(), "u_viewProjection");
     m_showPotentialsLocation = glGetUniformLocation(m_shader->getRendererID(), "u_showPotential");
     m_isMomentumEnabled = glGetUniformLocation(m_shader->getRendererID(), "u_isMomentumEnabled");
@@ -503,8 +390,8 @@ void QPong::GameLayer::onDetach()
     delete(m_staticBorderPotential);
     delete(m_xAt);
     delete(m_yAt);
-    delete(m_pxAt);
-    delete(m_pyAt);
+    delete(m_E_At);
+    // delete(m_pyAt);
 }
 
 void QPong::GameLayer::onEvent(GuiCore::Event& event)
@@ -518,16 +405,16 @@ void QPong::GameLayer::reset()
         int xRand = rand() % 100;
         int yRand = rand() % 100;
         int positive = rand() % 2;
-        m_initialParticleProperties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + (float)xRand / 120.0f);
+        m_particleProperties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + (float)xRand / 120.0f);
         positive = rand() % 2;
-        m_initialParticleProperties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + (float)yRand / 120.0f);
+        m_particleProperties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + (float)yRand / 120.0f);
     }
     initialiseParticleMomentum();
     m_restart = false;
     m_gameCounts = true;
     m_playerOne.currentlyScored = 0.0;
     m_playerTwo.currentlyScored = 0.0;
-
+    propagateStep(0.0);
 }
 
 void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
@@ -559,62 +446,112 @@ void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
         }
     }
     
-    // Particle
-    glBindBuffer(GL_ARRAY_BUFFER, m_pointsBuffer);
-    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements * 3, m_particleViewPositions);
-    
-    glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
-    glBufferSubData(GL_ARRAY_BUFFER, 0, m_memorySize, m_psi);
-    
-    glBindBuffer(GL_ARRAY_BUFFER, m_potentialBuffer);
-    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements, m_dynamicPotential);
-
-    glUseProgram(m_shader->getRendererID());
-    glUniform1i(m_showPotentialsLocation, static_cast<int>(m_potentialsEnabled));
-    glUniform1i(m_isMomentumEnabled, static_cast<int>(m_renderMomentum));
-    glUniformMatrix4fv(m_viewProjectionLocation, 1, GL_FALSE, &m_viewProjectionPosition[0][0]);
-    glBindVertexArray(m_vertexArray);
-    glDrawElements(GL_TRIANGLES, m_numberOfIndices, GL_UNSIGNED_INT, nullptr);
-
-    // Momentum
-    if (m_renderMomentum)
-    {    
+        // Particle
         glBindBuffer(GL_ARRAY_BUFFER, m_pointsBuffer);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements * 3, m_momentumViewPositions);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements * 3, m_particleViewPositions);
         
         glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, m_memorySize, m_momentum);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, m_memorySize, m_psi);
         
+        glBindBuffer(GL_ARRAY_BUFFER, m_potentialBuffer);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements, m_dynamicPotential);
+
         glUseProgram(m_shader->getRendererID());
-        glUniform1i(m_showPotentialsLocation, 0);
+        glUniform1i(m_showPotentialsLocation, static_cast<int>(m_potentialsEnabled));
+        glUniform1i(m_isMomentumEnabled, static_cast<int>(m_renderMomentum));
+        glUniformMatrix4fv(m_viewProjectionLocation, 1, GL_FALSE, &m_viewProjectionPosition[0][0]);
         glBindVertexArray(m_vertexArray);
         glDrawElements(GL_TRIANGLES, m_numberOfIndices, GL_UNSIGNED_INT, nullptr);
-    }
 
+        // Momentum
+        if (m_renderMomentum)
+        {    
+            glBindBuffer(GL_ARRAY_BUFFER, m_pointsBuffer);
+            glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements * 3, m_momentumViewPositions);
+            
+            glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
+            glBufferSubData(GL_ARRAY_BUFFER, 0, m_memorySize, m_momentum);
+            
+            glUseProgram(m_shader->getRendererID());
+            glUniform1i(m_showPotentialsLocation, 0);
+            glBindVertexArray(m_vertexArray);
+
+            glDrawElements(GL_TRIANGLES, m_numberOfIndices, GL_UNSIGNED_INT, nullptr);
+        }
     std::stringstream totalScore;
     totalScore << m_playerOne.totalScore << " : " << m_playerTwo.totalScore;
     GuiCore::Glyphs::renderText(totalScore.str(), -0.32f, 1.45f, 0.0075f, {1.0, 1.0, 1.0});
 }
 
+void QPong::GameLayer::guiSelectThreadCount()
+{
+    /// @todo Rework threading more efficient.
+    // ImGui::Checkbox("Enable multiple threads", &m_useThreads);
+    if (m_useThreads)
+    {
+        if (ImGui::Button("Less threads"))
+        {
+            if (m_renderingThreadsNumber > 1)
+            {
+                bool isPowerOf2 = false;
+                while (!isPowerOf2)
+                {
+                    m_renderingThreadsNumber--;
+                    for (int i = 0; i < 10; i++)
+                    {
+                        if (m_renderingThreadsNumber == pow(2, i))
+                        {
+                            isPowerOf2 = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        ImGui::SameLine();
+        if (ImGui::Button("More Threads"))
+        {
+            if (m_renderingThreadsNumber < 200)
+            {
+                bool isPowerOf2 = false;
+                while (!isPowerOf2)
+                {
+                    m_renderingThreadsNumber++;
+                    for (int i = 0; i < 10; i++)
+                    {
+                        if (m_renderingThreadsNumber == pow(2, i))
+                        {
+                            isPowerOf2 = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        ImGui::SameLine();
+        ImGui::Text("%d", m_renderingThreadsNumber);
+    }
+}
+
 void QPong::GameLayer::onGuiRender()
 {
     // GUI settings for the particle
     ImGui::Begin("Particle Settings");
     
     // Select initial momentum for particle at restart
-    ImGui::DragFloat2("Momentum [x,y]", glm::value_ptr(m_initialParticleProperties.momentum), 0.01f, -3.0f, 3.0f);
+    ImGui::DragFloat2("Momentum [x,y]", glm::value_ptr(m_particleProperties.momentum), 0.01f, -3.0f, 3.0f);
     ImGui::Checkbox("Random Momentum", &m_randomMomentum);
 
-    float pointUnsharpness = m_initialParticleProperties.pointUnsharpness;
+    float pointUnsharpness = m_particleProperties.pointUnsharpness;
     if (ImGui::DragFloat("Sharpness", &pointUnsharpness, 1.0f, 5.0f, 1000.0f))
     {
-        m_initialParticleProperties.pointUnsharpness = pointUnsharpness;
+        m_particleProperties.pointUnsharpness = pointUnsharpness;
     }
     // Select hbar, changes apply on the fly.
-    float hbar = m_initialParticleProperties.hbar;
+    float hbar = m_particleProperties.hbar;
     if (ImGui::DragFloat("hbar", &hbar, 0.000001f, 0.000001f, 1.0f, "%.6f"))
     {
-        m_initialParticleProperties.hbar = hbar;
+        m_particleProperties.hbar = hbar;
     }
 
     // This value increases or decreases the time step made every iteration.
@@ -623,62 +560,23 @@ void QPong::GameLayer::onGuiRender()
         ImGui::SetTooltip("Change the size of the timestep (dt)\nfor every iteration of the simulation.");
     }
 
-    // Decrease the 
-    if (ImGui::Button("Less threads"))
-    {
-        if (m_renderingThreadsNumber > 1)
-        {
-            bool isPowerOf2 = false;
-            while (!isPowerOf2)
-            {
-                m_renderingThreadsNumber--;
-                for (int i = 0; i < 10; i++)
-                {
-                    if (m_renderingThreadsNumber == pow(2, i))
-                    {
-                        isPowerOf2 = true;
-                        break;
-                    }
-                }
-            }
-        }
-    }
-    ImGui::SameLine();
-    if (ImGui::Button("More Threads"))
-    {
-        if (m_renderingThreadsNumber <  200)
-        {
-            bool isPowerOf2 = false;
-            while (!isPowerOf2)
-            {
-                m_renderingThreadsNumber++;
-                for (int i = 0; i < 10; i++)
-                {
-                    if (m_renderingThreadsNumber == pow(2, i))
-                    {
-                        isPowerOf2 = true;
-                        break;
-                    }
-                }
-            }
-        }
-    }
-    ImGui::SameLine();
-    ImGui::Text("%d", m_renderingThreadsNumber);
+    guiSelectThreadCount();
+
     ImGui::Checkbox("Render Momentum", &m_renderMomentum);
     ImGui::Checkbox("Enable Potentials", &m_potentialsEnabled);
     ImGui::Checkbox("Enable Particle absorption", &m_removeParticleEnabled);
+    
     // Start/Stop propagating
     if (m_propagate)
     {
-        if (ImGui::Button("Pause"))
+        if (ImGui::Button("PAUSE"))
         {
             m_propagate = false;
         }
     }
     else
     {
-        if (ImGui::Button("Play"))
+        if (ImGui::Button("PLAY"))
         {
             m_propagate = true;
         }
diff --git a/App/GameLayer.hpp b/App/GameLayer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ad87e88549f71f02f78a02b99e4cba688b128a3
--- /dev/null
+++ b/App/GameLayer.hpp
@@ -0,0 +1,110 @@
+/// @file   GameLayer.hpp
+/// @author Armin Co
+///
+
+#ifndef QPONG_GAME_LAYER_HPP
+#define QPONG_GAME_LAYER_HPP
+
+#include <glm/glm.hpp>
+
+#include <GuiCore/Layer.hpp>
+#include <GuiCore/Shader.hpp>
+#include <GuiCore/Timestep.hpp>
+
+#include <QPong/Bat.hpp>
+#include <QPong/Particle.hpp>
+
+#include <complex>
+#include <fftw3.h>
+
+namespace QPong
+{
+    struct ParticleProps
+    {
+        glm::vec3 position;
+        glm::vec3 momentum;
+        double pointUnsharpness;
+        double startValue;
+        double hbar;
+    };
+
+    struct Player
+    {
+        double currentlyScored;
+        int totalScore;
+    };
+
+    class GameLayer : public GuiCore::Layer
+    {
+    public:
+        GameLayer(int resolution);
+        virtual ~GameLayer(){};
+        virtual void onAttach() override;
+        virtual void onDetach() override;
+        virtual void onUpdate(GuiCore::Timestep ts) override;
+        virtual void onGuiRender() override;
+        virtual void onEvent(GuiCore::Event &event) override;
+
+    private:
+        void initialiseParticleMomentum();
+        void propagateStep(double dt);
+        void applyPotentials(int indexBegin, int indexEnd, double dt);
+        void moveForward(int indexBegin, int indexEnd, double dt);
+        void updateMomentumView(int indexBegin, int indexEnd);
+        double absorbParticle(int i, double c);
+        
+        void reset();
+        void guiSelectThreadCount();
+
+        Bat m_leftBat;
+        Bat m_rightBat;
+
+        Player m_playerOne;
+        Player m_playerTwo;
+
+        int m_arraySize;
+        int m_arrayElements;
+        int m_numberOfQuads;
+        int m_numberOfIndices;
+
+        size_t m_memorySize;
+        GuiCore::Shader *m_shader;
+        GLuint m_vertexArray;     ///< OpenGL object that "knows" all buffers.
+        GLuint m_pointsBuffer;    ///< Buffer with the location for each element in the particle array
+        GLuint m_indicesBuffer;   ///< Indicies to draw trinagles from the points to fill the "canvas"
+        GLuint m_colorBuffer;     ///< Reference for OpenGL to load the paritcle data to the GPU
+        GLuint m_potentialBuffer; ///< Borders and bats
+
+        float *m_particleViewPositions;
+        float *m_momentumViewPositions;
+        float *m_staticBorderPotential;
+        float *m_dynamicPotential;
+
+        GLuint m_isMomentumEnabled;
+        GLuint m_viewProjectionLocation;
+        GLuint m_showPotentialsLocation;
+        glm::mat4 m_viewProjectionPosition;
+
+        ParticleProps m_particleProperties;
+        fftw_plan m_planForward;
+        fftw_plan m_planBackwards;
+        double m_particleAbsouluteSumStart;
+        double *m_xAt;
+        double *m_yAt;
+        double *m_E_At;
+        std::complex<double> *m_psi;
+        std::complex<double> *m_momentum;
+
+        bool m_gameCounts;
+        bool m_useThreads;
+        bool m_restart;
+        bool m_propagate;
+        bool m_renderMomentum;
+        bool m_randomMomentum;
+        bool m_removeParticleEnabled;
+        bool m_potentialsEnabled;
+        float m_speedScale{1.0f};
+        int m_renderingThreadsNumber{8};
+    };
+}
+#endif
\ No newline at end of file
diff --git a/QPongApp/Log.cpp b/App/Log.cpp
similarity index 100%
rename from QPongApp/Log.cpp
rename to App/Log.cpp
diff --git a/QPongApp/Log.hpp b/App/Log.hpp
similarity index 100%
rename from QPongApp/Log.hpp
rename to App/Log.hpp
diff --git a/QPongApp/MainMenuLayer.cpp b/App/MainMenuLayer.cpp
similarity index 100%
rename from QPongApp/MainMenuLayer.cpp
rename to App/MainMenuLayer.cpp
diff --git a/QPongApp/MainMenuLayer.hpp b/App/MainMenuLayer.hpp
similarity index 100%
rename from QPongApp/MainMenuLayer.hpp
rename to App/MainMenuLayer.hpp
diff --git a/QPongApp/QPongApp.cpp b/App/QPongApp.cpp
similarity index 100%
rename from QPongApp/QPongApp.cpp
rename to App/QPongApp.cpp
diff --git a/QPongApp/Window.cpp b/App/Window.cpp
similarity index 100%
rename from QPongApp/Window.cpp
rename to App/Window.cpp
diff --git a/QPongApp/Window.hpp b/App/Window.hpp
similarity index 100%
rename from QPongApp/Window.hpp
rename to App/Window.hpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6e0c1a4b8c47d0f7e973a5aa99af84dbd8c46661..27a4f1c98e7595d8156c6d1586ae15533bd81858 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,8 +16,11 @@ find_package(PkgConfig REQUIRED)
 # GUI/Window 
 add_subdirectory(GuiCore)
 
+# QPong Basics
+add_subdirectory(QPong)
+
 # QPong App sources
-add_subdirectory(QPongApp)
+add_subdirectory(App)
 
 # Libraries the project depends on:
 add_subdirectory(libs/spdlog)
diff --git a/GuiCore/Application.cpp b/GuiCore/Application.cpp
index 35ccc77582faf1a09a9dc513d4684d56a791aa95..771a7195e36bbdaf94b85eacd6dcffa1e2ab8e6f 100644
--- a/GuiCore/Application.cpp
+++ b/GuiCore/Application.cpp
@@ -8,23 +8,31 @@
 #include "Log.hpp"
 #include "ApplicationEvent.hpp"
 
-
 namespace GuiCore
 {
-    Application* Application::s_instance = nullptr;
+    Application *Application::s_instance = nullptr;
 
     Application::Application(const std::string &name, uint32_t width, uint32_t height)
     {
         if (s_instance == nullptr)
         {
             Log::setup();
-        }
         s_instance = this;
         m_window = std::unique_ptr<IWindow>(IWindow::create({name, width, height}));
-        m_window->setEventCallback([this](auto &&... args) -> decltype(auto) { return this->onEvent(std::forward<decltype(args)>(args)...); });
-
+        m_window->setEventCallback([this](auto &&... args) -> decltype(auto) {
+            return this->onEvent(std::forward<decltype(args)>(args)...); });
         m_guiLayer = std::make_shared<ImGuiLayer>();
         pushLayer(m_guiLayer);
+        }
+        else
+        {
+            Log::get()->debug("Application object was created before.");
+        }
+    }
+
+    Application::~Application()
+    {
+        s_instance = nullptr;
     }
 
     void Application::pushLayer(std::shared_ptr<Layer> layer)
@@ -45,7 +53,7 @@ namespace GuiCore
             [this](auto &&... args) -> decltype(auto) { return this->onWindowClose(std::forward<decltype(args)>(args)...); });
         dispatcher.dispatch<WindowResizeEvent>(
             [this](auto &&... args) -> decltype(auto) { return this->onWindowResize(std::forward<decltype(args)>(args)...); });
-        
+
         for (auto it = m_layerStack.rbegin(); it != m_layerStack.rend(); ++it)
         {
             if (event.handled)
@@ -73,7 +81,7 @@ namespace GuiCore
             }
 
             m_guiLayer->begin();
-            for (auto layer: m_layerStack)
+            for (auto layer : m_layerStack)
             {
                 layer->onGuiRender();
             }
@@ -91,21 +99,20 @@ namespace GuiCore
 
     bool Application::onWindowResize(Event &event)
     {
-        WindowResizeEvent *rsEvent = static_cast<WindowResizeEvent*>(&event);
+        WindowResizeEvent *rsEvent = static_cast<WindowResizeEvent *>(&event);
         Log::get()->trace("Window minimized, {0}, {1}", rsEvent->getWidth(), rsEvent->getHeight());
-        glViewport(0,0, rsEvent->getWidth(), rsEvent->getHeight());
+        glViewport(0, 0, rsEvent->getWidth(), rsEvent->getHeight());
 
         return false;
     }
 
-    Application& Application::get()
+    Application &Application::get()
     {
         return *s_instance;
     }
 
-    IWindow& Application::getWindow()
+    IWindow &Application::getWindow()
     {
         return *m_window;
     }
 }
-
diff --git a/GuiCore/Application.hpp b/GuiCore/Application.hpp
index ad48c239feda5139a856edd86811142a668e8bbf..270db4c33bd6e557564c32c0c8edafdec16633cc 100644
--- a/GuiCore/Application.hpp
+++ b/GuiCore/Application.hpp
@@ -16,28 +16,46 @@
 
 namespace GuiCore
 {
+    /// @brief  Application
+    /// @details
+    /// The Application class contains the window
+    /// and the layer stack of the game/app.
+    /// The app can be started by calling the run method
+    /// after the app was created.
+    ///
     class Application
     {
     public:
+        /// @brief The constructor creates the window for the application.
+        /// @details
+        /// The application is a singleton and only one instance can be created.
+        /// To receive a reference to the application use the get() method.
+        ///
+        /// @param name "Title that will be shown oon the window."
+        /// @param width Width of the window.
+        /// @param height Height of the window.
+        ///
         Application(const std::string &name = "Application", uint32_t width = 1280, uint32_t height = 720);
-        virtual ~Application() {}
+        virtual ~Application();
 
         void run();
-        void onEvent(Event &e);
+        void onEvent(Event &event);
         void pushLayer(std::shared_ptr<Layer> layer);
         void popLayer(std::shared_ptr<Layer> layer);
-        IWindow& getWindow();
+        IWindow &getWindow();
         bool onWindowClose(Event &e);
         bool onWindowResize(Event &e);
 
-        static Application& get();
+        static Application &get();
 
     private:
-        std::unique_ptr<IWindow> m_window;
+        Application(Application&) = delete;
+        Application(Application&&) = delete;
         bool m_isRunnig = true;
         bool m_minimzed = false;
-        LayerStack m_layerStack;
         float m_lastFrameTime = 0.0f;
+        LayerStack m_layerStack;
+        std::unique_ptr<IWindow> m_window;
         std::shared_ptr<ImGuiLayer> m_guiLayer;
 
         static Application *s_instance;
diff --git a/GuiCore/ApplicationEvent.hpp b/GuiCore/ApplicationEvent.hpp
index b71ec60974387776611c6d6020b003c57fcd3381..3c095fa986412305c6fa1b3b4c07f2fd6102cbf7 100644
--- a/GuiCore/ApplicationEvent.hpp
+++ b/GuiCore/ApplicationEvent.hpp
@@ -14,13 +14,12 @@ namespace GuiCore
     {
     public:
         WindowResizeEvent(uint32_t width, uint32_t height)
-            : m_width{width}
-            , m_height{height}
+            : m_width{width}, m_height{height}
         {
         }
 
-        uint32_t getWidth() const {return m_width;}
-        uint32_t getHeight() const {return m_height;}
+        uint32_t getWidth() const { return m_width; }
+        uint32_t getHeight() const { return m_height; }
 
         std::string toString() const override
         {
diff --git a/GuiCore/Event.hpp b/GuiCore/Event.hpp
index c1390bd22f14913b3c29e5ae15a2f3b710350fff..58e87d4d85d10b53f9919ad62ae8b61805ec3666 100644
--- a/GuiCore/Event.hpp
+++ b/GuiCore/Event.hpp
@@ -15,26 +15,40 @@ namespace GuiCore
     enum class EventType
     {
         None = 0,
-        WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,
-		AppTick, AppUpdate, AppRender,
-		KeyPressed, KeyReleased, KeyTyped,
-		MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled
+        WindowClose,
+        WindowResize,
+        WindowFocus,
+        WindowLostFocus,
+        WindowMoved,
+        AppTick,
+        AppUpdate,
+        AppRender,
+        KeyPressed,
+        KeyReleased,
+        KeyTyped,
+        MouseButtonPressed,
+        MouseButtonReleased,
+        MouseMoved,
+        MouseScrolled
     };
-    
+
     enum EventCategory
-	{
-		None = 0,
-		EventCategoryApplication    = BIT(0),
-		EventCategoryInput          = BIT(1),
-		EventCategoryKeyboard       = BIT(2),
-		EventCategoryMouse          = BIT(3),
-		EventCategoryMouseButton    = BIT(4)
-	};
+    {
+        None = 0,
+        EventCategoryApplication = BIT(0),
+        EventCategoryInput = BIT(1),
+        EventCategoryKeyboard = BIT(2),
+        EventCategoryMouse = BIT(3),
+        EventCategoryMouseButton = BIT(4)
+    };
+
+#define EVENT_CLASS_TYPE(type)                                                  \
+    static EventType getStaticType() { return EventType::type; }                \
+    virtual EventType getEventType() const override { return getStaticType(); } \
+    virtual const char *getName() const override { return #type; }
 
-#define EVENT_CLASS_TYPE(type) static EventType getStaticType() { return EventType::type; }\
-								virtual EventType getEventType() const override { return getStaticType(); }\
-								virtual const char* getName() const override { return #type; }
-#define EVENT_CLASS_CATEGORY(category) virtual int getCategoryFlags() const override { return category; }
+#define EVENT_CLASS_CATEGORY(category) \
+    virtual int getCategoryFlags() const override { return category; }
 
     class Event
     {
@@ -42,9 +56,9 @@ namespace GuiCore
         bool handled = false;
 
         virtual EventType getEventType() const = 0;
-        virtual const char * getName() const = 0;
+        virtual const char *getName() const = 0;
         virtual int getCategoryFlags() const = 0;
-        virtual std::string toString() const {return getName();}
+        virtual std::string toString() const { return getName(); }
 
         inline bool isInCategory(EventCategory category)
         {
@@ -60,21 +74,22 @@ namespace GuiCore
         {
         }
 
-        template<typename T, typename F>
-        bool dispatch(const F& function)
+        template <typename T, typename F>
+        bool dispatch(const F &function)
         {
             if (m_event.getEventType() == T::getStaticType())
             {
-                m_event.handled = function(static_cast<T&>(m_event));
+                m_event.handled = function(static_cast<T &>(m_event));
                 return true;
             }
             return false;
         }
+
     private:
         Event &m_event;
     };
 
-    inline std::ostream& operator<<(std::ostream& os, const Event &e)
+    inline std::ostream &operator<<(std::ostream &os, const Event &e)
     {
         return os << e.toString();
     }
diff --git a/GuiCore/Glyphs.cpp b/GuiCore/Glyphs.cpp
index 9d30992c002a8cc8ffbfe67f74bd3b5359cd7b08..034cbd9e73d2ce1a21f85ad71969a35da6863443 100644
--- a/GuiCore/Glyphs.cpp
+++ b/GuiCore/Glyphs.cpp
@@ -7,15 +7,11 @@
 #include "Log.hpp"
 #include <glm/gtc/type_ptr.hpp>
 
-
-extern "C" {
 #include <ft2build.h>
 #include FT_FREETYPE_H
-}
-
 
 std::map<char, GuiCore::Character> GuiCore::Glyphs::s_characters;
-GuiCore::Shader* GuiCore::Glyphs::m_shader;
+GuiCore::Shader *GuiCore::Glyphs::m_shader;
 GLuint GuiCore::Glyphs::m_vertexArray;
 GLuint GuiCore::Glyphs::m_vertexBuffer;
 glm::mat4 GuiCore::Glyphs::projection = glm::ortho(-3.2f, 3.2f, -1.8f, 1.8f, -1.0f, 1.0f);
@@ -24,8 +20,7 @@ void GuiCore::Glyphs::setup()
 {
     m_shader = GuiCore::Shader::fromGLSLTextFiles(
         "assets/shaders/glyph.vert.glsl",
-        "assets/shaders/glyph.frag.glsl"
-    );
+        "assets/shaders/glyph.frag.glsl");
 
     glGenVertexArrays(1, &m_vertexArray);
     glGenBuffers(1, &m_vertexBuffer);
@@ -40,53 +35,55 @@ void GuiCore::Glyphs::setup()
     FT_Library ft;
     if (FT_Init_FreeType(&ft))
     {
-        GuiCore::Log::get()->error("ERROR::FREETYPE: Could not init FreeType Library");
+        GuiCore::Log::get()->error("Error::Freetype: Could not init FreeType Library");
     }
 
+    const char *fontPath = "assets/Font.ttf";
     FT_Face face;
-    if (FT_New_Face(ft, "assets/Font.ttf", 0, &face))
+    if (FT_New_Face(ft, fontPath, 0, &face))
     {
-        GuiCore::Log::get()->error("ERROR::FREETYPE: Failed to load font");
+        GuiCore::Log::get()->error("Error::Freetype: Failed to load font from: {}", fontPath);
     }
-    FT_Set_Pixel_Sizes(face, 0, 48);  
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    for (unsigned char c = 0; c < 128; c++)
+    else
     {
-        // load character glyph
-        auto error = FT_Load_Char(face, c, FT_LOAD_RENDER);
-        if (error)
+        FT_Set_Pixel_Sizes(face, 0, 48);
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        for (unsigned char c = 0; c < 128; c++)
         {
-            GuiCore::Log::get()->error("ERROR::FREETYTPE: Failed to load Glyph {0} {1}", c, error);
-            continue;
+            // load character glyph
+            auto error = FT_Load_Char(face, c, FT_LOAD_RENDER);
+            if (error)
+            {
+                GuiCore::Log::get()->error("Error::Freetype: Failed to load Glyph {0} {1}", c, error);
+                continue;
+            }
+            // generate texture
+            unsigned int texture;
+            glGenTextures(1, &texture);
+            glBindTexture(GL_TEXTURE_2D, texture);
+            glTexImage2D(
+                GL_TEXTURE_2D,
+                0,
+                GL_RED,
+                face->glyph->bitmap.width,
+                face->glyph->bitmap.rows,
+                0,
+                GL_RED,
+                GL_UNSIGNED_BYTE,
+                face->glyph->bitmap.buffer);
+            // set texture options
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+            // now store character for later use
+            Character character = {
+                texture,
+                glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
+                glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
+                static_cast<uint32_t>(face->glyph->advance.x)};
+            s_characters.insert(std::pair<char, Character>(c, character));
         }
-        // generate texture
-        unsigned int texture;
-        glGenTextures(1, &texture);
-        glBindTexture(GL_TEXTURE_2D, texture);
-        glTexImage2D(
-            GL_TEXTURE_2D,
-            0,
-            GL_RED,
-            face->glyph->bitmap.width,
-            face->glyph->bitmap.rows,
-            0,
-            GL_RED,
-            GL_UNSIGNED_BYTE,
-            face->glyph->bitmap.buffer
-        );
-        // set texture options
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        // now store character for later use
-        Character character = {
-            texture, 
-            glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
-            glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
-            static_cast<uint32_t>(face->glyph->advance.x)
-        };
-        s_characters.insert(std::pair<char, Character>(c, character));
     }
 }
 
@@ -110,14 +107,14 @@ void GuiCore::Glyphs::renderText(std::string text, float x, float y, float scale
         float h = ch.size.y * scale;
 
         float vertices[6][4] = {
-            { xPos,     yPos + h,   0.0f, 0.0f },            
-            { xPos,     yPos,       0.0f, 1.0f },
-            { xPos + w, yPos,       1.0f, 1.0f },
+            {xPos,      yPos + h,   0.0f, 0.0f},
+            {xPos,      yPos,       0.0f, 1.0f},
+            {xPos + w, yPos,        1.0f, 1.0f},
+
+            {xPos,      yPos + h,   0.0f, 0.0f},
+            {xPos + w,  yPos,       1.0f, 1.0f},
+            {xPos + w,  yPos + h,   1.0f, 0.0f}};
 
-            { xPos,     yPos + h,   0.0f, 0.0f },
-            { xPos + w, yPos,       1.0f, 1.0f },
-            { xPos + w, yPos + h,   1.0f, 0.0f }
-        };
         glBindTexture(GL_TEXTURE_2D, ch.textureId);
         glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
         glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
diff --git a/GuiCore/Glyphs.hpp b/GuiCore/Glyphs.hpp
index 75c395393f183f99d8feb1415a4aef4fc441494d..07f2172f91126cd75b73cc723f9d1c8390b739d0 100644
--- a/GuiCore/Glyphs.hpp
+++ b/GuiCore/Glyphs.hpp
@@ -8,31 +8,30 @@
 #include <map>
 #include <glm/glm.hpp>
 
-
 #include "Shader.hpp"
-
 namespace GuiCore
 {
-struct Character {
-    unsigned int textureId;  // ID handle of the glyph texture
-    glm::ivec2   size;       // Size of glyph
-    glm::ivec2   bearing;    // Offset from baseline to left/top of glyph
-    unsigned int advance;    // Offset to advance to next glyph
-};
-
-class Glyphs
-{
-public: 
-    static void setup();
-    static void renderText(std::string text, float x, float y, float scale, glm::vec3 color);
-
-private:
-    static std::map<char, Character> s_characters;
-    static Shader *m_shader;
-    static GLuint m_vertexArray;
-    static GLuint m_vertexBuffer;
-    static glm::mat4 projection;
-};
+    struct Character
+    {
+        unsigned int textureId; // ID handle of the glyph texture
+        glm::ivec2 size;        // Size of glyph
+        glm::ivec2 bearing;     // Offset from baseline to left/top of glyph
+        unsigned int advance;   // Offset to advance to next glyph
+    };
+
+    class Glyphs
+    {
+    public:
+        static void setup();
+        static void renderText(std::string text, float x, float y, float scale, glm::vec3 color);
+
+    private:
+        static std::map<char, Character> s_characters;
+        static Shader *m_shader;
+        static GLuint m_vertexArray;
+        static GLuint m_vertexBuffer;
+        static glm::mat4 projection;
+    };
 
 }
 
diff --git a/GuiCore/Timer.cpp b/GuiCore/Timer.cpp
index 4d070e37f1298a6ea57f3f5df6923652dbfd2cc2..908adc57a163ec71b97320026d051461527fa5cf 100644
--- a/GuiCore/Timer.cpp
+++ b/GuiCore/Timer.cpp
@@ -10,7 +10,7 @@ using namespace GuiCore;
 Timer::Timer(const char* name)
     : m_name{name}
 {
-    m_startTimepoint = std::chrono::high_resolution_clock::now();
+    start();
 }
 
 Timer::~Timer()
@@ -18,6 +18,11 @@ Timer::~Timer()
     stop();
 }
 
+void Timer::start()
+{
+    m_startTimepoint = std::chrono::high_resolution_clock::now();
+}
+
 double Timer::stop()
 {
     auto endTimepoint = std::chrono::high_resolution_clock::now();
diff --git a/GuiCore/Timer.hpp b/GuiCore/Timer.hpp
index 5508fe1e0fce97eb160ef611a628203e29b61c75..999b537efe40e8adb8de8c80fcbb5f7cdb2232a0 100644
--- a/GuiCore/Timer.hpp
+++ b/GuiCore/Timer.hpp
@@ -20,6 +20,7 @@ public:
     /// @brief Stops timer.
     ~Timer();
 
+    void start();
     double stop();
 private:
     std::chrono::time_point< std::chrono::high_resolution_clock > m_startTimepoint;
diff --git a/QPong/Bat.cpp b/QPong/Bat.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4d46d7f96ffc3e561a2a80ad756f84525ea40ef0
--- /dev/null
+++ b/QPong/Bat.cpp
@@ -0,0 +1,90 @@
+/// @file   Bat.cpp
+/// @author Armin Co
+///
+
+#include "Bat.hpp"
+#include <GuiCore/Input.hpp>
+
+static constexpr double s_speedStepSize = 0.005;
+
+template <typename T>
+const T pow2(const T v)
+{
+    return v * v;
+}
+
+QPong::Bat::Bat(double x, double y, int keyUp, int keyDown)
+    : m_x{x}
+    , m_y{y}
+    , m_vx{0.0}
+    , m_vy{0.0}
+    , m_height{0.21}
+    , m_width{0.0}
+    , m_keyUp{keyUp}
+    , m_keyDown{keyDown}
+{
+}
+
+void QPong::Bat::onUpdate(GuiCore::Timestep ts)
+{
+    constexpr double speed = 20.0;
+    if (GuiCore::Input::isKeyPressed(m_keyDown))
+    {
+        m_vy += s_speedStepSize * speed; 
+    }
+    else if (GuiCore::Input::isKeyPressed(m_keyUp))
+    {
+        m_vy -= s_speedStepSize * speed;
+    }
+    else
+    {
+        m_vy = 0.0;
+    }
+
+    constexpr double maxSpeedFactor = 300.0;
+    if (m_vy > s_speedStepSize * maxSpeedFactor)
+    {
+        m_vy = s_speedStepSize * maxSpeedFactor;
+    }
+    if (m_vy < -s_speedStepSize * maxSpeedFactor)
+    {
+        m_vy = -s_speedStepSize * maxSpeedFactor;
+    }
+    m_y += (m_vy * ts.getSeconds());
+
+    constexpr double maxY {1.3};
+    if (m_y > maxY)
+    {
+        m_y = maxY;
+    }
+    if (m_y < -maxY)
+    {
+        m_y = -maxY;
+    }
+}
+
+double QPong::Bat::getPotential(double x, double y) const
+{
+    y -= m_y;
+    double dist = 0.0;
+    double scale = 0.0000001;
+
+    if (y >= m_height)
+    {
+        dist = pow2(x - m_x) + pow2(y - m_height) + m_width;
+    }
+    else if (y <= (-m_height))
+    {
+        dist = pow2(x - m_x) + pow2((-y) - m_height) + m_width;
+    }
+    else
+    {
+        dist = pow2(m_x - x) + m_width;
+    }
+    return 1.0 / (pow2(dist) ) * scale;
+}
+
+double QPong::Bat::getX() const
+{
+    return m_x;
+}
\ No newline at end of file
diff --git a/QPong/Bat.hpp b/QPong/Bat.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3b46a997e27fc5194249d2753d28eeb19a67a45a
--- /dev/null
+++ b/QPong/Bat.hpp
@@ -0,0 +1,32 @@
+/// @file   Bat.hpp
+/// @author Armin Co
+///
+
+#ifndef QPONG_BAT_HPP
+#define QPONG_BAT_HPP
+
+#include <GuiCore/Timestep.hpp>
+
+namespace QPong
+{
+    class Bat
+    {
+    public:
+        Bat(double x, double y, int keyUp, int keyDown);
+        double getX() const;
+        double getY() const;
+        void onUpdate(GuiCore::Timestep ts);
+        double getPotential(double x, double y) const;
+    private:
+        double m_x;
+        double m_y;
+        double m_vx;
+        double m_vy;
+        double m_height;
+        double m_width;
+        int m_keyUp;
+        int m_keyDown;
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/QPong/CMakeLists.txt b/QPong/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..10028a94d1091711feb3706c9763846a0d745a9d
--- /dev/null
+++ b/QPong/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_library(QPong
+    Bat.cpp
+    Particle.cpp
+)
+
+target_include_directories(QPong PUBLIC
+    ..
+)
+
+target_link_libraries( QPong
+    GuiCore
+)
\ No newline at end of file
diff --git a/QPong/Matchfield.cpp b/QPong/Matchfield.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..402362fdf9c73b4d6e4b9d09b85231c83b26cfd3
--- /dev/null
+++ b/QPong/Matchfield.cpp
@@ -0,0 +1,16 @@
+/// @file   Matchfield.cpp
+/// @author Armin Co
+///
+
+#include "Matchfield.hpp"
+
+#include <GuiCore/Input.hpp>
+
+using namespace QPong;
+
+Matchfield::Matchfield(unsigned size)
+    : m_leftBat(-0.8, 0.0, Key::W, Key::S)
+    , m_rightBat(0.8, 0.0, Key::Up, Key::Down)
+{
+
+}
\ No newline at end of file
diff --git a/QPong/Matchfield.hpp b/QPong/Matchfield.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6327ace07627c7664fa09cb733fcdb789a8d6b0
--- /dev/null
+++ b/QPong/Matchfield.hpp
@@ -0,0 +1,48 @@
+/// @file   Matchfield.hpp
+/// @author Armin Co
+///
+
+#ifndef QPONG_MATCHFIELD_HPP
+#define QPONG_MATCHFIELD_HPP
+
+#include <glm/glm.hpp>
+#include "Bat.hpp"
+
+namespace QPong
+{
+    /// @brief Properties of the particle
+    ///
+    struct ParticleProperties
+    {
+        glm::vec3 position;
+        glm::vec3 momentum;
+        double pointUnsharpness;
+        double startValue;
+        double hbar;
+    };
+
+    /// @brief Score of a player.
+    ///
+    struct Player
+    {
+        double currentlyScored;
+        int totalScore;
+    };
+
+    class Matchfield
+    {
+    public:
+        Matchfield(unsigned size);
+
+    private:
+        int m_size;
+
+        Bat m_leftBat;
+        Bat m_rightBat;
+
+        Player m_playerOne;
+        Player m_playerTwo;
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/QPong/Particle.cpp b/QPong/Particle.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cd98359a5d713080e14dc323841bab159cf2aaae
--- /dev/null
+++ b/QPong/Particle.cpp
@@ -0,0 +1,38 @@
+#include "Particle.hpp"
+
+using namespace QPong;
+
+double QPong::posAt(int pos, int arraySize)
+{
+    return 2.0 * pos / arraySize - 1.0;
+}
+
+double  QPong::xAtIndex(int i, int arraySize)
+{
+    return posAt(i % arraySize, arraySize);
+}
+
+double QPong::yAtIndex(int i, int arraySize)
+{
+    return posAt(i / arraySize, arraySize);
+}
+
+     
+double QPong::potentialAt(int pos, int arraySize, double hbar)
+{
+    if (pos > arraySize / 2)
+    {
+        pos -= arraySize;
+    }
+    return pos * M_PI * hbar;
+}
+
+double QPong::pxAtIndex(int i, int arraySize, double hbar)
+{
+    return potentialAt(i % arraySize, arraySize, hbar);
+}
+
+double QPong::pyAtIndex(int i, int arraySize, double hbar)
+{
+    return potentialAt(i / arraySize, arraySize, hbar);
+}
diff --git a/QPong/Particle.hpp b/QPong/Particle.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..31bef370fd7951c6542d23cde79fbd5286b3c20c
--- /dev/null
+++ b/QPong/Particle.hpp
@@ -0,0 +1,16 @@
+
+#ifndef QPONG_PARTICLE_HPP
+#define QPONG_PARTICLE_HPP
+
+namespace QPong
+{
+    
+    double posAt(int pos, int arraySize);
+    double xAtIndex(int i, int arraySize);
+    double yAtIndex(int i, int arraySize);
+    double potentialAt(int pos, int arraySize, double hbar);
+    double pxAtIndex(int i, int arraySize, double hbar);
+    double pyAtIndex(int i, int arraySize, double hbar);
+}
+
+#endif
\ No newline at end of file
diff --git a/QPongApp/GameLayer.hpp b/QPongApp/GameLayer.hpp
deleted file mode 100644
index 296c08a7e18504fa4a4746a6353ab5fdfdd11fef..0000000000000000000000000000000000000000
--- a/QPongApp/GameLayer.hpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/// @file   GameLayer.hpp
-/// @author Armin Co
-///
-
-#ifndef QPONG_GAME_LAYER_HPP
-#define QPONG_GAME_LAYER_HPP
-
-#include <glm/glm.hpp>
-
-#include <GuiCore/Layer.hpp>
-#include <GuiCore/Shader.hpp>
-#include <GuiCore/Timestep.hpp>
-
-#include <complex>
-#include <fftw3.h>
-
-namespace QPong
-{
-class GameLayer : public GuiCore::Layer
-{
-public:
-    struct Properties
-    {
-        int resolution;
-        Properties(int res) : resolution {res}{};
-    };
-
-    struct ParticleProps
-    {
-        glm::vec3 position;
-        glm::vec3 momentum;
-        double pointUnsharpness;
-        double startValue;
-        double hbar;
-    };
-
-    struct Player
-    {
-        double currentlyScored;
-        int totalScore;
-    };
-
-    class Bat
-    {
-    public:
-        Bat(double x, double y, int keyUp, int keyDown);
-        double getX() const;
-        double getY() const;
-        void onUpdate(GuiCore::Timestep ts);
-        double getPotential(double x, double y) const;
-    private:
-        double m_x;
-        double m_y;
-        double m_vx;
-        double m_vy;
-        double m_height;
-        double m_width;
-        int m_keyUp;
-        int m_keyDown;
-        static double s_speedStepSize;
-    };
-
-    GameLayer(Properties props);
-    virtual ~GameLayer(){};
-    virtual void onAttach() override;
-    virtual void onDetach() override;
-    virtual void onUpdate(GuiCore::Timestep ts) override;
-    virtual void onGuiRender() override;
-    virtual void onEvent(GuiCore::Event &event) override;
-
-private:
-    void reset();
-
-    void calculatePointPositions(float *points);
-    void calculateMomentumViewPositions(float *points);
-    void calculateTriangleIndices(uint32_t *indices);
-    void calculateBorderPotential(float *potential);
-    void initialiseParticleMomentum();
-    void propagateStep(double dt);
-    void applyPotentials(int indexBegin, int indexEnd, double dt);
-    void moveForward(int indexBegin, int indexEnd, double dt);
-    void updateMomentumView(int indexBegin, int indexEnd);
-    double absorbParticle(int i, double c);
-    // positions at array index
-    inline double posAt(int pos) const;
-    inline double xAtIndex(int i) const;
-    inline double yAtIndex(int i) const;
-    inline double potentialAt(int pos) const;
-    inline double pxAtIndex(int i) const;
-    inline double pyAtIndex(int i) const;
-
-    GuiCore::Shader *m_shader;
-    std::string m_vertexShaderPath;
-    std::string m_fragmentShaderPath;
-
-    int m_arraySize;
-    int m_arrayElements;
-    int m_numberOfQuads;
-    int m_numberOfIndices;
-
-    GLuint m_vertexArray;       ///< OpenGL object that "knows" all buffers.
-    GLuint m_pointsBuffer;      ///< Buffer with the location for each element in the particle array
-    GLuint m_indicesBuffer;     ///< Indicies to draw trinagles from the points to fill the "canvas"
-    GLuint m_colorBuffer;       ///< Reference for OpenGL to load the paritcle data to the GPU
-    GLuint m_potentialBuffer;   ///< Borders and bats
-
-    float *m_particleViewPositions;
-    float *m_momentumViewPositions;
-    float *m_staticBorderPotential;
-    float *m_dynamicPotential;
-
-    double *m_xAt;
-    double *m_yAt;
-    double *m_pxAt;
-    double *m_pyAt;
-
-    glm::mat4 m_viewProjectionPosition;
-    int m_viewProjectionLocation;
-    GLuint m_showPotentialsLocation;
-    GLuint m_isMomentumEnabled;
-
-    ParticleProps m_initialParticleProperties;
-    double m_particleAbsouluteSumStart;
-    fftw_plan m_planForward;
-    fftw_plan m_planBackwards;
-
-    Bat m_leftBat;
-    Bat m_rightBat;
-    Player m_playerOne;
-    Player m_playerTwo;
-    bool m_gameCounts;
-
-    bool m_restart;
-    bool m_propagate;
-    bool m_renderMomentum;
-    bool m_randomMomentum;
-    bool m_removeParticleEnabled;
-    bool m_potentialsEnabled;
-    int m_renderingThreadsNumber {8};
-    size_t m_memorySize {0};
-    float m_speedScale {1.0f};
-    std::complex<double> *m_psi;
-    std::complex<double> *m_momentum;
-};
-}
-#endif
\ No newline at end of file
diff --git a/assets/assets b/assets/assets
new file mode 120000
index 0000000000000000000000000000000000000000..b0f7c4ed5ae58935d8f2eaa53a476e3992ec1dd8
--- /dev/null
+++ b/assets/assets
@@ -0,0 +1 @@
+/home/armin/Master/semester_1/vertiefung_c++/qpong/assets
\ No newline at end of file