diff --git a/config/Sources.cmake b/config/Sources.cmake
index 80fa3a09d163edf3277eb69f91e7b10e57b72c5d..f00cf4b3c65c9b553b9062210477aff594c27938 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -12,4 +12,7 @@ set(vkcv_sources
 
 		${vkcv_include}/vkcv/Window.hpp
 		${vkcv_source}/vkcv/Window.cpp
+		
+		${vkcv_include}/vkcv/SwapChain.hpp
+		${vkcv_source}/vkcv/SwapChain.cpp
 )
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 7a7f3be7d61995462da1f65bd58af098b1dd1f4e..8dfb4593c00ed5a8dc07d90df3fdef9eb43f14e2 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -6,6 +6,8 @@
 
 #include <vulkan/vulkan.hpp>
 #include "vkcv/Context.hpp"
+#include "vkcv/SwapChain.hpp"
+#include "vkcv/Window.hpp"
 #include "vkcv/Handles.hpp"
 
 namespace vkcv
@@ -24,16 +26,20 @@ namespace vkcv
          *
          * @param context encapsulates various Vulkan objects
          */
-        explicit Core(Context &&context) noexcept;
+        Core(Context &&context, const Window &window, SwapChain swapChain,  std::vector<vk::ImageView> imageViews) noexcept;
         // explicit destruction of default constructor
         Core() = delete;
 
         Context m_Context;
+        SwapChain m_swapchain;
+        std::vector<vk::ImageView> m_swapchainImageViews;
+        const Window& m_window;
+
     public:
         /**
          * Destructor of #Core destroys the Vulkan objects contained in the core's context.
          */
-        ~Core() noexcept = default;
+        ~Core();
 
         /**
          * Copy-constructor of #Core is deleted!
@@ -78,15 +84,14 @@ namespace vkcv
              *
              * @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,
+        static Core create(const Window &window,
+                           const char *applicationName,
                            uint32_t applicationVersion,
-                           uint32_t queueCount,
                            std::vector<vk::QueueFlagBits> queueFlags    = {},
                            std::vector<const char*> instanceExtensions  = {},
                            std::vector<const char*> deviceExtensions    = {});
diff --git a/include/vkcv/SwapChain.hpp b/include/vkcv/SwapChain.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..15633badd4c6a3aef9766049317f3f5c8382bab8
--- /dev/null
+++ b/include/vkcv/SwapChain.hpp
@@ -0,0 +1,63 @@
+#pragma once
+#include "vulkan/vulkan.hpp"
+#include "Context.hpp"
+#include "vkcv/Window.hpp"
+#include <iostream>
+
+namespace vkcv {
+    class SwapChain final {
+    private:
+
+        vk::SurfaceKHR m_surface;
+        vk::SwapchainKHR m_swapchain;
+        vk::SurfaceFormatKHR m_format;
+
+        /**
+         * Constructor of a SwapChain object
+         * glfw is not initialized in this class because ist must be sure that there exists a context first
+         * glfw is already initialized by the window class
+         * @param surface used by the swapchain
+         * @param swapchain to show images in the window
+         * @param format
+         */
+        SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format);
+
+    public:
+        SwapChain(const SwapChain &other) = default;
+        SwapChain(SwapChain &&other) = default;
+
+        /**
+         * @return The swapchain linked with the #SwapChain class
+         * @note The reference to our Swapchain variable is needed for the recreation step
+         */
+        [[nodiscard]]
+        vk::SwapchainKHR getSwapchain();
+
+        /**
+         * gets the current surface object
+         * @return current surface
+         */
+        [[nodiscard]]
+        vk::SurfaceKHR getSurface();
+        /**
+         * gets the current surface format
+         * @return gets the surface format
+         */
+        [[nodiscard]]
+        vk::SurfaceFormatKHR getSurfaceFormat();
+
+        /**
+         * creates a swap chain object out of the given window and the given context
+         * @param window a wrapper that represents a glfw window
+         * @param context of the application
+         * @return returns an object of swapChain
+         */
+        static SwapChain create(const Window &window, const Context &context);
+
+        /**
+         * Destructor of SwapChain
+         */
+        virtual ~SwapChain();
+    };
+
+}
diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp
index 080e55350ba82ae58da8afcc8758da3fda77f19f..ef5e35cc10a9983440d3d33f7d8dd93a6aef5199 100644
--- a/include/vkcv/Window.hpp
+++ b/include/vkcv/Window.hpp
@@ -4,19 +4,17 @@
  * @file src/vkcv/Window.hpp
  * @brief Window class to handle a basic rendering surface and input
  */
