diff --git a/App/GameLayer.cpp b/App/GameLayer.cpp
index 646b56f4a76d6ed0e61160c6011897b583e2e09b..d6b7e6b22f659c35ab652baf1e6a3c5a1717173a 100644
--- a/App/GameLayer.cpp
+++ b/App/GameLayer.cpp
@@ -2,38 +2,37 @@
 /// @author Armin Co
 ///
 
+#include <thread>
+#include <string>
+#include <memory>
 #include <GL/gl3w.h>
 #include <GLFW/glfw3.h>
-
 #include <imgui.h>
-
 #include <glm/gtc/type_ptr.hpp>
 #include <glm/gtc/matrix_transform.hpp>
-
 #include <GuiCore/Glyphs.hpp>
 #include <GuiCore/Input.hpp>
 #include <GuiCore/Timer.hpp>
-
+#include <QPong/Utils.hpp>
 #include "GameLayer.hpp"
 #include "Log.hpp"
-#include <QPong/Utils.hpp>
 
-#include <string>
-#include <thread>
 
 const std::string vertexShaderPath = "assets/shaders/particle.vert.glsl";
 const std::string fragmentShaderPath = "assets/shaders/particle.frag.glsl";
 
-const QPong::Particle::Properties initialParticleSettings = {
+constexpr QPong::Particle::Properties initialParticleSettings = {
     .size = 512,
     .position = {0.0, 0.0, 0.0},
     .momentum = {0.0, 0.0, 0.0},
     .sharpness = 64.0,
     .startValue = 0.01,
-    .hbar = 0.000125
+    .hbar = 0.000125,
+    .threads = 8,
+    .game = true
 };
 
-const QPong::Particle::GameOptions initialOptions = {
+constexpr QPong::Particle::GameOptions initialOptions = {
     .potentialsEnabled = true,
     .absorbtionEnabled = true,
     .momentumEnabled = false
@@ -42,29 +41,36 @@ const QPong::Particle::GameOptions initialOptions = {
 QPong::GameLayer::GameLayer(int resolution, int threads)
     :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_propagate{false}
     , m_options{initialOptions}
     , m_properties {initialParticleSettings}
     , m_speedScale{5.0f}
     , m_randomMomentum {true}
     , m_gaming {true}
 {
+    srand(time(nullptr));
+
     m_properties.size = resolution;
     m_properties.threads = threads;
     m_memorySize = sizeof(fftw_complex) * m_properties.elements();
 
-    Log::get()->debug("Creating GameLayer");
-
-    srand(time(NULL));
+    constexpr int indicesPerQuad { 6 }; // two triangles
     m_numberOfQuads = (m_arraySize - 1) * (m_arraySize - 1);
-    constexpr int indicesPerQuad{6}; // two triangles
     m_numberOfIndices = m_numberOfQuads * indicesPerQuad;
 
     m_staticBorderPotential = new float[m_properties.elements()];
     m_dynamicPotential = new float[m_properties.elements()];
-    m_particle = std::make_unique<Particle>(m_properties, m_options, m_playerOne, m_playerTwo, m_leftBat, m_rightBat, m_staticBorderPotential, m_dynamicPotential);
+    m_particle = std::make_unique<Particle>(
+            m_properties,
+            m_options,
+            m_playerOne,
+            m_playerTwo,
+            m_leftBat,
+            m_rightBat,
+            m_staticBorderPotential,
+            m_dynamicPotential);
 }
 
 void QPong::GameLayer::onAttach()
@@ -76,7 +82,8 @@ void QPong::GameLayer::onAttach()
         fragmentShaderPath);
 
     // static verticie positions
-    m_particleViewPositions = new float[m_properties.elements() * 3];
+    constexpr int pointsPerPosition { 3 };
+    m_particleViewPositions = new float[m_properties.elements() * pointsPerPosition];
     calculatePointPositions(m_particleViewPositions, m_arraySize);
 
     // Vertex array to store all buffers
@@ -86,18 +93,18 @@ void QPong::GameLayer::onAttach()
     // Buffer of all point locations
     glGenBuffers(1, &m_pointsBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, m_pointsBuffer);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * m_properties.elements(), m_particleViewPositions, GL_DYNAMIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * pointsPerPosition * m_properties.elements(), m_particleViewPositions, GL_DYNAMIC_DRAW);
     glEnableVertexAttribArray(0);
-    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);
+    glVertexAttribPointer(0, pointsPerPosition, GL_FLOAT, GL_FALSE, sizeof(float) * pointsPerPosition, 0);
 
     // Setup indies buffer
-    uint32_t *indices = new uint32_t[m_numberOfIndices];
-    calculateTriangleIndices(indices, m_arraySize);
+    // uint32_t *indices = new uint32_t[m_numberOfIndices];
+    std::unique_ptr<uint32_t[]> indices (new uint32_t[m_numberOfIndices]()); 
+    calculateTriangleIndices(indices.get(), m_arraySize);
 
     glGenBuffers(1, &m_indicesBuffer);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indicesBuffer);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * m_numberOfIndices, indices, GL_STATIC_DRAW);
