diff --git a/config/Libraries.cmake b/config/Libraries.cmake
index 512669ce85a96f8cc94d8181994cfe458fa8b604..ca2af95ef5533ffaf36cbd439f58cf9bd8e28854 100644
--- a/config/Libraries.cmake
+++ b/config/Libraries.cmake
@@ -16,6 +16,9 @@ if(NOT WIN32)
 	list(APPEND vkcv_flags -fopenmp)
 endif()
 
+# add custom functions to check for git submodules
+include(${vkcv_config_ext}/Git.cmake)
+
 list(APPEND vkcv_definitions _USE_MATH_DEFINES)
 
 # some formatted printing
diff --git a/config/ext/Git.cmake b/config/ext/Git.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a943ce02ab3a170a67fae7394fa6f616239ab5b4
--- /dev/null
+++ b/config/ext/Git.cmake
@@ -0,0 +1,15 @@
+
+function(use_git_submodule submodule_path submodule_status)
+    file(GLOB path_glob "${submodule_path}/*")
+    list(LENGTH path_glob glob_len)
+
+    if(glob_len GREATER 0)
+        set(${submodule_status} TRUE PARENT_SCOPE)
+        return()
+    endif()
+
+    get_filename_component(submodule_name ${submodule_path} NAME)
+
+    message(WARNING "${submodule_name} is required..! Update the submodules!")
+    set(${submodule_status} FALSE PARENT_SCOPE)
+endfunction()
diff --git a/config/ext/ProjectFix.cmake b/config/ext/ProjectFix.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..d3f26b4a5323f473868d87cc94d39b52eafd4313
--- /dev/null
+++ b/config/ext/ProjectFix.cmake
@@ -0,0 +1,13 @@
+
+# the first argument should be the project's target
+macro(fix_project)
+    # this should fix the execution path to load local files from the project (for MSVC)
+    if(MSVC)
+        set_target_properties(${ARGV1} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+        set_target_properties(${ARGV1} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+
+        # in addition to setting the output directory, the working directory has to be set
+        # by default visual studio sets the working directory to the build directory, when using the debugger
+        set_target_properties(${ARGV1} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+    endif()
+endmacro()
diff --git a/config/lib/GLFW.cmake b/config/lib/GLFW.cmake
index 9668694de5b6887c163f74b626c71873e3f611f8..977eabc8c3916da694420eb8b069e058b94c15f2 100644
--- a/config/lib/GLFW.cmake
+++ b/config/lib/GLFW.cmake
@@ -6,14 +6,14 @@ if (glfw3_FOUND)
 
     message(${vkcv_config_msg} " GLFW    -   " ${glfw3_VERSION})
 else()
-    if (EXISTS "${vkcv_lib_path}/glfw")
+    use_git_submodule("${vkcv_lib_path}/glfw" glfw_status)
+
+    if (${glfw_status})
         add_subdirectory(${vkcv_lib}/glfw)
 
         list(APPEND vkcv_libraries glfw)
         list(APPEND vkcv_includes ${vkcv_lib_path}/glfw/include)
 
         message(${vkcv_config_msg} " GLFW    -   " ${glfw3_VERSION})
-    else()
-        message(WARNING "GLFW is required..! Update the submodules!")
     endif ()
 endif ()
diff --git a/config/lib/SPIRV_Cross.cmake b/config/lib/SPIRV_Cross.cmake
index 00ae45527d0f49c5632d71e19509871d437ae691..ce4b2e437467436daa7e1bc04975be4fa9609fef 100644
--- a/config/lib/SPIRV_Cross.cmake
+++ b/config/lib/SPIRV_Cross.cmake
@@ -5,7 +5,9 @@ if (spirv-cross_FOUND)
 
     message(${vkcv_config_msg} " SPIRV Cross    - " ${SPIRV_CROSS_VERSION})
 else()
-    if (EXISTS "${vkcv_lib_path}/SPIRV-Cross")
+    use_git_submodule("${vkcv_lib_path}/SPIRV-Cross" spirv_cross_status)
+
+    if (${spirv_cross_status})
         set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF CACHE INTERNAL "")
         set(SPIRV_CROSS_SHARED OFF CACHE INTERNAL "")
         set(SPIRV_CROSS_STATIC ON CACHE INTERNAL "")
@@ -28,7 +30,5 @@ else()
         list(APPEND vkcv_includes ${vkcv_lib_path}/SPIV-Cross/include)
 
         message(${vkcv_config_msg} " SPIRV Cross    - " ${SPIRV_CROSS_VERSION})
-    else()
-        message(WARNING "SPIRV-Cross is required..! Update the submodules!")
     endif ()
 endif ()
\ No newline at end of file
diff --git a/config/lib/VulkanMemoryAllocator.cmake b/config/lib/VulkanMemoryAllocator.cmake
index 5f670ff04633e1747accb8f1598fee028a287168..2a11f936baab99186db3ac503874e490ee69f422 100644
--- a/config/lib/VulkanMemoryAllocator.cmake
+++ b/config/lib/VulkanMemoryAllocator.cmake
@@ -1,5 +1,7 @@
 
-if (EXISTS "${vkcv_lib_path}/VulkanMemoryAllocator-Hpp")
+use_git_submodule("${vkcv_lib_path}/VulkanMemoryAllocator-Hpp" vma_hpp_status)
+
+if (${vma_hpp_status})
 	set(VMA_HPP_PATH "${vkcv_lib_path}/VulkanMemoryAllocator-Hpp" CACHE INTERNAL "")
 	
 	set(VMA_RECORDING_ENABLED OFF CACHE INTERNAL "")
@@ -17,6 +19,4 @@ if (EXISTS "${vkcv_lib_path}/VulkanMemoryAllocator-Hpp")
 	list(APPEND vkcv_includes ${vkcv_lib_path}/VulkanMemoryAllocator-Hpp)
 	
 	message(${vkcv_config_msg} " VMA     - ")
-else()
-	message(WARNING "VulkanMemoryAllocator is required..! Update the submodules!")
 endif ()
diff --git a/modules/asset_loader/config/FX_GLTF.cmake b/modules/asset_loader/config/FX_GLTF.cmake
index 37cd162422d8277022067498f5d5ba3e26e2ae1b..4164c2786d9ada53c979b98bf23f973113edfda5 100644
--- a/modules/asset_loader/config/FX_GLTF.cmake
+++ b/modules/asset_loader/config/FX_GLTF.cmake
@@ -1,5 +1,7 @@
 
-if (EXISTS "${vkcv_asset_loader_lib_path}/fx-gltf")
+use_git_submodule("${vkcv_asset_loader_lib_path}/fx-gltf" fx_gltf_status)
+
+if (${fx_gltf_status})
 	set(FX_GLTF_INSTALL OFF CACHE INTERNAL "")
 	set(FX_GLTF_USE_INSTALLED_DEPS OFF CACHE INTERNAL "")
 	set(BUILD_TESTING OFF CACHE INTERNAL "")
@@ -7,6 +9,4 @@ if (EXISTS "${vkcv_asset_loader_lib_path}/fx-gltf")
 	add_subdirectory(${vkcv_asset_loader_lib}/fx-gltf)
 	
 	list(APPEND vkcv_asset_loader_libraries fx-gltf)
-else()
-	message(WARNING "FX-GLTF is required..! Update the submodules!")
 endif ()
diff --git a/modules/asset_loader/config/NLOHMANN_JSON.cmake b/modules/asset_loader/config/NLOHMANN_JSON.cmake
index 018f6a19809fd3e53e6e790a6fe6447348e43c09..4bd7f4475ef1e748e109814d440762e27948f495 100644
--- a/modules/asset_loader/config/NLOHMANN_JSON.cmake
+++ b/modules/asset_loader/config/NLOHMANN_JSON.cmake
@@ -1,10 +1,10 @@
 
-if (EXISTS "${vkcv_asset_loader_lib_path}/json")
+use_git_submodule("${vkcv_asset_loader_lib_path}/json" json_status)
+
+if (${json_status})
 	set(JSON_BuildTests OFF CACHE INTERNAL "")
 	
 	add_subdirectory(${vkcv_asset_loader_lib}/json)
 	
 	list(APPEND vkcv_asset_loader_libraries nlohmann_json::nlohmann_json)
-else()
-	message(WARNING "NLOHMANN_JSON is required..! Update the submodules!")
 endif ()
diff --git a/modules/asset_loader/config/STB.cmake b/modules/asset_loader/config/STB.cmake
index 1287d0a9ddda559e061ddd680bc815e24b3e2075..61b7cc929b2b5ae96fbbbe479f6e9d48d9db5c69 100644
--- a/modules/asset_loader/config/STB.cmake
+++ b/modules/asset_loader/config/STB.cmake
@@ -1,10 +1,10 @@
 
-if (EXISTS "${vkcv_asset_loader_lib_path}/stb")
+use_git_submodule("${vkcv_asset_loader_lib_path}/stb" stb_status)
+
+if (${stb_status})
 	list(APPEND vkcv_asset_loader_includes ${vkcv_asset_loader_lib}/stb)
 	
 	list(APPEND vkcv_asset_loader_definitions STB_IMAGE_IMPLEMENTATION)
 	list(APPEND vkcv_asset_loader_definitions STBI_ONLY_JPEG)
 	list(APPEND vkcv_asset_loader_definitions STBI_ONLY_PNG)
-else()
-	message(WARNING "STB is required..! Update the submodules!")
 endif ()
diff --git a/modules/camera/config/GLM.cmake b/modules/camera/config/GLM.cmake
index f256ccade8c4f44a89744bb7875371324cf2369d..53960241b8c147f522afd7afa3bfedb20f4f0761 100644
--- a/modules/camera/config/GLM.cmake
+++ b/modules/camera/config/GLM.cmake
@@ -5,13 +5,13 @@ if (glm_FOUND)
     list(APPEND vkcv_camera_includes ${GLM_INCLUDE_DIRS})
     list(APPEND vkcv_camera_libraries glm)
 else()
-    if (EXISTS "${vkcv_camera_lib_path}/glm")
+    use_git_submodule("${vkcv_camera_lib_path}/glm" glm_status)
+
+    if (${glm_status})
         add_subdirectory(${vkcv_camera_lib}/glm)
 
         list(APPEND vkcv_camera_includes ${vkcv_camera_lib_path}/glm)
         list(APPEND vkcv_camera_libraries glm)
-    else()
-        message(WARNING "GLM is required..! Update the submodules!")
     endif ()
 endif ()
 
diff --git a/modules/gui/config/ImGui.cmake b/modules/gui/config/ImGui.cmake
index 90cdafdeee355af9e63723632572799e135b04da..624ea7701e245ab8c20731d2b226896667c18f89 100644
--- a/modules/gui/config/ImGui.cmake
+++ b/modules/gui/config/ImGui.cmake
@@ -1,5 +1,7 @@
 
-if (EXISTS "${vkcv_gui_lib_path}/imgui")
+use_git_submodule("${vkcv_gui_lib_path}/imgui" imgui_status)
+
+if (${imgui_status})
 	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/backends/imgui_impl_glfw.cpp)
 	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/backends/imgui_impl_glfw.h)
 	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/backends/imgui_impl_vulkan.cpp)