-
-#define GLFW_INCLUDE_VULKAN
 #include <GLFW/glfw3.h>
 
 #define NOMINMAX
 #include <algorithm>
 
 namespace vkcv {
-
     class Window final {
     private:
         GLFWwindow *m_window;
 
+
         /**
          *
          * @param GLFWwindow of the class
@@ -32,8 +30,7 @@ namespace vkcv {
          * @param[in] resizable resize ability of the window (optional)
          * @return Window class
          */
-        static Window create(const char *windowTitle, int width = -1, int height = -1, bool resizable = false);
-
+        static Window create( const char *windowTitle, int width = -1, int height = -1, bool resizable = false);
         /**
          * checks if the window is still open, or the close event was called
          * This function should be changed/removed later on
@@ -54,20 +51,6 @@ namespace vkcv {
         [[nodiscard]]
         GLFWwindow *getWindow() const;
 
-        /**
-         * gets the current window width
-         * @return int with window width
-         */
-        [[nodiscard]]
-        int getWidth() const;
-
-        /**
-         * gets the current window height
-         * @return int with window height
-         */
-        [[nodiscard]]
-        int getHeight() const;
-
         /**
          * Copy-operator of #Window is deleted!
          *
@@ -84,10 +67,25 @@ namespace vkcv {
          */
         Window &operator=(Window &&other) = default;
 
+        /**
+         * gets the window width
+         * @param window glfwWindow
+         * @return int with window width
+         */
+        [[nodiscard]]
+        int getWidth() const;
+
+        /**
+         * gets the window height
+         * @param window glfwWindow
+         * @return int with window height
+         */
+        [[nodiscard]]
+        int getHeight() const;
+
         /**
          * Destructor of #Window, terminates GLFW
          */
         virtual ~Window();
-
     };
 }
\ No newline at end of file
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 0c981a25dc52db4363d2bc7835df3c3c9d7c49fa..cc84ce171678c94855b7c102b9af3119311cbd0e 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -1,20 +1,23 @@
 #include <iostream>
 #include <vkcv/Core.hpp>
-#include <vkcv/Window.hpp>
 
 int main(int argc, const char** argv) {
     const char* applicationName = "First Triangle";
-	vkcv::Window window = vkcv::Window::create(
+
+    vkcv::Window window = vkcv::Window::create(
             applicationName,
-        800,
-        600,
-		false
-	);
+            800,
+            600,
+            false
+    );
+
 	vkcv::Core core = vkcv::Core::create(
+            window,
             applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
-		20,
-		{vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eTransfer}
+            {vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute},
+		{},
+		{"VK_KHR_swapchain"}
 	);
 
 	const auto &context = core.getContext();
diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp
index d5261285557f07310c02acd50b6ccd6ca16cac59..761add2c9c0792bbf098c1f7f6122e84978a6735 100644
--- a/src/vkcv/Context.cpp
+++ b/src/vkcv/Context.cpp
@@ -1,3 +1,4 @@
+#include <iostream>
 #include "vkcv/Context.hpp"
 
 namespace vkcv
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 0c32f4e42d1a232a9b66d42e6a16f0c1eda06bbb..9f8036975aead0d4e99b5156fcfe5b6edd1bd30d 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -1,6 +1,6 @@
 /**
- * @authors Sebastian Gaida
- * @file src/vkcv/CoreManager.cpp
+ * @authors Artur Wasmut
+ * @file src/vkcv/Core.cpp
  * @brief Handling of global states regarding dependencies
  */
 
@@ -78,49 +78,169 @@ namespace vkcv
 
 
     /**
-     * @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)
+     * Given the @p physicalDevice and the @p queuePriorities, the @p queueCreateInfos are computed. First, the requested
+     * queues are sorted by priority depending on the availability of queues in the queue families of the given
+     * @p physicalDevice. Then check, if all requested queues are creatable. If so, the @p queueCreateInfos will be computed.
+     * Furthermore, lists of index pairs (queueFamilyIndex, queueIndex) for later referencing of the separate queues will
+     * be computed.
+     * @param[in] physicalDevice The physical device
+     * @param[in] queuePriorities The queue priorities used for the computation of @p queueCreateInfos
+     * @param[in] queueFlags The queue flags requesting the queues
+     * @param[in,out] queueCreateInfos The queue create info structures to be created
+     * @param[in,out] queuePairsGraphics The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
+     *      vk::QueueFlagBits::eGraphics
+     * @param[in,out] queuePairsCompute The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
+     *      vk::QueueFlagBits::eCompute
+     * @param[in,out] queuePairsTransfer The list of index pairs (queueFamilyIndex, queueIndex) of queues of type
+     *      vk::QueueFlagBits::eTransfer
+     * @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability.
+     */
+    void queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice,
+                                                           std::vector<float> &queuePriorities,
+                                                           std::vector<vk::QueueFlagBits> &queueFlags,
+                                                           std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos,
+                                                           std::vector<std::pair<int, int>> &queuePairsGraphics,
+                                                           std::vector<std::pair<int, int>> &queuePairsCompute,
+                                                           std::vector<std::pair<int, int>> &queuePairsTransfer)
     {
-        std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
+        queueCreateInfos = {};
+        queuePairsGraphics = {};
+        queuePairsCompute = {};
+        queuePairsTransfer = {};
         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);