-    delete (indices);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * m_numberOfIndices, indices.get(), GL_STATIC_DRAW);
 
     glGenBuffers(1, &m_colorBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
@@ -135,7 +142,7 @@ void QPong::GameLayer::onDetach()
     delete (m_staticBorderPotential);
 }
 
-void QPong::GameLayer::onEvent(GuiCore::Event &event)
+void QPong::GameLayer::onEvent([[maybe_unused]] GuiCore::Event &event)
 {
 }
 
@@ -146,20 +153,27 @@ void QPong::GameLayer::reset()
     
     if (m_randomMomentum)
     {
-        int xRand = rand() % 64;
-        int yRand = rand() % 32;
+        const int xRand = rand() % 64;
+        const int yRand = rand() % 32;
         int positive = rand() % 2;
-        m_properties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + (float)xRand / 120.0f);
+        m_properties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + static_cast<float>(xRand) / 120.0f);
         positive = rand() % 2;
-        m_properties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + (float)yRand / 120.0f);
+        m_properties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + static_cast<float>(yRand) / 120.0f);
     }
     m_options.game = m_gaming;
-    m_particle.reset(new Particle(m_properties, m_options, m_playerOne, m_playerTwo, m_leftBat, m_rightBat, m_staticBorderPotential, m_dynamicPotential));
+    m_particle.reset(new Particle(
+                m_properties,
+                m_options,
+                m_playerOne,
+                m_playerTwo,
+                m_leftBat,
+                m_rightBat,
+                m_staticBorderPotential,
+                m_dynamicPotential));
 
     m_restart = false;
     m_gameCounts = true;
     m_particle->update(0.0);
-    Log::get()->debug("GameLayer reset done");
 }
 
 void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
@@ -168,21 +182,23 @@ void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
     {
         reset();
     }
+
     if (m_propagate)
     {
         m_leftBat.onUpdate(ts);
         m_rightBat.onUpdate(ts);
         m_particle->update(ts.getSeconds() * m_speedScale);
 
+        constexpr double gameWonThreshold { 35.0 };
         if (m_gameCounts)
         {
-            if (m_playerOne.getCurrentGameScore() > 35.0)
+            if (m_playerOne.getCurrentGameScore() > gameWonThreshold)
             {
                 m_playerOne.gameWon();
                 m_gameCounts = false;
                 m_propagate = false;
             }
-            if (m_playerTwo.getCurrentGameScore() > 35.0)
+            if (m_playerTwo.getCurrentGameScore() > gameWonThreshold)
             {
                 m_playerTwo.gameWon();
                 m_gameCounts = false;
@@ -237,7 +253,6 @@ void QPong::GameLayer::onGuiRender()
 {
     // GUI settings for the particle
     ImGui::Begin("Particle Settings");
-
     ImGui::DragFloat2("Start Position", glm::value_ptr(m_properties.position), 0.01f, -1.0f, 1.0f);
 
     // Select initial momentum for particle at restart
@@ -249,6 +264,7 @@ void QPong::GameLayer::onGuiRender()
     {
         m_properties.sharpness = sharpness;
     }
+
     // Select hbar, changes apply on the fly.
     float hbar = m_properties.hbar;
     if (ImGui::DragFloat("hbar", &hbar, 0.0000001f, 0.0000001f, 1.0f, "%.7f"))
@@ -307,6 +323,6 @@ void QPong::GameLayer::onGuiRender()
         m_options.momentumEnabled = true;
         m_restart = true;
     }
-
     ImGui::End();
-}
\ No newline at end of file
+}
+
diff --git a/App/MainMenuLayer.cpp b/App/MainMenuLayer.cpp
index 83fff45473f2eaa8192ae805dd618531b257443b..0bbcf8e5b94f1b597756d5bdd6a105aaa6e2b8c2 100644
--- a/App/MainMenuLayer.cpp
+++ b/App/MainMenuLayer.cpp
@@ -3,24 +3,26 @@
 ///
 
 #include "MainMenuLayer.hpp"
-
+#include <math.h>
 #include <imgui.h>
+#include <glm/gtc/type_ptr.hpp>
 #include <GuiCore/Application.hpp>
 #include "Log.hpp"
-
 #include "GameLayer.hpp"
-#include <glm/gtc/type_ptr.hpp>
 
 using namespace QPong;
 
 MainMenuLayer::MainMenuLayer()
-    : m_selectedResolution {512}
-    , m_powOfResolution {9}
+    : m_powOfResolution {9}
+    , m_selectedResolution {512}
     , m_forceIndividualResolution {false}
     , m_checkboxThreads {true}
     , m_workerThreads {8}
     , m_resetOnce {false} 
+    , m_gameLayer {nullptr}
     , m_gameAttached {false}
+    , m_fps {0.0}
+    , m_backgroundColor {0.12f, 0.12f, 0.12f}
 {
 }
 
@@ -30,7 +32,6 @@ void MainMenuLayer::onAttach()
     glDepthFunc(GL_LESS);
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    m_backgroundColor = {0.15f, 0.15f, 0.15f};
     createNewGame();
 }
 