@@ -22,6 +24,4 @@ if (EXISTS "${vkcv_gui_lib_path}/imgui")
 	list(APPEND vkcv_gui_include ${vkcv_gui_lib})
 	
 	list(APPEND vkcv_gui_defines IMGUI_DISABLE_WIN32_FUNCTIONS=1)
-else()
-	message(WARNING "IMGUI is required..! Update the submodules!")
 endif ()
diff --git a/modules/shader_compiler/config/GLSLANG.cmake b/modules/shader_compiler/config/GLSLANG.cmake
index 50b9fd46bd0db9421c632aa0b80fb8df7e3f2123..98bd45497f9d7ed5196dbed486921f8e6ada12da 100644
--- a/modules/shader_compiler/config/GLSLANG.cmake
+++ b/modules/shader_compiler/config/GLSLANG.cmake
@@ -1,5 +1,7 @@
 
-if (EXISTS "${vkcv_shader_compiler_lib_path}/glslang")
+use_git_submodule("${vkcv_shader_compiler_lib_path}/glslang" glslang_status)
+
+if (${glslang_status})
 	set(SKIP_GLSLANG_INSTALL ON CACHE INTERNAL "")
 	set(ENABLE_SPVREMAPPER OFF CACHE INTERNAL "")
 	set(ENABLE_GLSLANG_BINARIES OFF CACHE INTERNAL "")