+        // DEBUG
+        std::cout << "Input queue flags:" << std::endl;
+        for (auto qFlag : queueFlags) {
+            std::cout << "\t" << to_string(qFlag) << std::endl;
+        }
+
+        //check priorities of flags -> the lower prioCount the higher the priority
+        std::vector<int> prios;
+        for(auto flag: queueFlags){
+            int prioCount = 0;
+            for (int i = 0; i < qFamilyProperties.size(); i++) {
+                prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount;
             }
-            if (supported) {
-                qFamilyCandidates.push_back(qFamily);
+            prios.push_back(prioCount);
+            std::cout<< "prio Count: " << prioCount << std::endl;
+        }
+        //resort flags with heighest priority before allocating the queues
+        std::vector<vk::QueueFlagBits> newFlags;
+        for(int i = 0; i < prios.size(); i++){
+            auto minElem = std::min_element(prios.begin(), prios.end());
+            int index = minElem - prios.begin();
+            std::cout << "index: "<< index << std::endl;
+            newFlags.push_back(queueFlags[index]);
+            prios[index] = std::numeric_limits<int>::max();
+        }
+
+        std::cout << "Sorted queue flags:" << std::endl;
+        for (auto qFlag : newFlags) {
+            std::cout << "\t" << to_string(qFlag) << std::endl;
+        }
+
+        // create requested queues and check if more requested queues are supported
+        // herefore: create vector that updates available queues in each queue family
+        // structure: [qFamily_0, ..., qFamily_n] where
+        // - qFamily_i = [GraphicsCount, ComputeCount, TransferCount], 0 <= i <= n
+        std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus;
+
+        for (auto qFamily : qFamilyProperties) {
+            int graphicsCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0) * qFamily.queueCount;
+            int computeCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0) * qFamily.queueCount;;
+            int transferCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0) * qFamily.queueCount;;
+            queueFamilyStatus.push_back({graphicsCount, computeCount, transferCount});
+        }
+
+        initialQueueFamilyStatus = queueFamilyStatus;
+
+        // check if every queue with the specified queue flag can be created
+        // this automatically checks for queue flag support!
+        for (auto qFlag : newFlags) {
+            bool found;
+            switch (qFlag) {
+                case vk::QueueFlagBits::eGraphics:
+                    found = false;
+                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
+                        if (queueFamilyStatus[i][0] > 0) {
+                            queuePairsGraphics.push_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]));
+                            queueFamilyStatus[i][0]--;
+                            queueFamilyStatus[i][1]--;
+                            queueFamilyStatus[i][2]--;
+                            std::cout << "Graphics queue available at queue family #" << i << std::endl;
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        throw std::runtime_error("Too many graphics queues were requested than being available!");
+                    }
+                    break;
+                case vk::QueueFlagBits::eCompute:
+                    found = false;
+                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
+                        if (queueFamilyStatus[i][1] > 0) {
+                            queuePairsCompute.push_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1]));
+                            queueFamilyStatus[i][0]--;
+                            queueFamilyStatus[i][1]--;
+                            queueFamilyStatus[i][2]--;
+                            std::cout << "Compute queue available at queue family #" << i << std::endl;
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        throw std::runtime_error("Too many compute queues were requested than being available!");
+                    }
+                    break;
+                case vk::QueueFlagBits::eTransfer:
+                    found = false;
+                    for (int i = 0; i < queueFamilyStatus.size() && !found; i++) {
+                        if (queueFamilyStatus[i][2] > 0) {
+                            queuePairsTransfer.push_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2]));
+                            queueFamilyStatus[i][0]--;
+                            queueFamilyStatus[i][1]--;
+                            queueFamilyStatus[i][2]--;
+                            std::cout << "Transfer queue available at queue family #" << i << std::endl;
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        throw std::runtime_error("Too many transfer queues were requested than being available!");
+                    }
+                    break;
+                default:
+                    throw std::runtime_error("Invalid input for queue flag bits. Valid inputs are 'vk::QueueFlagBits::eGraphics', 'vk::QueueFlagBits::eCompute' and 'vk::QueueFlagBits::eTransfer'.");
             }
         }
 