@@ -42,7 +43,7 @@ void MainMenuLayer::onDetach()
 void MainMenuLayer::createNewGame()
 {
     m_resetOnce = false;
-    if (m_gameAttached)
+    if (m_gameAttached == true)
     {
         GuiCore::Application::get().popLayer(m_gameLayer);
         m_gameAttached = false;
@@ -54,7 +55,8 @@ void MainMenuLayer::createNewGame()
 
 void MainMenuLayer::onUpdate(GuiCore::Timestep ts)
 {
-    m_fps = 1000.0f / ts.getMilliseconds();
+    constexpr float oneSecond_ms { 1000.0f };
+    m_fps = oneSecond_ms / ts.getMilliseconds();
     glClearColor(m_backgroundColor.r, m_backgroundColor.g, m_backgroundColor.b, 1.0f);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -64,8 +66,6 @@ void MainMenuLayer::onUpdate(GuiCore::Timestep ts)
     }
 }
 
-#include <math.h>
-
 void MainMenuLayer::guiShowFPS()
 {
     ImGui::Text("FPS: %3.1f", m_fps);
@@ -94,14 +94,15 @@ void MainMenuLayer::guiSelectResolution()
         }
         m_powOfResolution = (m_powOfResolution < minPowOfResolution) ? minPowOfResolution : m_powOfResolution;
         m_powOfResolution = (m_powOfResolution > maxPowOfResolution) ? maxPowOfResolution : m_powOfResolution;
-        
         m_selectedResolution = std::pow<int>(2, m_powOfResolution);
     }
     else
     {
+        constexpr int minResolution { 32 };
         constexpr int maxResolution = std::pow<int>(2, maxPowOfResolution);
-        ImGui::DragInt("Forced Resolution", &m_selectedResolution, 1, 32, maxResolution);
+        ImGui::DragInt("Forced Resolution", &m_selectedResolution, 1, minResolution, maxResolution);
     }
