diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfe411c374e3d794ce3c1ee9cea162aed86e7cc0..fa60a82591425ec6c9a44828df76fe97c3dcca4f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,9 +1,11 @@
 cmake_minimum_required(VERSION 3.16)
 project(vkcv)
 
+# settings c++ standard for the framework
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
+# checking build type and setting up a variable
 if (CMAKE_BUILD_TYPE)
 	string(TOLOWER "${CMAKE_BUILD_TYPE}" _vkcv_build_type)
 	set(vkcv_build_${_vkcv_build_type} 1)
@@ -11,15 +13,19 @@ endif()
 
 message("-- Language: [ C++ " ${CMAKE_CXX_STANDARD} " ]")
 
+# setting up different paths
 set(vkcv_config ${PROJECT_SOURCE_DIR}/config)
 set(vkcv_config_ext ${vkcv_config}/ext)
 
 set(vkcv_lib lib)
 
 set(vkcv_source ${PROJECT_SOURCE_DIR}/src)
+set(vkcv_include ${PROJECT_SOURCE_DIR}/include)
 
+# initializes compiler flags with defaults
 set(vkcv_flags ${CMAKE_CXX_FLAGS})
 
+# enabling warnings in the debug build
 if (vkcv_build_debug)
 	if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
 		set(vkcv_flags ${vkcv_flags} " -Weverything")
@@ -30,19 +36,21 @@ if (vkcv_build_debug)
 	endif()
 endif()
 
+# add source files for compilation
 include(${vkcv_config}/Sources.cmake)
+
+# configure everything to use the required dependencies
 include(${vkcv_config}/Libraries.cmake)
 
+# set the compiler flags for the framework
 set(CMAKE_CXX_FLAGS ${vkcv_flags})
 
 message("-- Flags: [ ${CMAKE_CXX_FLAGS} ]")
 
+# set the compile definitions aka preprocessor variables
 add_compile_definitions(${vkcv_definitions})
 
-if (vkcv_directories)
-	include_directories(${vkcv_directories})
-endif()
-
+# create VkCV framework as static library using all source files
 add_library(vkcv STATIC ${vkcv_sources})
 
 if(MSVC)
@@ -53,9 +61,17 @@ if(MSVC)
   source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${vkcv_sources})
 endif()
 
+# add include directories from dependencies as system includes
 target_include_directories(vkcv SYSTEM BEFORE PRIVATE ${vkcv_includes})
+
+# add the own include directory for public headers
+target_include_directories(vkcv BEFORE PUBLIC ${vkcv_include})
+
+# link the framework using all required libraries
 target_link_libraries(vkcv ${vkcv_libraries})
 
+# add sub-projects/examples as targets
 add_subdirectory(projects)
 
+# add doxygen as target if installed
 include(${vkcv_config}/ext/Doxygen.cmake)
diff --git a/Doxyfile b/Doxyfile
index 071110099373bf500cc4a94fd6be5183336c7865..10040ece70cd320944009390bcedf9c4e59e417a 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -864,7 +864,8 @@ WARN_LOGFILE           =
 # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = src
+INPUT                  = src \
+                         include
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/config/Libraries.cmake b/config/Libraries.cmake
index 3b4c75ead3998641e3868ade305f281b3ce1bd93..ef199df6ed4d59acb87d6b0d6b4d2261081c82d4 100644
--- a/config/Libraries.cmake
+++ b/config/Libraries.cmake
@@ -1,5 +1,5 @@
-set(vkcv_config_lib ${vkcv_config}/lib)
 
+set(vkcv_config_lib ${vkcv_config}/lib)
 set(vkcv_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_lib})
 
 if(NOT WIN32)
@@ -10,21 +10,27 @@ if(NOT WIN32)
 	list(APPEND vkcv_flags -fopenmp)
 endif()
 
+# some formatted printing
 set(vkcv_config_msg " - Library: ")
 
+# load dependencies via separate cmake file
 include(${vkcv_config_lib}/GLFW.cmake)    # glfw-x11 / glfw-wayland					# libglfw3-dev
 include(${vkcv_config_lib}/Vulkan.cmake)  # vulkan-intel / vulkan-radeon / nvidia	# libvulkan-dev
 
+# cleanup of compiler flags
 if (vkcv_flags)
     list(REMOVE_DUPLICATES vkcv_flags)
 endif()
 
+# cleanup of include directories from dependencies
 if (vkcv_includes)
     list(REMOVE_DUPLICATES vkcv_includes)
 endif ()
 
+# fix dependencies for different Linux distros (looking at you Ubuntu)
 include(${vkcv_config_ext}/CheckLibraries.cmake)
 
+# cleanup of compiler definitions aka preprocessor variables
 if (vkcv_definitions)
     list(REMOVE_DUPLICATES vkcv_definitions)
 endif ()
diff --git a/config/Sources.cmake b/config/Sources.cmake
index 9a9f55747194ab9972254d5bf57ac11735607b06..e390e997071d86f5dcd1f4744a1f8bfd348d0c99 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -1,9 +1,12 @@
 
+# adding all source files and header files of the framework:
 set(vkcv_sources
-		${vkcv_source}/vkcv/Context.hpp
-		${vkcv_source}/vkcv/Context.cpp
-		${vkcv_source}/vkcv/Window.hpp
+		${vkcv_include}/vkcv/Core.hpp
+		${vkcv_source}/vkcv/Core.cpp
+
+		${vkcv_include}/vkcv/Handles.hpp
+		${vkcv_source}/vkcv/Handles.cpp
+
+		${vkcv_include}/vkcv/Window.hpp
 		${vkcv_source}/vkcv/Window.cpp
-		${vkcv_source}/vkcv/CoreManager.hpp
-		${vkcv_source}/vkcv/CoreManager.cpp
 )