-        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;
+        std::cout << "Initial queue status:" << std::endl;
+        int x = 0;
+        for (std::vector<int> e : initialQueueFamilyStatus) {
+            std::cout << "#" << x << ":\t[" << e[0] << ", " << e[1] << ", " << e[2] << "]" << std::endl;
+            x++;
+        }
+
+        std::cout << "Actual queue status:" << std::endl;
+        x = 0;
+        for (std::vector<int> e : queueFamilyStatus) {
+            std::cout << "#" << x << ":\t[" << e[0] << ", " << e[1] << ", " << e[2] << "]" << std::endl;
+            x++;
         }
 
-        return queueCreateInfos;
+        // create all requested queues
+        for (int i = 0; i < qFamilyProperties.size(); i++) {
+            uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]);
+            std::cout << "For Queue Family #" << i << " create " << create << " queues" << std::endl;
+            if (create > 0) {
+                vk::DeviceQueueCreateInfo qCreateInfo(
+                        vk::DeviceQueueCreateFlags(),
+                        i,
+                        create,
+                        queuePriorities.data()
+                );
+                queueCreateInfos.push_back(qCreateInfo);
+            }
+        }
     }
 
     /**
@@ -146,14 +266,42 @@ namespace vkcv
         return true;
     }
 
-    Core Core::create(const char *applicationName,
+
+    std::vector<const char*> 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;
+    }
+
+    /**
+     * Computes the queue handles from @p queuePairs
+     * @param queuePairs The queuePairs that were created separately for each queue type (e.g., vk::QueueFlagBits::eGraphics)
+     * @param device The device
+     * @return An array of queue handles based on the @p queuePairs
+     */
+    std::vector<vk::Queue> getQueueHandles(const std::vector<std::pair<int, int>> queuePairs, const vk::Device device) {
+        std::vector<vk::Queue> queueHandles;
+        for (auto q : queuePairs) {
+            int queueFamilyIndex = q.first; // the queueIndex of the queue family
+            int queueIndex = q.second;   // the queueIndex within a queue family
+            queueHandles.push_back(device.getQueue(queueFamilyIndex, queueIndex));
+        }
+        return queueHandles;
+    }
+
+    Core Core::create(const Window &window,
+                      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();
@@ -190,9 +338,9 @@ namespace vkcv
             throw std::runtime_error("The requested instance extensions are not supported!");
         }
 