+
     ImGui::Checkbox("Force other resolution", &m_forceIndividualResolution);
     if (ImGui::IsItemHovered())
     {
@@ -111,15 +112,21 @@ void MainMenuLayer::guiSelectResolution()
 
 void MainMenuLayer::guiResetGame()
 {
-    if (ImGui::Button("Reset Game")){ m_resetOnce = true; }
+    if (ImGui::Button("Reset Game"))
+    {
+        m_resetOnce = true;
+    }
 
-    if (ImGui::IsItemHovered()) {
+    if (ImGui::IsItemHovered())
+    {
         ImGui::SetTooltip("Reinitialise Simulation with selected array resolution.");
     }
 }
 
 void MainMenuLayer::guiNumberOfThreads()
 {
+    constexpr int minWorkerThreadCount { 1 };
+    constexpr int maxWOrkerThreadCoutn { 32 };
     std::stringstream checkbox;
     checkbox << "Use multiple threads [" << m_workerThreads << "]";
     ImGui::Checkbox(checkbox.str().c_str(), &m_checkboxThreads);
@@ -134,31 +141,27 @@ void MainMenuLayer::guiNumberOfThreads()
         {
             m_workerThreads++;
         }
-        m_workerThreads = (m_workerThreads < 1) ? 1 : m_workerThreads;
-        m_workerThreads = (m_workerThreads > 32) ? 32 : m_workerThreads;
+        m_workerThreads = (m_workerThreads < minWorkerThreadCount) ? minWorkerThreadCount : m_workerThreads;
+        m_workerThreads = (m_workerThreads > maxWOrkerThreadCoutn) ? maxWOrkerThreadCoutn  : m_workerThreads;
     }
     else
     {
-        m_workerThreads = 1;
+        m_workerThreads = minWorkerThreadCount;
     }
 }
 
 void MainMenuLayer::onGuiRender()
 {
-    // Main menu controls and info
     ImGui::Begin("Main Menu");
-    
     guiShowFPS();
     guiSelectResolution();
     guiResetGame();
     guiNumberOfThreads();
-
-    ImGui::ColorEdit3("Background Color", glm::value_ptr(m_backgroundColor));
-
     ImGui::End();
 }
 
-void MainMenuLayer::onEvent(GuiCore::Event &event)
+void MainMenuLayer::onEvent([[maybe_unused]] GuiCore::Event &event)
 {
 
 }
+
diff --git a/App/MainMenuLayer.hpp b/App/MainMenuLayer.hpp
index 4657b9afe41b9740289074969d6a7edfbe6625d1..f8403c8e8ede727b5989db1ff9b49dbf0f7c67bc 100644
--- a/App/MainMenuLayer.hpp
+++ b/App/MainMenuLayer.hpp
@@ -34,7 +34,6 @@ private:
     void guiResetGame();
     void guiNumberOfThreads();
 
-    // Resolution
     int m_powOfResolution; ///< choose only from resolutions with 2^pow
     int m_selectedResolution; ///< selected res in the gui
     bool m_forceIndividualResolution; ///< Override resoultion
@@ -48,4 +47,4 @@ private:
     glm::vec3 m_backgroundColor;
 };
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/App/Window.cpp b/App/Window.cpp
index 5e20adb3de76a10731a4bb297efff1a9f683eadf..fd8cadee923f9d42bcc414f7c482bb9f96206bb9 100644
--- a/App/Window.cpp
+++ b/App/Window.cpp
@@ -15,6 +15,9 @@ static bool s_GLFW_Initialized = false;
 static void GLFWErrorCallback(int error, const char *description)
 {
     /// @todo add GuiCore::Logger
+    //
+    GuiCore::Log::get()->error("{}", error);
+    GuiCore::Log::get()->error("{}", description);
 }
 
 GuiCore::IWindow* GuiCore::IWindow::create(const WindowProperties &properties)
