diff --git a/.github/workflows/releaseDeploy.yml b/.github/workflows/releaseDeploy.yml
index d823012b6..83ae754b4 100644
--- a/.github/workflows/releaseDeploy.yml
+++ b/.github/workflows/releaseDeploy.yml
@@ -48,7 +48,7 @@ jobs:
         if: matrix.os == 'ubuntu-latest'
         run: |
           sudo apt update --yes
-          sudo apt install --yes xorg-dev cmake libgtk-3-dev libdbus-1-dev
+          sudo apt install --yes xorg-dev cmake libgtk-3-dev libdbus-1-dev libhdf5-dev
 
       - name: Configure CMake
         run: cmake -B ${{github.workspace}}/build -DWERROR=YES -DCMAKE_BUILD_TYPE=${{ matrix.build-type }}
diff --git a/Intern/rayx-core/CMakeLists.txt b/Intern/rayx-core/CMakeLists.txt
index 01a2dac59..652b63130 100644
--- a/Intern/rayx-core/CMakeLists.txt
+++ b/Intern/rayx-core/CMakeLists.txt
@@ -119,34 +119,45 @@ target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC
 
 # ---- Compile Shaders ----
 if(Vulkan_FOUND)
-    # The following code is used to always compile the shader.
-    # This is most likely not an optimal solution, but it will work
-    # until we find a better one.
     add_dependencies(${PROJECT_NAME} RAYX_CORE_COMPILE_SHADER)
-    set(RAYX_CORE_SHADER ${CMAKE_BINARY_DIR}/bin/shaders/comp.spv)
-    set(RAYX_CORE_SHADER_FAKE ${CMAKE_BINARY_DIR}/bin/___comp.spv) # this exists so file cannot be found -> always execute command
-
+    set(RAYX_CORE_SHADER ${CMAKE_BINARY_DIR}/bin/Shaders/comp.spv)
+    file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/Shaders)
     add_custom_command(
         OUTPUT
         ${RAYX_CORE_SHADER}
-        ${RAYX_CORE_SHADER_FAKE}
         COMMAND glslangValidator
         ARGS -V ${PROJECT_SOURCE_DIR}/src/Shader/main-glsl.comp -o ${RAYX_CORE_SHADER}
     )
-
     add_custom_target(RAYX_CORE_COMPILE_SHADER ALL DEPENDS ${RAYX_CORE_SHADER})
 endif()
 
 # ------------------------
 