-#ifndef NDEBUG
-        instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
-#endif
+        // for GLFW: get all required extensions
+        std::vector<const char*> requiredExtensions = getRequiredExtensions();
+        instanceExtensions.insert(instanceExtensions.end(), requiredExtensions.begin(), requiredExtensions.end());
 
         const vk::ApplicationInfo applicationInfo(
                 applicationName,
@@ -233,10 +381,12 @@ namespace vkcv
 
         //vector to define the queue priorities
         std::vector<float> qPriorities;
-        qPriorities.resize(queueCount, 1.f); // all queues have the same priorities
+        qPriorities.resize(queueFlags.size(), 1.f); // all queues have the same priorities
 
         // create required queues
-        std::vector<vk::DeviceQueueCreateInfo> qCreateInfos = getQueueCreateInfos(physicalDevice, queueCount, qPriorities,queueFlags);
+        std::vector<vk::DeviceQueueCreateInfo> qCreateInfos;
+        std::vector<std::pair<int, int>> queuePairsGraphics, queuePairsCompute, queuePairsTransfer;
+        queueCreateInfosQueueHandles(physicalDevice, qPriorities, queueFlags, qCreateInfos, queuePairsGraphics, queuePairsCompute, queuePairsTransfer);
 
         vk::DeviceCreateInfo deviceCreateInfo(
                 vk::DeviceCreateFlags(),
@@ -256,10 +406,48 @@ namespace vkcv
 
 
         vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
-        // TODO: implement device.getQueue() to access the queues, if needed
+
+        // maybe it can be useful to store these lists as member variable of Core
+        std::vector<vk::Queue> graphicsQueues = getQueueHandles(queuePairsGraphics, device);
+        std::vector<vk::Queue> computeQueues = getQueueHandles(queuePairsCompute, device);
+        std::vector<vk::Queue> transferQueues = getQueueHandles(queuePairsTransfer, device);
+
+        // examples for accessing queues
+        vk::Queue graphicsQueue = graphicsQueues[0];
+        vk::Queue computeQueue = computeQueues[0];
+        vk::Queue transferQueue = transferQueues[0];
+
         Context context(instance, physicalDevice, device);
 
-        return Core(std::move(context));
+        SwapChain swapChain = SwapChain::create(window, context);
+
+        std::vector<vk::Image> swapChainImages = device.getSwapchainImagesKHR(swapChain.getSwapchain());
+        std::vector<vk::ImageView> imageViews;
+        imageViews.reserve( swapChainImages.size() );
+        //here can be swizzled with vk::ComponentSwizzle if needed
+        vk::ComponentMapping componentMapping(
+                vk::ComponentSwizzle::eR,
+                vk::ComponentSwizzle::eG,
+                vk::ComponentSwizzle::eB,
+                vk::ComponentSwizzle::eA );
+
+        vk::ImageSubresourceRange subResourceRange( vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 );
+
+        for ( auto image : swapChainImages )
+        {
+            vk::ImageViewCreateInfo imageViewCreateInfo(
+                    vk::ImageViewCreateFlags(),
+                    image,
+                    vk::ImageViewType::e2D,
+                    swapChain.getSurfaceFormat().format,
+                    componentMapping,
+                    subResourceRange
+            );
+
+            imageViews.push_back( device.createImageView( imageViewCreateInfo ) );
+        }
+
+        return Core(std::move(context) , window, swapChain, imageViews);
     }
 
     const Context &Core::getContext() const
@@ -267,7 +455,19 @@ namespace vkcv
         return m_Context;
     }
 
-    Core::Core(Context &&context) noexcept :
-            m_Context(std::move(context))
+    Core::Core(Context &&context, const Window &window , SwapChain swapChain,  std::vector<vk::ImageView> imageViews) noexcept :
+            m_Context(std::move(context)),
+            m_window(window),
+            m_swapchain(swapChain),
+            m_swapchainImageViews(imageViews)
     {}
+
+    Core::~Core() {
+        for( auto image: m_swapchainImageViews ){
+            m_Context.getDevice().destroyImageView(image);
+        }
+
+        m_Context.getDevice().destroySwapchainKHR(m_swapchain.getSwapchain());
+        m_Context.getInstance().destroySurfaceKHR( m_swapchain.getSurface() );
+    }
 }
diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/SwapChain.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..85f67b8d0fe252a2ab65d4e0d5baf388a7cfa862
--- /dev/null
+++ b/src/vkcv/SwapChain.cpp
@@ -0,0 +1,192 @@
+
+#include <vkcv/SwapChain.hpp>
+
+namespace vkcv {
+
+    SwapChain::SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format )
+        : m_surface(surface), m_swapchain(swapchain), m_format( format)
+    {}
+
+    vk::SwapchainKHR SwapChain::getSwapchain() {
+        return m_swapchain;
+    }
+
+    /**
+     * gets surface of the swapchain
+     * @return current surface
+     */
+    vk::SurfaceKHR SwapChain::getSurface() {
+        return m_surface;
+    }
+
+    /**
+     * gets the surface of the swapchain
+     * @return chosen format
+     */
+    vk::SurfaceFormatKHR SwapChain::getSurfaceFormat(){
+        return m_format;
+    }
+
+    /**
+     * creates surface and checks availability
+     * @param window current window for the surface
+     * @param instance Vulkan-Instance
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @return created surface
+     */
+    vk::SurfaceKHR createSurface(GLFWwindow *window, const vk::Instance &instance, const vk::PhysicalDevice& physicalDevice) {
+        //create surface
+        VkSurfaceKHR surface;
+        if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) {
+            throw std::runtime_error("failed to create a window surface!");
+        }
+        vk::Bool32 surfaceSupport = false;
+        if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) {
+            throw std::runtime_error("surface is not supported by the device!");
+        }
+
+        return vk::SurfaceKHR(surface);
+    }
+
+    /**
+     * chooses Extent and clapms values to the available
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface of the swapchain
+     * @param window of the current application
+     * @return chosen Extent for the surface
+     */
+    vk::Extent2D chooseSwapExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){
+        vk::SurfaceCapabilitiesKHR surfaceCapabilities;
+        if(physicalDevice.getSurfaceCapabilitiesKHR(surface,&surfaceCapabilities) != vk::Result::eSuccess){
+            throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface.");
+        }
+
+        VkExtent2D extent2D = {
+                static_cast<uint32_t>(window.getWidth()),
+                static_cast<uint32_t>(window.getHeight())
+        };
+        extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width));
+        extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height));
+
+        if (extent2D.width > surfaceCapabilities.maxImageExtent.width ||
+            extent2D.width < surfaceCapabilities.minImageExtent.width ||
+            extent2D.height > surfaceCapabilities.maxImageExtent.height ||
+            extent2D.height < surfaceCapabilities.minImageExtent.height) {
+            std::printf("Surface size not matching. Resizing to allowed value.");
+        }
+        return extent2D;
+    }
+
+    /**
+     * chooses Surface Format for the current surface
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface of the swapchain
+     * @return available Format
+     */
+    vk::SurfaceFormatKHR chooseSwapSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+        uint32_t formatCount;
+        physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, nullptr);
+        std::vector<vk::SurfaceFormatKHR> availableFormats(formatCount);
+        if (physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, &availableFormats[0]) != vk::Result::eSuccess) {
+            throw std::runtime_error("Failed to get surface formats");
+        }
+
+        for (const auto& availableFormat : availableFormats) {
+            if (availableFormat.format == vk::Format::eB8G8R8A8Unorm  && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
+                return availableFormat;
+            }
+        }
+        return availableFormats[0];
+    }
+
+    /**
+     * returns vk::PresentModeKHR::eMailbox if available or vk::PresentModeKHR::eFifo otherwise
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface of the swapchain
+     * @return available PresentationMode
+     */
+    vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+        uint32_t modeCount;
+        physicalDevice.getSurfacePresentModesKHR( surface, &modeCount, nullptr );
+        std::vector<vk::PresentModeKHR> availablePresentModes(modeCount);
+        if (physicalDevice.getSurfacePresentModesKHR(surface, &modeCount, &availablePresentModes[0]) != vk::Result::eSuccess) {
+            throw std::runtime_error("Failed to get presentation modes");
+        }
+
+        for (const auto& availablePresentMode : availablePresentModes) {
+            if (availablePresentMode == vk::PresentModeKHR::eMailbox) {
+                return availablePresentMode;
+            }
+        }
+        // The FIFO present mode is guaranteed by the spec to be supported
+        return vk::PresentModeKHR::eFifo;
+    }
+
+    /**
+     * returns the minImageCount +1 for at least doublebuffering, if it's greater than maxImageCount return maxImageCount
+     * @param physicalDevice Vulkan-PhysicalDevice
+     * @param surface of the swapchain
+     * @return available ImageCount
+     */
+    uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
+        vk::SurfaceCapabilitiesKHR surfaceCapabilities;
+        if(physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities) != vk::Result::eSuccess){
+            throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface.");
+        }
+
+        uint32_t imageCount = surfaceCapabilities.minImageCount + 1;    // minImageCount should always be at least 2; set to 3 for triple buffering
+        // check if requested image count is supported
+        if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) {
+            imageCount = surfaceCapabilities.maxImageCount;
+        }
+
+        return imageCount;
+    }
+    /**
+     * creates and returns a swapchain with default specs
+     * @param window of the current application
+     * @param context that keeps instance, physicalDevice and a device.
+     * @return swapchain
+     */
+    SwapChain SwapChain::create(const Window &window, const Context &context) {
+        const vk::Instance& instance = context.getInstance();
+        const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
+        const vk::Device& device = context.getDevice();
+
+        vk::SurfaceKHR surface = createSurface(window.getWindow(),instance,physicalDevice);
+
+        vk::Extent2D extent2D = chooseSwapExtent(physicalDevice, surface, window);
+        vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(physicalDevice, surface);
+        vk::PresentModeKHR presentMode = choosePresentMode(physicalDevice, surface);
+        uint32_t imageCount = chooseImageCount(physicalDevice, surface);
+
+        vk::SwapchainCreateInfoKHR swapchainCreateInfo(
+                vk::SwapchainCreateFlagsKHR(),  //flags
+                surface,    // surface
+                imageCount,  // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard)
+                surfaceFormat.format,   // imageFormat
+                surfaceFormat.colorSpace,   // imageColorSpace
+                extent2D,   // imageExtent
+                1,  // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers"
+                vk::ImageUsageFlagBits::eColorAttachment,  // imageUsage TODO: what attachments? only color? depth?
+                vk::SharingMode::eExclusive,    // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues"
+                0,  // queueFamilyIndexCount, the number of queue families having access to the image(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT
+                nullptr,    // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT
+                vk::SurfaceTransformFlagBitsKHR::eIdentity, // preTransform, transformations applied onto the image before display
+                vk::CompositeAlphaFlagBitsKHR::eOpaque, // compositeAlpha, TODO: how to handle transparent pixels? do we need transparency? If no -> opaque
+                presentMode,    // presentMode
+                true,   // clipped
+                nullptr // oldSwapchain
+        );
+
+        vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo);
+
+        return SwapChain(surface, swapchain, surfaceFormat);
+    }
+
+
+    SwapChain::~SwapChain() {
+        // needs to be destroyed by creator
+    }
+
+}
diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp
index 8814a5abcf7977386490d9783d5b121b7f986651..ce05d67cb216215c625b468acdb85be2fc2a8b2e 100644
--- a/src/vkcv/Window.cpp
+++ b/src/vkcv/Window.cpp
@@ -6,6 +6,7 @@
 
 #include "vkcv/Window.hpp"
 