@@ -23,6 +25,4 @@ if (EXISTS "${vkcv_shader_compiler_lib_path}/glslang")
 	
 	list(APPEND vkcv_shader_compiler_libraries glslang SPIRV)
 	list(APPEND vkcv_shader_compiler_includes ${vkcv_shader_compiler_lib})
-else()
-	message(WARNING "GLSLANG is required..! Update the submodules!")
 endif ()
diff --git a/modules/upscaling/config/FidelityFX_FSR.cmake b/modules/upscaling/config/FidelityFX_FSR.cmake
index cc52b4189f781f534a933feb7b782b6bec333e5a..780f1d441abe2a567db7491ce5e2f4821a396b89 100644
--- a/modules/upscaling/config/FidelityFX_FSR.cmake
+++ b/modules/upscaling/config/FidelityFX_FSR.cmake
@@ -1,5 +1,7 @@
 
-if (EXISTS "${vkcv_upscaling_lib_path}/FidelityFX-FSR")
+use_git_submodule("${vkcv_upscaling_lib_path}/FidelityFX-FSR" ffx_fsr_status)
+
+if (${ffx_fsr_status})
 	include_shader(${vkcv_upscaling_lib_path}/FidelityFX-FSR/ffx-fsr/ffx_a.h ${vkcv_upscaling_include} ${vkcv_upscaling_source})
 	include_shader(${vkcv_upscaling_lib_path}/FidelityFX-FSR/ffx-fsr/ffx_fsr1.h ${vkcv_upscaling_include} ${vkcv_upscaling_source})
 	include_shader(${vkcv_upscaling_lib_path}/FidelityFX-FSR/sample/src/VK/FSR_Pass.glsl ${vkcv_upscaling_include} ${vkcv_upscaling_source})