@@ -60,7 +63,7 @@ void Window::setup(const GuiCore::WindowProperties &properties)
 
     glfwSetWindowSizeCallback(m_window, [](GLFWwindow * window, int width, int height)
     {
-        Data &data = *(Data*)glfwGetWindowUserPointer(window);
+        Data &data = *(static_cast<Data*>(glfwGetWindowUserPointer(window)));
         data.width = width;
         data.height = height;
 
@@ -71,7 +74,7 @@ void Window::setup(const GuiCore::WindowProperties &properties)
     using namespace GuiCore;
     glfwSetWindowCloseCallback(m_window, [](GLFWwindow* window)
     {
-        Data &data = *(Data*)glfwGetWindowUserPointer(window);
+        Data &data = *(static_cast<Data*>(glfwGetWindowUserPointer(window)));
         WindowCloseEvent event;
         data.eventCallback(event);
     });
@@ -125,4 +128,4 @@ void Window::setEventCallback(const std::function<void(GuiCore::Event&)> callbac
 {
     GuiCore::Log::get()->trace("Window::setEventCallback");
     m_data.eventCallback = callback;
-}
\ No newline at end of file
+}
diff --git a/Dockerfile b/Dockerfile
index ca9f57560d6b0554db09841daa0324704b1fb5e6..24f08cb4fe17b4815754e319a954b4f058c10c15 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -22,9 +22,22 @@ RUN apt-get install -y \
 
 # Specify the wokring directory
 WORKDIR /usr/src/qpong/build
+RUN mkdir -p /usr/src/qpong/App && \
+    mkdir -p /usr/src/qpong/QPong && \
+    mkdir -p /usr/src/qpong/GuiCore && \
+    touch /usr/src/qpong/App/CMakeLists.txt && \
+    touch /usr/src/qpong/QPong/CMakeLists.txt && \
+    touch /usr/src/qpong/GuiCore/CMakeLists.txt
 
+FROM qpongbase as qponglibs
+COPY ./libs /usr/src/qpong/libs
+COPY ./CMakeLists.txt /usr/src/qpong/
+COPY ./ImGuiSrc /usr/src/qpong/ImGuiSrc
+RUN cmake .. && make spdlog ImGuiSrc
 
-FROM qpongbase AS qpongbuild
-
-COPY . /usr/src/qpong
+FROM qponglibs AS qpongbuild
+COPY ./App /usr/src/qpong/App
+COPY ./QPong /usr/src/qpong/QPong
+COPY ./GuiCore /usr/src/qpong/GuiCore
 RUN cmake .. && make -j2
+
diff --git a/GuiCore/ImGuiLayer.cpp b/GuiCore/ImGuiLayer.cpp
index 568b96ac91488311bbdec22b1945eeb46daad445..63c044e9957b7ec791c308186ee7fca7570c51fe 100644
--- a/GuiCore/ImGuiLayer.cpp
+++ b/GuiCore/ImGuiLayer.cpp
@@ -59,7 +59,9 @@ void ImGuiLayer::end()
 {
     ImGuiIO& io = ImGui::GetIO();
     Application& app = Application::get();
-    io.DisplaySize = ImVec2((float)app.getWindow().getWidth(), (float)app.getWindow().getHeight());
+    io.DisplaySize = ImVec2(
+            static_cast<float>(app.getWindow().getWidth()),
+            static_cast<float>(app.getWindow().getHeight()));
 
     ImGui::Render();
     ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
@@ -70,7 +72,7 @@ void ImGuiLayer::onEvent(Event &event)
 
 }
 
-bool ImGuiLayer::onMouseButtonPressed(Event &event)
+bool ImGuiLayer::onMouseButtonPressed([[maybe_unused]] Event &event)
 {
     return false;
 }
diff --git a/GuiCore/Layer.cpp b/GuiCore/Layer.cpp
index 152287f27ad277e5c9bde934bc0f923589e90f75..2aac3005b98e9f4dc3d12ffb0c55c23d827202b9 100644
--- a/GuiCore/Layer.cpp
+++ b/GuiCore/Layer.cpp
@@ -15,6 +15,14 @@ namespace GuiCore
     {
     }
 
+    void Layer::onUpdate([[maybe_unused]] Timestep ts)
+    {
+    }
+
+    void Layer::onEvent([[maybe_unused]] Event &event)
+    {
+    }
+
     const std::string &Layer::getName() const
     {
         return m_debugName;
diff --git a/GuiCore/Layer.hpp b/GuiCore/Layer.hpp
index 73687a1cb8568c263caed48cb8b99a03066b7809..54d165d5876a5bec898491f18095cd12f1447214 100644
--- a/GuiCore/Layer.hpp
+++ b/GuiCore/Layer.hpp
@@ -20,16 +20,16 @@ namespace GuiCore
 
         virtual void onAttach() {}
         virtual void onDetach() {}
-        virtual void onUpdate(Timestep ts) {}
+        virtual void onUpdate(Timestep ts);
         virtual void onGuiRender() {}
-        virtual void onEvent(Event &event){}
+        virtual void onEvent(Event &event);
 
         const std::string &getName() const;
 
     protected:
         std::string m_debugName;
     };
-
 }
 
-#endif
\ No newline at end of file
+#endif
+
diff --git a/QPong/Particle.cpp b/QPong/Particle.cpp
index 6b0dc32c34a383417cf04e1b885f28ccd5b97e19..ae1f9ee40faa675488c99e15941679ab7c237bde 100644
--- a/QPong/Particle.cpp
+++ b/QPong/Particle.cpp
@@ -332,4 +332,4 @@ void Particle::update(double dt)
 double Particle::getTimeFFT() const
 {
     return m_timeFFT;
-}
\ No newline at end of file
+}