+
 namespace vkcv {
 
     static uint32_t s_WindowCount = 0;
@@ -18,14 +19,15 @@ namespace vkcv {
         glfwDestroyWindow(m_window);
         s_WindowCount--;
 
-        if(s_WindowCount == 0)
+        if(s_WindowCount == 0) {
             glfwTerminate();
+        }
     }
 
-    Window Window::create(const char *windowTitle, int width, int height, bool resizable) {
-        if(s_WindowCount == 0)
+    Window Window::create( const char *windowTitle, int width, int height, bool resizable) {
+        if(s_WindowCount == 0) {
             glfwInit();
-
+        }
         s_WindowCount++;
 
         width = std::max(width, 1);
@@ -35,9 +37,8 @@ namespace vkcv {
         glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE);
         GLFWwindow *window;
         window = glfwCreateWindow(width, height, windowTitle, nullptr, nullptr);
-        return Window(window);
-
 
+        return Window(window);
     }
 
     bool Window::isWindowOpen() const {
@@ -48,10 +49,6 @@ namespace vkcv {
         glfwPollEvents();
     }
 
-    GLFWwindow *Window::getWindow() const {
-        return m_window;
-    }
-
     int Window::getWidth() const {
         int width;
         glfwGetWindowSize(m_window, &width, nullptr);
@@ -63,4 +60,8 @@ namespace vkcv {
         glfwGetWindowSize(m_window, nullptr, &height);
         return height;
     }
-}
\ No newline at end of file
+
+    GLFWwindow *Window::getWindow() const {
+        return m_window;
+    }
+}