@@ -13,6 +15,4 @@ if (EXISTS "${vkcv_upscaling_lib_path}/FidelityFX-FSR")
 	list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_include}/ffx_a.h.hxx)
 	list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_include}/ffx_fsr1.h.hxx)
 	list(APPEND vkcv_upscaling_sources ${vkcv_upscaling_include}/FSR_Pass.glsl.hxx)
-else()
-	message(WARNING "FidelityFX-FSR is required..! Update the submodules!")
 endif ()
diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt
index 9cf1ff1c9327114d28871f11694a2fb88bc00735..621371fd4e20f942a775ac73300861ba2e15dd45 100644
--- a/projects/CMakeLists.txt
+++ b/projects/CMakeLists.txt
@@ -1,4 +1,6 @@
 
+include(${vkcv_config_ext}/ProjectFix.cmake)
+
 # Add new projects/examples here:
 add_subdirectory(first_triangle)
 add_subdirectory(first_mesh)
diff --git a/projects/first_mesh/CMakeLists.txt b/projects/first_mesh/CMakeLists.txt
index 345324ac1d2c836b174c90d16c710491ee477f93..946031f922d7f6b4e2fc5db43c2ef92d48de2691 100644
--- a/projects/first_mesh/CMakeLists.txt
+++ b/projects/first_mesh/CMakeLists.txt
@@ -10,16 +10,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
 # adding source files to the project
 add_executable(first_mesh src/main.cpp)