diff --git a/config/ext/CheckLibraries.cmake b/config/ext/CheckLibraries.cmake
index 97950d1123f126cc555f376b86c90ed1acb2628e..3da1c06ebb529895bef1d8198c1a063173982394 100644
--- a/config/ext/CheckLibraries.cmake
+++ b/config/ext/CheckLibraries.cmake
@@ -1,6 +1,8 @@
 
+# cleanup of dependency libraries
 list(REMOVE_DUPLICATES vkcv_libraries)
 
+# fixing paths of libraries to work on most Linux distros
 foreach (a_lib IN LISTS vkcv_libraries)
     if (NOT EXISTS "${a_lib}")
         string(REGEX MATCH ^/usr/lib/x86_64-linux-gnu/.*$ vkcv_usr_lib_u_match ${a_lib})
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a347380ece98514049bdac3b7f7d8fee008d15bb
--- /dev/null
+++ b/include/vkcv/Core.hpp
@@ -0,0 +1,129 @@
+#pragma once
+/**
+ * @file src/vkcv/Core.hpp
+ * @brief Handling of global states regarding dependencies
+ */
+
+#include <vulkan/vulkan.hpp>
+#include "vkcv/Handles.hpp"
+
+namespace vkcv
+{
+    // TODO:
+    class Buffer;
+    class Renderpass;
+    class Pipeline;
+
+    class Core final
+    {
+    private:
+        class Context
+        {
+        public:
+            /**
+             * Constructor of #Context requires an @p instance, a @p physicalDevice and a @p device.
+             *
+             * @param instance Vulkan-Instance
+             * @param physicalDevice Vulkan-PhysicalDevice
+             * @param device Vulkan-Device
+             */
+            Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device) noexcept;
+            // explicit destruction of default constructor
+            Context() = delete;
+            // is never called directly
+            ~Context() noexcept;
+
+            Context(const Context &other) = delete; // copy-ctor
+            Context(Context &&other) noexcept; // move-ctor
+
+            Context & operator=(const Context &other) = delete; // copy assignment
+            Context & operator=(Context &&other) noexcept; // move assignment
+
+            const vk::Instance &getInstance() const;
+            const vk::PhysicalDevice &getPhysicalDevice() const;
+            const vk::Device &getDevice() const;
+
+        private:
+            vk::Instance        m_Instance;
+            vk::PhysicalDevice  m_PhysicalDevice;
+            vk::Device          m_Device;
+        } m_Context;
+
+        /**
+         * Constructor of #Core requires an @p context.
+         *
+         * @param context encapsulates various Vulkan objects
+         */
+        explicit Core(Context &&context) noexcept;
+        // explicit destruction of default constructor
+        Core() = delete;
+
+    public:
+        /**
+         * Destructor of #Core destroys the Vulkan objects contained in the core's context.
+         */
+        ~Core() noexcept = default;
+
+        /**
+         * Copy-constructor of #Core is deleted!
+         *
+         * @param other Other instance of #Context
+         */
+        Core(const Core& other) = delete;
+
+        /**
+         * Move-constructor of #Core uses default behavior!
+         *
+         * @param other Other instance of #Context
+         */
+        Core(Core &&other) = delete; // move-ctor
+
+        /**
+         * Copy assignment operator of #Core is deleted!
+         *
+         * @param other Other instance of #Context
+         * @return Reference to itself
+         */
+        Core & operator=(const Core &other) = delete;
+
+        /**
+         * Move assignment operator of #Core uses default behavior!
+         *
+         * @param other Other instance of #Context
+         * @return Reference to itself
+         */
+        Core & operator=(Core &&other) = delete;
+
+        [[nodiscard]]
+        const Context &getContext() const;
+
+        /**
+             * Creates a #Core with given @p applicationName and @p applicationVersion for your application.
+             *
+             * It is also possible to require a specific amount of queues, ask for specific queue-flags or
+             * extensions. This function will take care of the required arguments as best as possible.
+             *
+             * To pass a valid version for your application, you should use #VK_MAKE_VERSION().
+             *
+             * @param[in] applicationName Name of the application
+             * @param[in] applicationVersion Version of the application
+             * @param[in] queueCount (optional) Amount of queues which is requested
+             * @param[in] queueFlags (optional) Requested flags of queues
+             * @param[in] instanceExtensions (optional) Requested instance extensions
+             * @param[in] deviceExtensions (optional) Requested device extensions
+             * @return New instance of #Context
+             */
+        static Core create(const char *applicationName,
+                           uint32_t applicationVersion,
+                           uint32_t queueCount,
+                           std::vector<vk::QueueFlagBits> queueFlags    = {},
+                           std::vector<const char*> instanceExtensions  = {},
+                           std::vector<const char*> deviceExtensions    = {});
+
+        // TODO:
+        BufferHandle createBuffer(const Buffer &buf);
+        PassHandle createRenderPass(const Renderpass &pass) ;
+        PipelineHandle createPipeline(const Pipeline &pipeline);
+
+    };
+}
diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ec2bc058409e9119695700b2b727be9426c2bcd
--- /dev/null
+++ b/include/vkcv/Handles.hpp
@@ -0,0 +1,16 @@
+#pragma once
+/**
+ * @authors Artur Wasmut
+ * @file src/vkcv/Handles.cpp
+ * @brief Central header file for all possible handles that the framework will hand out.
+ */
+
+#include <cstdint>
+
+namespace vkcv
+{
+    // Handle returned for any buffer created with the core/context objects
+    struct BufferHandle     {uint64_t id;};
+    struct PassHandle       {uint64_t id;};
+    struct PipelineHandle   {uint64_t id;};
+}
diff --git a/src/vkcv/Window.hpp b/include/vkcv/Window.hpp
similarity index 98%
rename from src/vkcv/Window.hpp
rename to include/vkcv/Window.hpp
index 62440d90143d5c4cd9a31fbdf46819fdeda2d101..080e55350ba82ae58da8afcc8758da3fda77f19f 100644
--- a/src/vkcv/Window.hpp
+++ b/include/vkcv/Window.hpp
@@ -8,6 +8,9 @@
 #define GLFW_INCLUDE_VULKAN
 #include <GLFW/glfw3.h>
 