-# ---- CPack ----
+# ---- Data ----
+# Define the source and destination paths
+set(DATA_SRC_DIR "${CMAKE_SOURCE_DIR}/Data")
+# Set the destination directory for the Data directory based on the build type
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+    set(DATA_DST_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/Data")
+else()
+    set(DATA_DST_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/Data")
+endif()
 
-include(InstallRequiredSystemLibraries)
+# Copy the Data directory to the binary output directory after building
+message(STATUS "Copying Data directory from ${DATA_SRC_DIR} to ${DATA_DST_DIR}")
+add_custom_command(
+    TARGET ${PROJECT_NAME} POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${DATA_SRC_DIR} ${DATA_DST_DIR}
+    COMMENT "Copying Data directory to build output directory..."
+)
+# -----------------
 
-set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/../../LICENSE")
+# ---- CPack ----
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
 set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
 set(CPACK_PACKAGE_CONTACT "Your Name <your.email@example.com>")
 set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Your Project Description")
+install(DIRECTORY ${DATA_SRC_DIR} DESTINATION ${CMAKE_INSTALL_PREFIX})
 
 include(CPack)
 
diff --git a/Intern/rayx-core/src/CanonicalizePath.cpp b/Intern/rayx-core/src/CanonicalizePath.cpp
index bc3f0b8fd..0f0d860c9 100644
--- a/Intern/rayx-core/src/CanonicalizePath.cpp
+++ b/Intern/rayx-core/src/CanonicalizePath.cpp
@@ -1,9 +1,52 @@
 #include "CanonicalizePath.h"
 
 #include "Debug/Debug.h"
+#include <cstring>
+#include <stdexcept>
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+#include <windows.h>
+#elif defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION)
+#include <unistd.h>
+#include <limits.h>
+#elif defined(__APPLE__)
+#include <mach-o/dyld.h>
+#endif
 
 namespace RAYX {
 
+std::filesystem::path getExecutablePath() {
+    char buffer[1024];
+    std::size_t length = sizeof(buffer);
+    memset(buffer, 0, length);
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+    // Windows implementation
+    DWORD ret = GetModuleFileNameA(NULL, buffer, length);
+    if (ret == 0 || ret == length) {
+        // Handle error
+        throw std::runtime_error("Failed to get executable path.");
+    }
+#elif defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION)
+    // Linux and Unix implementation
+    ssize_t ret = readlink("/proc/self/exe", buffer, length - 1);
+    if (ret == -1) {
+        // Handle error
+        throw std::runtime_error("Failed to get executable path.");
+    }
+    buffer[ret] = '\0';  // Ensure null-terminated string
+#elif defined(__APPLE__)
+    // macOS implementation
+    if (_NSGetExecutablePath(buffer, &length) != 0) {
+        // Handle error
+        throw std::runtime_error("Buffer too small; should not happen.");
+    }
+#else
+#error "Platform not supported."
+#endif
+
+    return std::filesystem::path(buffer).parent_path();
+}
+
 /// this function assumes that `base` is already an absolute path
 std::filesystem::path canonicalize(const std::filesystem::path& relPath, const std::filesystem::path& base) {
     if (!base.is_absolute()) {
@@ -23,5 +66,4 @@ std::filesystem::path canonicalizeRepositoryPath(const std::filesystem::path& re
 
 std::filesystem::path canonicalizeUserPath(const std::filesystem::path& relPath) { return canonicalize(relPath, std::filesystem::current_path()); }
 
-
 }  // namespace RAYX
diff --git a/Intern/rayx-core/src/CanonicalizePath.h b/Intern/rayx-core/src/CanonicalizePath.h
index 1ca83048c..9a9dc083b 100644
--- a/Intern/rayx-core/src/CanonicalizePath.h
+++ b/Intern/rayx-core/src/CanonicalizePath.h
@@ -9,6 +9,9 @@
 
 namespace RAYX {
 
+/// Returns the path to the directory containing the executable.
+std::filesystem::path RAYX_API getExecutablePath();
+
 /// `relPath` is a path relative to the root of the RAY-X git repository (i.e.
 /// where .git lies). canonicalizeRepositoryPath(relPath) yields an absolute
 /// path representing the same path. Examples:
diff --git a/Intern/rayx-core/src/Material/NffTable.cpp b/Intern/rayx-core/src/Material/NffTable.cpp
index f8d6e2f62..25261deab 100644
--- a/Intern/rayx-core/src/Material/NffTable.cpp
+++ b/Intern/rayx-core/src/Material/NffTable.cpp
@@ -14,8 +14,9 @@ bool NffTable::load(const char* element, NffTable* out) {
 
     std::transform(elementString.begin(), elementString.end(), elementString.begin(), [](unsigned char c) { return std::tolower(c); });
 
-    std::string f = "Data/nff/" + elementString + ".nff";
-    std::ifstream s(canonicalizeRepositoryPath(f));
+    std::string f = getExecutablePath().string() + "/Data/nff/" + elementString + ".nff";
+    RAYX_VERB << "Loading NffTable from " << f;
+    std::ifstream s(f);
 
     if (s.fail()) {
         return false;
diff --git a/Intern/rayx-core/src/Material/PalikTable.cpp b/Intern/rayx-core/src/Material/PalikTable.cpp
index 12881cfe2..ac4501028 100644
--- a/Intern/rayx-core/src/Material/PalikTable.cpp
+++ b/Intern/rayx-core/src/Material/PalikTable.cpp
@@ -12,8 +12,9 @@ bool PalikTable::load(const char* element, PalikTable* out) {
     std::string elementString = element;
     std::transform(elementString.begin(), elementString.end(), elementString.begin(), [](unsigned char c) { return std::toupper(c); });
 
-    std::string f = "Data/PALIK/" + elementString + ".NKP";
-    std::ifstream s(canonicalizeRepositoryPath(f));
+    std::string f = getExecutablePath().string() + "/Data/PALIK/" + elementString + ".NKP";
+    RAYX_VERB << "Loading PalikTable from " << f;
+    std::ifstream s(f);
 
     if (s.fail()) {
         return false;
diff --git a/Intern/rayx-core/src/VulkanEngine/Init/ShaderModule.cpp b/Intern/rayx-core/src/VulkanEngine/Init/ShaderModule.cpp
index e93d53641..230c925f0 100644
--- a/Intern/rayx-core/src/VulkanEngine/Init/ShaderModule.cpp
+++ b/Intern/rayx-core/src/VulkanEngine/Init/ShaderModule.cpp
@@ -18,7 +18,8 @@ void VulkanEngine::createShaderModule() {
 
     // the code in comp.spv was created by running the command:
     // glslangValidator.exe -V shader.comp
-    std::string path = canonicalizeRepositoryPath(m_shaderFile).string();
+    std::string path = getExecutablePath().string() + "/Shaders/comp.spv";
+    RAYX_VERB << "Loading compute shader from: " << path;
     std::vector<uint32_t> compShaderCode;
     if (auto d = readFileAlign32(path)) {
         compShaderCode = d.value();
diff --git a/Intern/rayx-ui/CMakeLists.txt b/Intern/rayx-ui/CMakeLists.txt
index c5f4eba20..7ad636c3c 100644
--- a/Intern/rayx-ui/CMakeLists.txt
+++ b/Intern/rayx-ui/CMakeLists.txt
@@ -37,11 +37,11 @@ if(Vulkan_FOUND)
 
     # ---- CPack ----
     install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
-    install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/shaders
-            DESTINATION ./
+    install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/Shaders
+            DESTINATION ./bin
             FILES_MATCHING PATTERN "*_*.spv")
     include(InstallRequiredSystemLibraries)
-    set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/../../LICENSE")
+    set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
     set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
     set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "rayx-ui - RAYX GUI Application")
     include(CPack)
@@ -85,7 +85,7 @@ if(Vulkan_FOUND)
             string(SUBSTRING ${SHADER_EXT} 1 -1 SHADER_STAGE) # Remove the leading '.' from the extension
 
             # Set output file name
-            set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/bin/shaders/${SHADER_NAME}_${SHADER_STAGE}.spv")
+            set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/bin/Shaders/${SHADER_NAME}_${SHADER_STAGE}.spv")
 
             # Create a custom command for each shader file
             add_custom_command(
diff --git a/Intern/rayx-ui/src/RenderSystem/GridRenderSystem.cpp b/Intern/rayx-ui/src/RenderSystem/GridRenderSystem.cpp
index 8ed9f0d8a..782ae7cf0 100644
--- a/Intern/rayx-ui/src/RenderSystem/GridRenderSystem.cpp
+++ b/Intern/rayx-ui/src/RenderSystem/GridRenderSystem.cpp
@@ -49,7 +49,7 @@ void GridRenderSystem::createPipeline(VkRenderPass renderPass) {
     pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
 
     // Use the grid-specific shaders
-    const std::string vertexShader = RAYX::canonicalizeRepositoryPath("build/bin/shaders/grid_shader_vert.spv").string();
-    const std::string fragmentShader = RAYX::canonicalizeRepositoryPath("build/bin/shaders/grid_shader_frag.spv").string();
+    const std::string vertexShader = RAYX::getExecutablePath().string() + "/Shaders/grid_shader_vert.spv";
+    const std::string fragmentShader = RAYX::getExecutablePath().string() + "/Shaders/grid_shader_frag.spv";
     m_Pipeline = std::make_unique<GraphicsPipeline>(m_Device, vertexShader, fragmentShader, pipelineConfig);
 }
diff --git a/Intern/rayx-ui/src/RenderSystem/ObjectRenderSystem.cpp b/Intern/rayx-ui/src/RenderSystem/ObjectRenderSystem.cpp
index 97e150e1c..f4311eb20 100644
--- a/Intern/rayx-ui/src/RenderSystem/ObjectRenderSystem.cpp
+++ b/Intern/rayx-ui/src/RenderSystem/ObjectRenderSystem.cpp
@@ -47,8 +47,8 @@ void ObjectRenderSystem::createPipeline(VkRenderPass renderPass) {
     GraphicsPipeline::defaultPipelineConfigInfo(pipelineConfig, GraphicsPipeline::VertexMode::TEXTURED);
     pipelineConfig.renderPass = renderPass;
     pipelineConfig.pipelineLayout = m_PipelineLayout;
-    const std::string vertexShader = RAYX::canonicalizeRepositoryPath("build/bin/shaders/shader_vert.spv").string();
-    const std::string fragmentShader = RAYX::canonicalizeRepositoryPath("build/bin/shaders/shader_frag.spv").string();
+    const std::string vertexShader = RAYX::getExecutablePath().string() + "/Shaders/shader_vert.spv";
+    const std::string fragmentShader = RAYX::getExecutablePath().string() + "/Shaders/shader_frag.spv";
     m_Pipeline = std::make_unique<GraphicsPipeline>(m_Device, vertexShader, fragmentShader, pipelineConfig);
 }
 
diff --git a/Intern/rayx-ui/src/RenderSystem/RayRenderSystem.cpp b/Intern/rayx-ui/src/RenderSystem/RayRenderSystem.cpp
index e1002204e..dfb7b3449 100644
--- a/Intern/rayx-ui/src/RenderSystem/RayRenderSystem.cpp
+++ b/Intern/rayx-ui/src/RenderSystem/RayRenderSystem.cpp
@@ -46,7 +46,7 @@ void RayRenderSystem::createPipeline(VkRenderPass renderPass) {
     pipelineConfig.renderPass = renderPass;
     pipelineConfig.pipelineLayout = m_PipelineLayout;
 
-    const std::string vertexShader = RAYX::canonicalizeRepositoryPath("build/bin/shaders/ray_shader_vert.spv").string();
-    const std::string fragmentShader = RAYX::canonicalizeRepositoryPath("build/bin/shaders/ray_shader_frag.spv").string();
+    const std::string vertexShader = RAYX::getExecutablePath().string() + "/Shaders/ray_shader_vert.spv";
+    const std::string fragmentShader = RAYX::getExecutablePath().string() + "/Shaders/ray_shader_frag.spv";
     m_Pipeline = std::make_unique<GraphicsPipeline>(m_Device, vertexShader, fragmentShader, pipelineConfig);
 }
\ No newline at end of file
diff --git a/Intern/rayx/CMakeLists.txt b/Intern/rayx/CMakeLists.txt
index a531534c4..450783fe5 100644
--- a/Intern/rayx/CMakeLists.txt
+++ b/Intern/rayx/CMakeLists.txt
@@ -41,15 +41,15 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_BINARY_DIR})
 # ----------------------
 
 # ---- CPack ----
-install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/shaders
-        DESTINATION ./
+install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/Shaders
+        DESTINATION ./bin
         FILES_MATCHING PATTERN "comp.spv")
-install(DIRECTORY ${CMAKE_BINARY_DIR}/../Data
-        DESTINATION ./)
+install(DIRECTORY ${CMAKE_SOURCE_DIR}/Data
+        DESTINATION ./bin)
 set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "rayx - A RAYX Beamline Simulation Tool")
 set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
 set(CPACK_PACKAGE_INSTALL_DIRECTORY "rayx")
-set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/../../LICENSE")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
 set(CPACK_PACKAGE_EXECUTABLES ${PROJECT_NAME})
 include(CPack)
 # --------------
\ No newline at end of file