-
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(first_mesh PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(first_mesh PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-    
-    # in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(first_mesh PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+fix_project(first_mesh)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include})
diff --git a/projects/first_scene/CMakeLists.txt b/projects/first_scene/CMakeLists.txt
index d55476f5fa62639aeaec7a3859f2f63f9c937aed..3d0a5ee7e32ea1ad4cfdd0744e00ad15d69a7541 100644
--- a/projects/first_scene/CMakeLists.txt
+++ b/projects/first_scene/CMakeLists.txt
@@ -10,16 +10,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
 # adding source files to the project
 add_executable(first_scene src/main.cpp)
-
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(first_scene PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(first_scene PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-    
-    # in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(first_scene PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+fix_project(first_scene)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include})
diff --git a/projects/first_triangle/CMakeLists.txt b/projects/first_triangle/CMakeLists.txt
index cf1fdb9022fc8332210a44946911fbfab3f5559a..793c2bc37db08c9fe744a56c97f474e1e2d17c4f 100644
--- a/projects/first_triangle/CMakeLists.txt
+++ b/projects/first_triangle/CMakeLists.txt
@@ -10,16 +10,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
 # adding source files to the project
 add_executable(first_triangle src/main.cpp)
-
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(first_triangle PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(first_triangle PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-
-	# in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(first_triangle PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+fix_project(first_triangle)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include})
diff --git a/projects/indirect_dispatch/CMakeLists.txt b/projects/indirect_dispatch/CMakeLists.txt
index ac8501f17b65212f87d00998dbf9bc4d5c044619..18a89c8e1966b1e0ee509afd716c1410d9d671d8 100644
--- a/projects/indirect_dispatch/CMakeLists.txt
+++ b/projects/indirect_dispatch/CMakeLists.txt
@@ -26,16 +26,8 @@ target_sources(indirect_dispatch PRIVATE
     
     src/MotionBlurSetup.hpp
     src/MotionBlurSetup.cpp)
-    
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(indirect_dispatch PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(indirect_dispatch PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-
-	# in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(indirect_dispatch PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+
+fix_project(indirect_dispatch)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(indirect_dispatch SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include})
diff --git a/projects/mesh_shader/CMakeLists.txt b/projects/mesh_shader/CMakeLists.txt
index 9e132e555136a7dfdd7d8fc15e06547d8059aff5..0eb0ca2e45daa7486a80ea897a2397c1d3ac1ba3 100644
--- a/projects/mesh_shader/CMakeLists.txt
+++ b/projects/mesh_shader/CMakeLists.txt
@@ -10,18 +10,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 
 # adding source files to the project
 add_executable(mesh_shader src/main.cpp)
-
-target_sources(mesh_shader PRIVATE)
-
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(mesh_shader PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(mesh_shader PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-
-	# in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(mesh_shader PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+fix_project(mesh_shader)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(mesh_shader SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_meshlet_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include})
diff --git a/projects/particle_simulation/CMakeLists.txt b/projects/particle_simulation/CMakeLists.txt
index 41ce6ca2f4042285ad42d81e79f04d7b53c837e7..2ff6aaf62c6a9842c3d1b9669286becfd79d92ca 100644
--- a/projects/particle_simulation/CMakeLists.txt
+++ b/projects/particle_simulation/CMakeLists.txt
@@ -18,15 +18,7 @@ add_executable(particle_simulation
 		src/BloomAndFlares.hpp
 		src/BloomAndFlares.cpp)
 
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(particle_simulation PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(particle_simulation PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-
-	# in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(particle_simulation PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+fix_project(particle_simulation)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(particle_simulation SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include})
diff --git a/projects/voxelization/CMakeLists.txt b/projects/voxelization/CMakeLists.txt
index 9597f9493b91ef48a5932fb22da7dce791dc450c..ba3c467766377d22925ac9c90acffee7fe324332 100644
--- a/projects/voxelization/CMakeLists.txt
+++ b/projects/voxelization/CMakeLists.txt
@@ -19,15 +19,7 @@ target_sources(voxelization PRIVATE
     src/BloomAndFlares.hpp
     src/BloomAndFlares.cpp)
 
-# this should fix the execution path to load local files from the project (for MSVC)
-if(MSVC)
-	set_target_properties(voxelization PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-	set_target_properties(voxelization PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-    
-    # in addition to setting the output directory, the working directory has to be set
-	# by default visual studio sets the working directory to the build directory, when using the debugger
-	set_target_properties(voxelization PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
+fix_project(voxelization)
 
 # including headers of dependencies and the VkCV framework
 target_include_directories(voxelization SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include} ${vkcv_upscaling_include})
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7e41ca8e8ad62ce6667ab4d9c549f2ea613d28aa
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Check if release or debug build
+CMAKE_BUILD_DIR="build"
+CMAKE_FLAGS=""
+if [ "$1" = "--debug" ]; then
+	CMAKE_BUILD_DIR="cmake-build-debug"
+	CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=Debug"
+elif [ "$1" = "--release" ]; then
+	CMAKE_BUILD_DIR="cmake-build-release"
+	CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=Release"
+fi
+
+# Navigate to the main directory of the cloned repository
+cd "$(dirname "$0")" || exit
+cd ..
+
+# Setup git lfs and the submodules
+git lfs install
+git submodule init
+git submodule update
+
+# Setup build directory
+mkdir $CMAKE_BUILD_DIR
+cd $CMAKE_BUILD_DIR || exit
+BUILD_THREADS=$(($(nproc --all) - 1))
+
+if [ $BUILD_THREADS -lt 1 ]; then
+	BUILD_THREADS=1
+fi
+
+# Build process
+cmake $CMAKE_FLAGS ..
+make -j $BUILD_THREADS "$@"
\ No newline at end of file
diff --git a/scripts/generate.sh b/scripts/generate.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cf9ff2d607217890b6fd0586e1dddece962d59b9
--- /dev/null
+++ b/scripts/generate.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+CMAKE_PROJECT_DIR="$(pwd)"
+CMAKE_PROJECT_NAME="$(basename "$CMAKE_PROJECT_DIR")"
+
+# Navigate to the main directory of the cloned repository
+cd "$(dirname "$0")" || exit
+cd ..
+
+CMAKE_FRAMEWORK_DIR="$(realpath -s --relative-to="$CMAKE_PROJECT_DIR" "$(pwd)")"
+
+# Navigate back to the project directory
+cd "$CMAKE_PROJECT_DIR" || exit
+
+test -f "CMakeLists.txt" && echo "WARNING: CMakeLists.txt exists already! Project generation stops!" && exit
+test -f "src/main.cpp" && echo "WARNING: src/main.cpp exists already! Project generation stops!" && exit
+
+generate_cmake_lists() {
+  echo "cmake_minimum_required(VERSION 3.16)"
+  echo "project($CMAKE_PROJECT_NAME)"
+  echo
+  echo "set(CMAKE_CXX_STANDARD 20)"
+  echo "set(CMAKE_CXX_STANDARD_REQUIRED ON)"
+  echo
+  echo "set(BUILD_MODULES ON CACHE INTERNAL \"\")"
+  echo "set(BUILD_PROJECTS OFF CACHE INTERNAL \"\")"
+  echo "set(BUILD_DOXYGEN_DOCS OFF CACHE INTERNAL \"\")"
+  echo "set(BUILD_SHARED OFF CACHE INTERNAL \"\")"
+  echo "add_subdirectory($CMAKE_FRAMEWORK_DIR)"
+  echo
+  echo "add_executable($CMAKE_PROJECT_NAME src/main.cpp)"
+  echo
+  echo "target_include_directories($CMAKE_PROJECT_NAME SYSTEM BEFORE PRIVATE \${vkcv_includes})"
+  echo "target_link_libraries($CMAKE_PROJECT_NAME \${vkcv_libraries})"
+}
+
+generate_main_cpp() {
+  echo "#include <vkcv/Core.hpp>"
+  echo
+  echo "int main(int argc, const char** argv) {"
+  echo "  vkcv::Core core = vkcv::Core::create("
+  echo "    \"$CMAKE_PROJECT_NAME\","
+  echo "    VK_MAKE_VERSION(0, 0, 1),"
+  echo "    { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },"
+  echo "    { VK_KHR_SWAPCHAIN_EXTENSION_NAME }"
+  echo "  );"
+  echo "  "
+  echo "  vkcv::WindowHandle windowHandle = core.createWindow(\"$CMAKE_PROJECT_NAME\", 800, 600, true);"
+  echo "  "
+  echo "  while (vkcv::Window::hasOpenWindow()) {"
+  echo "    vkcv::Window::pollEvents();"
+  echo "  }"
+  echo "}"
+}
+
+generate_cmake_lists > "CMakeLists.txt"
+
+mkdir -p "src"
+generate_main_cpp > "src/main.cpp"
diff --git a/scripts/run.sh b/scripts/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2f5a32131003b8c684adb4a4d0d9219bdc8fc3d8
--- /dev/null
+++ b/scripts/run.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Navigate to the scripts directory
+cd "$(dirname "$0")" || exit
+
+# Check if there is a project name as argument
+if [ $# -lt 1 ]; then
+	echo "You need to specify a project name to run!">&2
+	exit
+fi
+
+RUN_WITH_HUD="no"
+BUILD_FLAGS=""
+while [ $# -gt 1 ]; do
+  case "$1" in
+    "--"*)
+      if [ "$1" = "--hud" ]; then
+        RUN_WITH_HUD="yes"
+      else
+        BUILD_FLAGS="$BUILD_FLAGS$1 "
+      fi
+      shift 1;;
+    *) break;;
+  esac
+done
+
+PROJECT="$1"
+PROJECT_DIR="../projects/$PROJECT"
+shift 1
+
+# Check if the project name is valid
+if [ ! -d "$PROJECT_DIR" ]; then
+	echo "There is no project with the name '$PROJECT'!">&2
+	exit
+fi
+
+./build.sh $FLAGS "$PROJECT"
+cd "$PROJECT_DIR" || exit
+
+if [ ! -f "$PROJECT" ]; then
+	echo "Building the project '$PROJECT' failed!">&2
+	exit
+fi
+
+if [ "$RUN_WITH_HUD" = "yes" ]; then
+  MANGOHUD=1 ./"$PROJECT" "$@"
+else
+  ./"$PROJECT" "$@"
+fi
\ No newline at end of file