+#define NOMINMAX
+#include <algorithm>
+
 namespace vkcv {
 
     class Window final {
diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt
index 27305956cac6670331096364a6658a90efcc831b..f7687bca4ba7cb05835c8afda1396ad319a035c7 100644
--- a/projects/CMakeLists.txt
+++ b/projects/CMakeLists.txt
@@ -1,2 +1,3 @@
 
+# Add new projects/examples here:
 add_subdirectory(first_triangle)
diff --git a/projects/first_triangle/CMakeLists.txt b/projects/first_triangle/CMakeLists.txt
index c5a9046881dbab737b357b8a3cd875a9c6b284ae..40e016a71cd3e20690f3ace9ec0260aa37449a0c 100644
--- a/projects/first_triangle/CMakeLists.txt
+++ b/projects/first_triangle/CMakeLists.txt
@@ -1,10 +1,15 @@
 cmake_minimum_required(VERSION 3.16)
 project(first_triangle)
 
+# setting c++ standard for the project
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
+# adding source files to the project
 add_executable(first_triangle src/main.cpp)
 
-target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_source} ${vkcv_includes})
+# including headers of dependencies and the VkCV framework
+target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes})
+
+# linking with libraries from all dependencies and the VkCV framework
 target_link_libraries(first_triangle vkcv ${vkcv_libraries})
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index cc592f468e0c3e95d64a1558404873c4ca19f8b9..0c981a25dc52db4363d2bc7835df3c3c9d7c49fa 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -1,5 +1,5 @@
 #include <iostream>
-#include <vkcv/Context.hpp>
+#include <vkcv/Core.hpp>
 #include <vkcv/Window.hpp>
 
 int main(int argc, const char** argv) {
@@ -10,13 +10,14 @@ int main(int argc, const char** argv) {
         600,
 		false
 	);
-	vkcv::Context context = vkcv::Context::create(
+	vkcv::Core core = vkcv::Core::create(
             applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		20,
 		{vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eTransfer}
 	);
 
+	const auto &context = core.getContext();
 	const vk::Instance& instance = context.getInstance();
 	const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
 	const vk::Device& device = context.getDevice();
@@ -32,7 +33,30 @@ int main(int argc, const char** argv) {
 		default: std::cout << "Unknown GPU vendor?! Either you're on an exotic system or your driver is broken..." << std::endl;
 	}
 
-	while (window.isWindowOpen()) {
+	/*
+	 * BufferHandle triangleVertices = core.createBuffer(vertices);
+	 * BufferHandle triangleIndices = core.createBuffer(indices);
+	 *
+	 * // triangle Model creation goes here
+	 *
+	 *
+	 * // attachment creation goes here
+	 * PassHandle trianglePass = core.CreatePass(presentationPass);
+	 *
+	 * // shader creation goes here
+	 * // material creation goes here
+	 *
+	 * PipelineHandle trianglePipeline = core.CreatePipeline(trianglePipeline);
+	 */
+
+	while (window.isWindowOpen())
+	{
+        // core.beginFrame(); or something like that
+	    // core.execute(trianglePass, trianglePipeline, triangleModel);
+	    // core.endFrame(); or something like that
+
+	    // TBD: synchronization
+
 		window.pollEvents();
 	}
 	return 0;
diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp
deleted file mode 100644
index 3d5dfca627a064a49a57a015b23c4c7d919a2f07..0000000000000000000000000000000000000000
--- a/src/vkcv/Context.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
- * @authors Tobias Frisch, Vanessa Karolek, Katharina Krämer, Sebastian Gaida
- * @file src/vkcv/Context.cpp
- * @brief Context class to handle instance, physical-device and device
- */
-
-#include "Context.hpp"
-#include "CoreManager.hpp"
-
-namespace vkcv {
-
-	Context::Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device)
-		: m_instance(instance), m_physicalDevice(physicalDevice), m_device(device)
-	{}
-
-	Context::~Context() {
-		m_device.destroy();
-		m_instance.destroy();
-		vkcv::terminateGLFW();
-	}
-
-	Context Context::create(const char* applicationName, uint32_t applicationVersion, uint32_t queueCount, std::vector<vk::QueueFlagBits> queueFlags, std::vector<const char*> instanceExtensions, std::vector<const char*> deviceExtensions) {
-		vkcv::initGLFW();
-
-		// check for layer support
-		
-		const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
-		
-		std::vector<const char*> supportedLayers;
-		supportedLayers.reserve(layerProperties.size());
-		
-		for (auto& elem : layerProperties) {
-			supportedLayers.push_back(elem.layerName);
-		}
-
-// if in debug mode, check if validation layers are supported. Enable them if supported
-#ifndef NDEBUG
-		std::vector<const char*> validationLayers = {
-			"VK_LAYER_KHRONOS_validation"
-		};
-		
-		if (!Context::checkSupport(supportedLayers, validationLayers)) {
-			throw std::runtime_error("Validation layers requested but not available!");
-		}
-#endif
-		
-		// check for extension support
-		std::vector<vk::ExtensionProperties> instanceExtensionProperties = vk::enumerateInstanceExtensionProperties();
-		
-		std::vector<const char*> supportedExtensions;
-		supportedExtensions.reserve(instanceExtensionProperties.size());
-		
-		for (auto& elem : instanceExtensionProperties) {
-			supportedExtensions.push_back(elem.extensionName);
-		}
-		
-		if (!checkSupport(supportedExtensions, instanceExtensions)) {
-			throw std::runtime_error("The requested instance extensions are not supported!");
-		}
-
-		// for GLFW: get all required extensions
-		std::vector<const char*> requiredExtensions = Context::getRequiredExtensions();
-		instanceExtensions.insert(instanceExtensions.end(), requiredExtensions.begin(), requiredExtensions.end());
-
-		const vk::ApplicationInfo applicationInfo(
-			applicationName,
-			applicationVersion,
-			"vkCV",
-			VK_MAKE_VERSION(0, 0, 1),
-			VK_HEADER_VERSION_COMPLETE
-		);
-
-		vk::InstanceCreateInfo instanceCreateInfo(
-			vk::InstanceCreateFlags(),
-			&applicationInfo,
-			0,
-			nullptr,
-			static_cast<uint32_t>(instanceExtensions.size()),
-			instanceExtensions.data()
-		);
-
-#ifndef NDEBUG
-		instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
-		instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
-#endif
-
-		vk::Instance instance = vk::createInstance(instanceCreateInfo);
-
-		std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
-		vk::PhysicalDevice physicalDevice = pickPhysicalDevice(instance);
-
-		// check for physical device extension support
-		std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties();
-		supportedExtensions.clear();
-		for (auto& elem : deviceExtensionProperties) {
-			supportedExtensions.push_back(elem.extensionName);
-		}
-		if (!checkSupport(supportedExtensions, deviceExtensions)) {
-			throw std::runtime_error("The requested device extensions are not supported by the physical device!");
-		}
-
-		//vector to define the queue priorities
-		std::vector<float> qPriorities;
-		qPriorities.resize(queueCount, 1.f); // all queues have the same priorities
-
-		// create required queues
-		std::vector<vk::DeviceQueueCreateInfo> qCreateInfos = getQueueCreateInfos(physicalDevice, queueCount, qPriorities,queueFlags);
-
-		vk::DeviceCreateInfo deviceCreateInfo(
-			vk::DeviceCreateFlags(),
-			qCreateInfos.size(),
-			qCreateInfos.data(),
-			0,
-			nullptr,
-			deviceExtensions.size(),
-			deviceExtensions.data(),
-			nullptr		// Should our device use some features??? If yes: TODO
-		);
-
-#ifndef NDEBUG
-		deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
-		deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
-#endif
-
-
-		vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
-		// TODO: implement device.getQueue() to access the queues, if needed
-
-		return Context(instance, physicalDevice, device);
-	}
-
-	const vk::Instance& Context::getInstance() const {
-		return m_instance;
-	}
-
-	const vk::PhysicalDevice& Context::getPhysicalDevice() const {
-		return m_physicalDevice;
-	}
-
-	const vk::Device& Context::getDevice() const {
-		return m_device;
-	}
-
-	vk::PhysicalDevice Context::pickPhysicalDevice(vk::Instance& instance) {
-		vk::PhysicalDevice phyDevice;
-		std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
-
-		if (devices.empty()) {
-			throw std::runtime_error("failed to find GPUs with Vulkan support!");
-		}
-
-		int max_score = -1;
-		for (const auto& device : devices) {
-			int score = deviceScore(device);
-			if (score > max_score) {
-				max_score = score;
-				phyDevice = device;
-			}
-		}
-
-		if (max_score == -1) {
-			throw std::runtime_error("failed to find a suitable GPU!");
-		}
-
-		return phyDevice;
-	}
-
-	int Context::deviceScore(const vk::PhysicalDevice& physicalDevice) {
-		int score = 0;
-		vk::PhysicalDeviceProperties properties = physicalDevice.getProperties();
-		std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
-
-		// for every queue family compute queue flag bits and the amount of queues
-		for (const auto& qFamily : qFamilyProperties) {
-			uint32_t qCount = qFamily.queueCount;
-			uint32_t bitCount = (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0)
-				+ (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0)
-				+ (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0)
-				+ (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eSparseBinding) != 0);
-			score += static_cast<int>(qCount * bitCount);
-		}
-
-		// compute the VRAM of the physical device
-		vk::PhysicalDeviceMemoryProperties memoryProperties = physicalDevice.getMemoryProperties();
-		int vram = static_cast<int>(memoryProperties.memoryHeaps[0].size / 1E9);
-		score *= vram;
-
-		if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
-			score *= 2;
-		}
-		else if (properties.deviceType != vk::PhysicalDeviceType::eIntegratedGpu) {
-			score = -1;
-		}
-
-		return score;
-	}
-
-	std::vector<vk::DeviceQueueCreateInfo> Context::getQueueCreateInfos(vk::PhysicalDevice& physicalDevice, uint32_t queueCount,std::vector<float> &qPriorities, std::vector<vk::QueueFlagBits>& queueFlags) {
-		std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
-		std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
-		std::vector<vk::QueueFamilyProperties> qFamilyCandidates;
-
-		// search for queue families which support the desired queue flag bits
-		for (auto& qFamily : qFamilyProperties) {
-			bool supported = true;
-			for (auto qFlag : queueFlags) {
-				supported = supported && (static_cast<uint32_t>(qFlag & qFamily.queueFlags) != 0);
-			}
-			if (supported) {
-				qFamilyCandidates.push_back(qFamily);
-			}
-		}
-
-		uint32_t create = queueCount;
-		for (uint32_t i = 0; i < qFamilyCandidates.size() && create > 0; i++) {
-			const int maxCreatableQueues = std::min(create, qFamilyCandidates[i].queueCount);		
-			vk::DeviceQueueCreateInfo qCreateInfo(
-				vk::DeviceQueueCreateFlags(),
-				i,
-				maxCreatableQueues,
-				qPriorities.data()
-			);
-			queueCreateInfos.push_back(qCreateInfo);
-			create -= maxCreatableQueues;
-		}
-
-		return queueCreateInfos;
-	}
-
-	bool Context::checkSupport(std::vector<const char*>& supported, std::vector<const char*>& check) {
-		for (auto checkElem : check) {
-			bool found = false;
-			for (auto supportedElem : supported) {
-				if (strcmp(supportedElem, checkElem) == 0) {
-					found = true;
-					break;
-				}
-			}
-			if (!found)
-				return false;
-		}
-		return true;
-	}
-
-	std::vector<const char*> Context::getRequiredExtensions() {
-		uint32_t glfwExtensionCount = 0;
-		const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
-		std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
-
-#ifndef NDEBUG
-	extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
-#endif
-
-		return extensions;
-	}
-}
diff --git a/src/vkcv/Context.hpp b/src/vkcv/Context.hpp
deleted file mode 100644
index 1d11f82743ada5d1493df48ece54e558c234df47..0000000000000000000000000000000000000000
--- a/src/vkcv/Context.hpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#pragma once
-/**
- * @authors Tobias Frisch, Vanessa Karolek, Katharina Krämer, Sebastian Gaida
- * @file src/vkcv/Context.hpp
- * @brief Context class to handle instance, physical-device and device
- */
-
-#include <vulkan/vulkan.hpp>
-
-namespace vkcv {
-
-	class Context final {
-	private:
-		vk::Instance m_instance;
-		vk::PhysicalDevice m_physicalDevice;
-		vk::Device m_device;
-
-		/**
-		 * Constructor of #Context requires an @p instance, a @p physicalDevice and a @p device.
-		 *
-		 * @param instance Vulkan-Instance
-		 * @param physicalDevice Vulkan-PhysicalDevice
-		 * @param device Vulkan-Device
-		 */
-		Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device);
-
-	public:
-		/**
-		 * Copy-constructor of #Context is deleted!
-		 *
-		 * @param other Other instance of #Context
-		 */
-		Context(const Context &other) = delete;
-		
-		/**
-		 * Move-constructor of #Context uses default behavior!
-		 *
-		 * @param other Other instance of #Context
-		 */
-		Context(Context &&other) = default;
-
-		/**
-		 * Get the Vulkan handle for the instance.
-		 *
-		 * @return Vulkan-Instance
-		 */
-		[[nodiscard]]
-		const vk::Instance& getInstance() const;
-		
-		/**
-		 * Get the Vulkan handle for the physical-device.
-		 *
-		 * @return Vulkan-PhysicalDevice
-		 */
-		[[nodiscard]]
-		const vk::PhysicalDevice& getPhysicalDevice() const;
-		
-		/**
-		 * Get the Vulkan handle for the device.
-		 *
-		 * @return Vulkan-Device
-		 */
-		[[nodiscard]]
-		const vk::Device& getDevice() const;
-
-		/**
-		 * Destructor of #Context
-		 */
-		virtual ~Context();
-
-		/**
-		 * Copy-operator of #Context is deleted!
-		 *
-		 * @param other Other instance of #Context
-		 * @return Reference to itself
-		 */
-		Context& operator=(const Context &other) = delete;
-		
-		/**
-		 * Move-operator of #Context uses default behavior!
-		 *
-		 * @param other Other instance of #Context
-		 * @return Reference to itself
-		 */
-		Context& operator=(Context &&other) = default;
-
-		/**
-		 * Creates a #Context with given @p applicationName and @p applicationVersion for your application.
-		 *
-		 * It is also possible to require a specific amount of queues, ask for specific queue-flags or
-		 * extensions. This function will take care of the required arguments as best as possible.
-		 *
-		 * To pass a valid version for your application, you should use #VK_MAKE_VERSION().
-		 *
-		 * @param[in] applicationName Name of the application
-		 * @param[in] applicationVersion Version of the application
-		 * @param[in] queueCount (optional) Amount of queues which is requested
-		 * @param[in] queueFlags (optional) Requested flags of queues
-		 * @param[in] instanceExtensions (optional) Requested instance extensions
-		 * @param[in] deviceExtensions (optional) Requested device extensions
-		 * @return New instance of #Context
-		 */
-		static Context create(const char* applicationName, uint32_t applicationVersion, uint32_t queueCount = 1, std::vector<vk::QueueFlagBits> queueFlags = {}, std::vector<const char*> instanceExtensions = {}, std::vector<const char*> deviceExtensions = {});
-
-		/**
-		 * @brief With the help of the reference "supported" all elements in "check" checked,
-		 * if they are supported by the physical device.
-		 * @param supported The reference that can be used to check "check"
-		 * @param check The elements to be checked
-		 * @return True, if all elements in "check" are supported
-		*/
-		static bool checkSupport(std::vector<const char*> &supported, std::vector<const char*> &check);
-
-		/**
-		 * @brief Gets all extensions required, i.e. GLFW and advanced debug extensions.
-		 * @return The required extensions
-		*/
-		static std::vector<const char*> getRequiredExtensions();
-
-		/**
-		 * @brief All existing physical devices will be evaluated by deviceScore.
-		 * @param instance The instance
-		 * @return The optimal physical device
-		 * @see Context.deviceScore
-		*/
-		static vk::PhysicalDevice pickPhysicalDevice(vk::Instance& instance);
-
-		/**
-		 * @brief The physical device is evaluated by three categories:
-		 * discrete GPU vs. integrated GPU, amount of queues and its abilities, and VRAM.physicalDevice.
-		 * @param physicalDevice The physical device
-		 * @return Device score as integer
-		*/
-		static int deviceScore(const vk::PhysicalDevice &physicalDevice);
-
-		/**
-		 * @brief Creates a candidate list of queues that all meet the desired flags and then creates the maximum possible number
-		 * of queues. If the number of desired queues is not sufficient, the remaining queues are created from the next
-		 * candidate from the list.
-		 * @param physicalDevice The physical device
-		 * @param queueCount The amount of queues to be created
-		 * @param qPriorities 
-		 * @param queueFlags The abilities which have to be supported by any created queue
-		 * @return 
-		*/
-		static std::vector<vk::DeviceQueueCreateInfo> getQueueCreateInfos(vk::PhysicalDevice& physicalDevice, uint32_t queueCount, std::vector<float>& qPriorities, std::vector<vk::QueueFlagBits> &queueFlags);
-	};
-
-}
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..962f55606d492501a95bc3e31c736e1869f61d53
--- /dev/null
+++ b/src/vkcv/Core.cpp
@@ -0,0 +1,325 @@
+/**
+ * @authors Sebastian Gaida
+ * @file src/vkcv/CoreManager.cpp
+ * @brief Handling of global states regarding dependencies
+ */
+
+#include "vkcv/Core.hpp"
+
+namespace vkcv
+{
+    /**
+     * @brief The physical device is evaluated by three categories:
+     * discrete GPU vs. integrated GPU, amount of queues and its abilities, and VRAM.physicalDevice.
+     * @param physicalDevice The physical device
+     * @return Device score as integer
+    */
+    int deviceScore(const vk::PhysicalDevice& physicalDevice)
+    {
+        int score = 0;
+        vk::PhysicalDeviceProperties properties = physicalDevice.getProperties();
+        std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
+
+        // for every queue family compute queue flag bits and the amount of queues
+        for (const auto& qFamily : qFamilyProperties) {
+            uint32_t qCount = qFamily.queueCount;
+            uint32_t bitCount = (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0)
+                                + (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0)
+                                + (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0)
+                                + (static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eSparseBinding) != 0);
+            score += static_cast<int>(qCount * bitCount);
+        }
+
+        // compute the VRAM of the physical device
+        vk::PhysicalDeviceMemoryProperties memoryProperties = physicalDevice.getMemoryProperties();
+        auto vram = static_cast<int>(memoryProperties.memoryHeaps[0].size / static_cast<uint32_t>(1E9));
+        score *= vram;
+
+        if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
+            score *= 2;
+        }
+        else if (properties.deviceType != vk::PhysicalDeviceType::eIntegratedGpu) {
+            score = -1;
+        }
+
+        return score;
+    }
+
+    /**
+     * @brief All existing physical devices will be evaluated by deviceScore.
+     * @param instance The instance
+     * @return The optimal physical device
+     * @see Context.deviceScore
+    */
+    vk::PhysicalDevice pickPhysicalDevice(vk::Instance& instance)
+    {
+        vk::PhysicalDevice phyDevice;
+        std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
+
+        if (devices.empty()) {
+            throw std::runtime_error("failed to find GPUs with Vulkan support!");
+        }
+
+        int max_score = -1;
+        for (const auto& device : devices) {
+            int score = deviceScore(device);
+            if (score > max_score) {
+                max_score = score;
+                phyDevice = device;
+            }
+        }
+
+        if (max_score == -1) {
+            throw std::runtime_error("failed to find a suitable GPU!");
+        }
+
+        return phyDevice;
+    }
+
+
+    /**
+     * @brief Creates a candidate list of queues that all meet the desired flags and then creates the maximum possible number
+     * of queues. If the number of desired queues is not sufficient, the remaining queues are created from the next
+     * candidate from the list.
+     * @param physicalDevice The physical device
+     * @param queueCount The amount of queues to be created
+     * @param qPriorities
+     * @param queueFlags The abilities which have to be supported by any created queue
+     * @return
+    */
+    std::vector<vk::DeviceQueueCreateInfo> getQueueCreateInfos(vk::PhysicalDevice& physicalDevice,
+                                                               uint32_t queueCount,
+                                                               std::vector<float> &qPriorities,
+                                                               std::vector<vk::QueueFlagBits>& queueFlags)
+    {
+        std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
+        std::vector<vk::QueueFamilyProperties> qFamilyProperties = physicalDevice.getQueueFamilyProperties();
+        std::vector<vk::QueueFamilyProperties> qFamilyCandidates;
+
+        // search for queue families which support the desired queue flag bits
+        for (auto& qFamily : qFamilyProperties) {
+            bool supported = true;
+            for (auto qFlag : queueFlags) {
+                supported = supported && (static_cast<uint32_t>(qFlag & qFamily.queueFlags) != 0);
+            }
+            if (supported) {
+                qFamilyCandidates.push_back(qFamily);
+            }
+        }
+
+        uint32_t create = queueCount;
+        for (uint32_t i = 0; i < qFamilyCandidates.size() && create > 0; i++) {
+            const uint32_t maxCreatableQueues = std::min(create, qFamilyCandidates[i].queueCount);
+            vk::DeviceQueueCreateInfo qCreateInfo(
+                    vk::DeviceQueueCreateFlags(),
+                    i,
+                    maxCreatableQueues,
+                    qPriorities.data()
+            );
+            queueCreateInfos.push_back(qCreateInfo);
+            create -= maxCreatableQueues;
+        }
+
+        return queueCreateInfos;
+    }
+
+    /**
+     * @brief With the help of the reference "supported" all elements in "check" checked,
+     * if they are supported by the physical device.
+     * @param supported The reference that can be used to check "check"
+     * @param check The elements to be checked
+     * @return True, if all elements in "check" are supported
+    */
+    bool checkSupport(std::vector<const char*>& supported, std::vector<const char*>& check)
+    {
+        for (auto checkElem : check) {
+            bool found = false;
+            for (auto supportedElem : supported) {
+                if (strcmp(supportedElem, checkElem) == 0) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+                return false;
+        }
+        return true;
+    }
+
+    Core Core::create(const char *applicationName,
+                      uint32_t applicationVersion,
+                      uint32_t queueCount,
+                      std::vector<vk::QueueFlagBits> queueFlags,
+                      std::vector<const char *> instanceExtensions,
+                      std::vector<const char *> deviceExtensions)
+    {
+
+        // check for layer support
+
+        const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
+
+        std::vector<const char*> supportedLayers;
+        supportedLayers.reserve(layerProperties.size());
+
+        for (auto& elem : layerProperties) {
+            supportedLayers.push_back(elem.layerName);
+        }
+
+// if in debug mode, check if validation layers are supported. Enable them if supported
+#ifndef NDEBUG
+        std::vector<const char*> validationLayers = {
+                "VK_LAYER_KHRONOS_validation"
+        };
+
+        if (!checkSupport(supportedLayers, validationLayers)) {
+            throw std::runtime_error("Validation layers requested but not available!");
+        }
+#endif
+
+        // check for extension support
+        std::vector<vk::ExtensionProperties> instanceExtensionProperties = vk::enumerateInstanceExtensionProperties();
+
+        std::vector<const char*> supportedExtensions;
+        supportedExtensions.reserve(instanceExtensionProperties.size());
+
+        for (auto& elem : instanceExtensionProperties) {
+            supportedExtensions.push_back(elem.extensionName);
+        }
+
+        if (!checkSupport(supportedExtensions, instanceExtensions)) {
+            throw std::runtime_error("The requested instance extensions are not supported!");
+        }
+
+#ifndef NDEBUG
+        instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+#endif
+
+        const vk::ApplicationInfo applicationInfo(
+                applicationName,
+                applicationVersion,
+                "vkCV",
+                VK_MAKE_VERSION(0, 0, 1),
+                VK_HEADER_VERSION_COMPLETE
+        );
+
+        vk::InstanceCreateInfo instanceCreateInfo(
+                vk::InstanceCreateFlags(),
+                &applicationInfo,
+                0,
+                nullptr,
+                static_cast<uint32_t>(instanceExtensions.size()),
+                instanceExtensions.data()
+        );
+
+#ifndef NDEBUG
+        instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
+        instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
+#endif
+
+        vk::Instance instance = vk::createInstance(instanceCreateInfo);
+
+        std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
+        vk::PhysicalDevice physicalDevice = pickPhysicalDevice(instance);
+
+        // check for physical device extension support
+        std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties();
+        supportedExtensions.clear();
+        for (auto& elem : deviceExtensionProperties) {
+            supportedExtensions.push_back(elem.extensionName);
+        }
+        if (!checkSupport(supportedExtensions, deviceExtensions)) {
+            throw std::runtime_error("The requested device extensions are not supported by the physical device!");
+        }
+
+        //vector to define the queue priorities
+        std::vector<float> qPriorities;
+        qPriorities.resize(queueCount, 1.f); // all queues have the same priorities
+
+        // create required queues
+        std::vector<vk::DeviceQueueCreateInfo> qCreateInfos = getQueueCreateInfos(physicalDevice, queueCount, qPriorities,queueFlags);
+
+        vk::DeviceCreateInfo deviceCreateInfo(
+                vk::DeviceCreateFlags(),
+                qCreateInfos.size(),
+                qCreateInfos.data(),
+                0,
+                nullptr,
+                deviceExtensions.size(),
+                deviceExtensions.data(),
+                nullptr		// Should our device use some features??? If yes: TODO
+        );
+
+#ifndef NDEBUG
+        deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
+        deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
+#endif
+
+
+        vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
+        // TODO: implement device.getQueue() to access the queues, if needed
+        Context context(instance, physicalDevice, device);
+
+        return Core(std::move(context));
+    }
+
+    const Core::Context &Core::getContext() const
+    {
+        return m_Context;
+    }
+
+    Core::Core(Core::Context &&context) noexcept :
+            m_Context(std::move(context))
+    {}
+
+    Core::Context::Context(vk::Instance instance,
+                           vk::PhysicalDevice physicalDevice,
+                           vk::Device device) noexcept :
+    m_Instance{instance},
+    m_PhysicalDevice{physicalDevice},
+    m_Device{device}
+    {}
+
+    Core::Context::~Context() noexcept
+    {
+        m_Device.destroy();
+        m_Instance.destroy();
+    }
+
+    const vk::Instance &Core::Context::getInstance() const
+    {
+        return m_Instance;
+    }
+
+    const vk::PhysicalDevice &Core::Context::getPhysicalDevice() const
+    {
+        return m_PhysicalDevice;
+    }
+
+    const vk::Device &Core::Context::getDevice() const
+    {
+        return m_Device;
+    }
+
+    Core::Context::Context(Core::Context &&other) noexcept:
+    m_Instance(other.m_Instance),
+    m_PhysicalDevice(other.m_PhysicalDevice),
+    m_Device(other.m_Device)
+    {
+        other.m_Instance        = nullptr;
+        other.m_PhysicalDevice  = nullptr;
+        other.m_Device          = nullptr;
+    }
+
+    Core::Context &Core::Context::operator=(Core::Context &&other) noexcept
+    {
+        m_Instance          = other.m_Instance;
+        m_PhysicalDevice    = other.m_PhysicalDevice;
+        m_Device            = other.m_Device;
+
+        other.m_Instance        = nullptr;
+        other.m_PhysicalDevice  = nullptr;
+        other.m_Device          = nullptr;
+
+        return *this;
+    }
+}
diff --git a/src/vkcv/CoreManager.cpp b/src/vkcv/CoreManager.cpp
deleted file mode 100644
index 471075e3b48eb6aba8251d2924c00462f506fbc3..0000000000000000000000000000000000000000
--- a/src/vkcv/CoreManager.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * @authors Sebastian Gaida
- * @file src/vkcv/CoreManager.cpp
- * @brief Handling of global states regarding dependencies
- */
-
-#include "CoreManager.hpp"
-
-namespace vkcv {
-
-    int glfwCounter = 0;
-
-    void initGLFW() {
-
-        if (glfwCounter == 0) {
-            int glfwSuccess = glfwInit();
-
-            if (glfwSuccess == GLFW_FALSE) {
-                throw std::runtime_error("Could not initialize GLFW");
-            }
-        }
-        glfwCounter++;
-    }
-
-    void terminateGLFW() {
-        if (glfwCounter == 1) {
-            glfwTerminate();
-        }
-        glfwCounter--;
-    }
-}
diff --git a/src/vkcv/CoreManager.hpp b/src/vkcv/CoreManager.hpp
deleted file mode 100644
index a4104ae4a8dca0b01825f023bcb3ec2a2808c876..0000000000000000000000000000000000000000
--- a/src/vkcv/CoreManager.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-/**
- * @authors Sebastian Gaida
- * @file src/vkcv/CoreManager.hpp
- * @brief Handling of global states regarding dependencies
- */
-
-#include <GLFW/glfw3.h>
-#include <stdexcept>
-
-namespace vkcv {
-
-    /**
-     * initializes glfw once and increases the counter
-     */
-    void initGLFW();
-
-    /**
-     * terminates glfw once, if it was initialized or decreases the counter
-     */
-    void terminateGLFW();
-}
diff --git a/src/vkcv/Handles.cpp b/src/vkcv/Handles.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1337a132ae0b8721bd2776e24212f73dfb94ae46
--- /dev/null
+++ b/src/vkcv/Handles.cpp
@@ -0,0 +1 @@
+#include "vkcv/Handles.hpp"
diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp
index 7d8b86e08f25fe7741db1cfa777f00054aa8cee0..8814a5abcf7977386490d9783d5b121b7f986651 100644
--- a/src/vkcv/Window.cpp
+++ b/src/vkcv/Window.cpp
@@ -4,22 +4,30 @@
  * @brief Window class to handle a basic rendering surface and input
  */
 
-#include "Window.hpp"
-#include "CoreManager.hpp"
+#include "vkcv/Window.hpp"
 
 namespace vkcv {
 
+    static uint32_t s_WindowCount = 0;
+
     Window::Window(GLFWwindow *window)
             : m_window(window) {
     }
 
     Window::~Window() {
         glfwDestroyWindow(m_window);
-        vkcv::terminateGLFW();
+        s_WindowCount--;
+
+        if(s_WindowCount == 0)
+            glfwTerminate();
     }
 
     Window Window::create(const char *windowTitle, int width, int height, bool resizable) {
-        vkcv::initGLFW();
+        if(s_WindowCount == 0)
+            glfwInit();
+
+        s_WindowCount++;
+
         width = std::max(width, 1);
         height = std::max(height, 1);
 
@@ -28,6 +36,8 @@ namespace vkcv {
         GLFWwindow *window;
         window = glfwCreateWindow(width, height, windowTitle, nullptr, nullptr);
         return Window(window);
+
+
     }
 
     bool Window::isWindowOpen() const {