diff --git a/.gitignore b/.gitignore
index d2bf98a016f588760241f9dc7f90f6197c458404..7ee4ff1903e902c4715c6e2b0c3e784ed5755aaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,3 @@
-<<<<<<< HEAD
-=======
-
->>>>>>> develop
 # IDE specific files
 .project
 .cproject
@@ -19,3 +15,6 @@ cmake-build-release/
 *.exe
 *.ilk
 *.pdb
+
+# GUI configuration files
+imgui.ini
diff --git a/.gitmodules b/.gitmodules
index 62938a4b1ff2c6787b619cc2c18ef91cb0f0f679..e0aaf2d17c340f98ae875f7e0f1238bfe04f7e5d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -19,3 +19,6 @@
 [submodule "modules/shader_compiler/lib/glslang"]
 	path = modules/shader_compiler/lib/glslang
 	url = https://github.com/KhronosGroup/glslang.git
+[submodule "modules/gui/lib/imgui"]
+	path = modules/gui/lib/imgui
+	url = https://github.com/ocornut/imgui.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0a7f978f81313ecc3a657dd670d2a16db3cd4e8d..bff486150f082c2e96e543436d977cf3112403ba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,15 +41,15 @@ if (vkcv_build_debug)
 	endif()
 endif()
 
+# configure everything to use the required dependencies
+include(${vkcv_config}/Libraries.cmake)
+
 # add modules as targets
 add_subdirectory(modules)
 
 # add source files for compilation
 include(${vkcv_config}/Sources.cmake)
 
-# configure everything to use the required dependencies
-include(${vkcv_config}/Libraries.cmake)
-
 message("-- Libraries: [ ${vkcv_libraries} ]")
 message("-- Flags: [ ${vkcv_flags} ]")
 
diff --git a/config/Sources.cmake b/config/Sources.cmake
index 62cec249367995db0217c71455cfcee982c65af3..4397e4978eb022d267571d185a1f122d053a5ea1 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -32,8 +32,8 @@ set(vkcv_sources
 		
 		${vkcv_include}/vkcv/Logger.hpp
 
-		${vkcv_include}/vkcv/SwapChain.hpp
-		${vkcv_source}/vkcv/SwapChain.cpp
+		${vkcv_include}/vkcv/Swapchain.hpp
+		${vkcv_source}/vkcv/Swapchain.cpp
 		
 		${vkcv_include}/vkcv/ShaderStage.hpp
 		
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 4a51b24f5c978daebc5116e20b527252c8063d61..bf9514d5ba4c9d5dbf8d41be2a489dae826886a8 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -8,7 +8,7 @@
 #include <vulkan/vulkan.hpp>
 
 #include "vkcv/Context.hpp"
-#include "vkcv/SwapChain.hpp"
+#include "vkcv/Swapchain.hpp"
 #include "vkcv/Window.hpp"
 #include "vkcv/PassConfig.hpp"
 #include "vkcv/Handles.hpp"
@@ -41,6 +41,7 @@ namespace vkcv
 		QueueType queueType;
 		std::vector<vk::Semaphore> waitSemaphores;
 		std::vector<vk::Semaphore> signalSemaphores;
+		vk::Fence fence;
 	};
 
     class Core final
@@ -52,7 +53,7 @@ namespace vkcv
          *
          * @param context encapsulates various Vulkan objects
          */
-        Core(Context &&context, Window &window, const SwapChain& swapChain,  std::vector<vk::ImageView> imageViews,
+        Core(Context &&context, Window &window, const Swapchain& swapChain,  std::vector<vk::ImageView> imageViews,
 			const CommandResources& commandResources, const SyncResources& syncResources) noexcept;
         // explicit destruction of default constructor
         Core() = delete;
@@ -61,11 +62,11 @@ namespace vkcv
 
         Context m_Context;
 
-        SwapChain                       m_swapchain;
+        Swapchain                       m_swapchain;
         std::vector<vk::ImageView>      m_swapchainImageViews;
         std::vector<vk::Image>          m_swapchainImages;
 		std::vector<vk::ImageLayout>    m_swapchainImageLayouts;
-        const Window&                   m_window;
+        Window&                   		m_window;
 
         std::unique_ptr<PassManager>            m_PassManager;
         std::unique_ptr<PipelineManager>        m_PipelineManager;
@@ -78,10 +79,10 @@ namespace vkcv
 		CommandResources    m_CommandResources;
 		SyncResources       m_SyncResources;
 		uint32_t            m_currentSwapchainImageIndex;
+	
+		event_handle<int,int> e_resizeHandle;
 
-        std::function<void(int, int)> e_resizeHandle;
-
-        static std::vector<vk::ImageView> createImageViews( Context &context, SwapChain& swapChain);
+        static std::vector<vk::ImageView> createImageViews( Context &context, Swapchain& swapChain);
 
 		void recordSwapchainImageLayoutTransition(vk::CommandBuffer cmdBuffer, vk::ImageLayout newLayout);
 
@@ -123,6 +124,9 @@ namespace vkcv
 
         [[nodiscard]]
         const Context &getContext() const;
+        
+        [[nodiscard]]
+        const Swapchain& getSwapchain() const;
 
         /**
              * Creates a #Core with given @p applicationName and @p applicationVersion for your application.
@@ -253,8 +257,6 @@ namespace vkcv
 		*/
 		void endFrame();
 
-		vk::Format getSwapchainImageFormat();
-
 		/**
 		 * Submit a command buffer to any queue of selected type. The recording can be customized by a
 		 * custom record-command-function. If the command submission has finished, an optional finish-function
@@ -279,5 +281,8 @@ namespace vkcv
 		void submitCommandStream(const CommandStreamHandle handle);
 		void prepareSwapchainImageForPresent(const CommandStreamHandle handle);
 		void prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image);
+		
+		const vk::ImageView& getSwapchainImageView() const;
+		
     };
 }
diff --git a/include/vkcv/Event.hpp b/include/vkcv/Event.hpp
index 0836e836e84ff7dfc4931a7cedd65497bf9a89cf..e324917674cd2e1773ee23a9411ab28f6eb0d684 100644
--- a/include/vkcv/Event.hpp
+++ b/include/vkcv/Event.hpp
@@ -3,10 +3,18 @@
 #include <functional>
 
 namespace vkcv {
+	
+	template<typename... T>
+	struct event_handle {
+		uint32_t id;
+	};
 
     template<typename... T>
     struct event_function {
         typedef std::function<void(T...)> type;
+	
+		event_handle<T...> handle;
+        type callback;
     };
 
     /**
@@ -16,7 +24,8 @@ namespace vkcv {
     template<typename... T>
     struct event {
     private:
-        std::vector<typename event_function<T...>::type> m_handles;
+        std::vector< event_function<T...> > m_functions;
+        uint32_t m_id_counter;
 
     public:
 
@@ -25,28 +34,34 @@ namespace vkcv {
          * @param arguments of the given function
          */
         void operator()(T... arguments) {
-            for (auto &handle : this->m_handles) {
-                handle(arguments...);
+            for (auto &function : this->m_functions) {
+				function.callback(arguments...);
             }
         }
 
         /**
          * adds a function handle to the event to be called
-         * @param handle of the function
+         * @param callback of the function
+         * @return handle of the function
          */
-        typename event_function<T...>::type add(typename event_function<T...>::type handle) {
-            this->m_handles.push_back(handle);
-            return handle;
+		event_handle<T...> add(typename event_function<T...>::type callback) {
+			event_function<T...> function;
+			function.handle = { m_id_counter++ };
+			function.callback = callback;
+            this->m_functions.push_back(function);
+            return function.handle;
         }
 
         /**
          * removes a function handle of the event
          * @param handle of the function
          */
-        void remove(typename event_function<T...>::type handle) {
-            this->m_handles.erase(
-                    remove(this->m_handles.begin(), this->m_handles.end(), handle),
-                    this->m_handles.end()
+        void remove(event_handle<T...> handle) {
+            this->m_functions.erase(
+					std::remove_if(this->m_functions.begin(), this->m_functions.end(), [&handle](auto function){
+						return (handle.id == function.handle.id);
+					}),
+                    this->m_functions.end()
             );
         }
 
diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp
index a1219ce4147ebbb8ae0650da8a87766f8967874b..840650a1d6288922eceff7ba10ee7e71bf88dc22 100644
--- a/include/vkcv/Image.hpp
+++ b/include/vkcv/Image.hpp
@@ -29,9 +29,6 @@ namespace vkcv {
 		
 		[[nodiscard]]
 		uint32_t getDepth() const;
-		
-		[[nodiscard]]
-		vk::ImageLayout getLayout() const;
 
 		[[nodiscard]]
 		vkcv::ImageHandle getHandle() const;
diff --git a/include/vkcv/SwapChain.hpp b/include/vkcv/Swapchain.hpp
similarity index 83%
rename from include/vkcv/SwapChain.hpp
rename to include/vkcv/Swapchain.hpp
index 089205d1633551b4ad9f11d0bdd5540b2bb61bbb..b75fc5a87156ea56061e41b4b0974928c83ffa28 100644
--- a/include/vkcv/SwapChain.hpp
+++ b/include/vkcv/Swapchain.hpp
@@ -7,8 +7,9 @@
 
 namespace vkcv
 {
-    class SwapChain final {
+    class Swapchain final {
     private:
+    	friend class Core;
 
         struct Surface
         {
@@ -21,10 +22,10 @@ namespace vkcv
         Surface m_Surface;
 
         vk::SwapchainKHR m_Swapchain;
-        vk::Format m_SwapchainFormat;
-        vk::ColorSpaceKHR m_SwapchainColorSpace;
-        vk::PresentModeKHR m_SwapchainPresentMode;
-		uint32_t m_SwapchainImageCount;
+        vk::Format m_Format;
+        vk::ColorSpaceKHR m_ColorSpace;
+        vk::PresentModeKHR m_PresentMode;
+		uint32_t m_ImageCount;
 	
 		vk::Extent2D m_Extent;
 	
@@ -39,16 +40,36 @@ namespace vkcv
          * @param format
          */
          // TODO:
-        SwapChain(const Surface &surface,
+        Swapchain(const Surface &surface,
                   vk::SwapchainKHR swapchain,
                   vk::Format format,
                   vk::ColorSpaceKHR colorSpace,
                   vk::PresentModeKHR presentMode,
                   uint32_t imageCount,
 				  vk::Extent2D extent) noexcept;
+	
+		/**
+		 * TODO
+		 *
+		 * @return
+		 */
+		bool shouldUpdateSwapchain() const;
+	
+		/**
+		 * TODO
+		 *
+		 * context
+		 * window
+		 */
+		void updateSwapchain(const Context &context, const Window &window);
+	
+		/**
+		 *
+		 */
+		void signalSwapchainRecreation();
 
     public:
-    	SwapChain(const SwapChain& other);
+    	Swapchain(const Swapchain& other);
 
         /**
          * @return The swapchain linked with the #SwapChain class
@@ -69,7 +90,7 @@ namespace vkcv
          * @return gets the chosen swapchain format
          */
         [[nodiscard]]
-        vk::Format getSwapchainFormat() const;
+        vk::Format getFormat() const;
 
         /**
          * creates a swap chain object out of the given window and the given context
@@ -77,37 +98,17 @@ namespace vkcv
          * @param context of the application
          * @return returns an object of swapChain
          */
-        static SwapChain create(const Window &window, const Context &context);
+        static Swapchain create(const Window &window, const Context &context);
 
         /**
          * Destructor of SwapChain
          */
-        virtual ~SwapChain();
+        virtual ~Swapchain();
 
 		/**
 		 * @return number of images in swapchain
 		*/
-		uint32_t getImageCount();
-		
-		/**
-		 * TODO
-		 *
-		 * @return
-		 */
-		bool shouldUpdateSwapchain() const;
-
-		/**
-		 * TODO
-		 *
-		 * context
-		 * window
-		 */
-		void updateSwapchain(const Context &context, const Window &window);
-		
-		/**
-		 *
-		 */
-        void signalSwapchainRecreation();
+		uint32_t getImageCount() const;
 	
         /**
          * TODO
diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp
index f71671c935a0a5e17bb517c726d75ffff2973532..51d6e2245a8b588334b38254c05276ee0eb10150 100644
--- a/include/vkcv/Window.hpp
+++ b/include/vkcv/Window.hpp
@@ -13,16 +13,19 @@ struct GLFWwindow;
 
 namespace vkcv {
 
-    class Window final {
-    private:
-        GLFWwindow *m_window;
-
-        /**
+    class Window {
+	protected:
+		GLFWwindow *m_window;
+	
+		/**
          *
          * @param GLFWwindow of the class
          */
-        explicit Window(GLFWwindow *window);
-
+		explicit Window(GLFWwindow *window);
+		
+		static GLFWwindow* createGLFWWindow(const char *windowTitle, int width, int height, bool resizable);
+		
+    private:
         /**
          * mouse callback for moving the mouse on the screen
          * @param[in] window The window that received the event.
@@ -58,6 +61,13 @@ namespace vkcv {
          * @param[in] mods Bit field describing which [modifier keys](@ref mods) were held down.
          */
         static void onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods);
+	
+        /**
+         * char callback for any typed character
+         * @param[in] window The window that received the event
+         * @param[in] c The character that got typed
+         */
+		static void onCharEvent(GLFWwindow *callbackWindow, unsigned int c);
 
     public:
         /**
@@ -95,6 +105,7 @@ namespace vkcv {
         event< double, double > e_mouseScroll;
         event< int, int > e_resize;
         event< int, int, int, int > e_key;
+        event< unsigned int > e_char;
 
         /**
          * returns the current window
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index e8efea4981da3ffb338d508431ed4f92805ed5cd..5edb802b3adf16878c2dec4050d8444278739026 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -2,5 +2,6 @@
 # Add new modules here:
 add_subdirectory(asset_loader)
 add_subdirectory(camera)
+add_subdirectory(gui)
 add_subdirectory(shader_compiler)
 add_subdirectory(testing)
diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp
index 0c5041795ece9cd84e740a04c0d64e4964d0f4c8..5755d6cdc20f0321197b7755e459725eb363fc90 100644
--- a/modules/camera/include/vkcv/camera/CameraManager.hpp
+++ b/modules/camera/include/vkcv/camera/CameraManager.hpp
@@ -25,11 +25,11 @@ namespace vkcv::camera {
      */
     class CameraManager{
     private:
-        std::function<void(int, int, int, int)> m_keyHandle;
-        std::function<void(double, double)> m_mouseMoveHandle;
-        std::function<void(double, double)> m_mouseScrollHandle;
-        std::function<void(int, int, int)> m_mouseButtonHandle;
-        std::function<void(int, int)> m_resizeHandle;
+		event_handle<int, int, int, int> m_keyHandle;
+		event_handle<double, double> m_mouseMoveHandle;
+		event_handle<double, double> m_mouseScrollHandle;
+		event_handle<int, int, int> m_mouseButtonHandle;
+		event_handle<int, int> m_resizeHandle;
 
         Window& m_window;
         std::vector<Camera> m_cameras;
diff --git a/modules/camera/src/vkcv/camera/CameraManager.cpp b/modules/camera/src/vkcv/camera/CameraManager.cpp
index 561596c25a66334b56b3253b998c8c63428ef121..84a0d7ca3049846c4fbb234bab02b5f4d3c7ffd5 100644
--- a/modules/camera/src/vkcv/camera/CameraManager.cpp
+++ b/modules/camera/src/vkcv/camera/CameraManager.cpp
@@ -14,7 +14,13 @@ namespace vkcv::camera {
         m_lastY = static_cast<float>(window.getHeight()) / 2.0f;
     }
 
-    CameraManager::~CameraManager() {}
+    CameraManager::~CameraManager() {
+    	m_window.e_key.remove(m_keyHandle);
+		m_window.e_mouseMove.remove(m_mouseMoveHandle);
+		m_window.e_mouseScroll.remove(m_mouseScrollHandle);
+		m_window.e_mouseButton.remove(m_mouseButtonHandle);
+		m_window.e_resize.remove(m_resizeHandle);
+    }
 
     void CameraManager::bindCameraToEvents() {
         m_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); });
diff --git a/modules/gui/CMakeLists.txt b/modules/gui/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ce03f16e1f8d421f5b8e6c2fe913c0da04d34598
--- /dev/null
+++ b/modules/gui/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.16)
+project(vkcv_gui)
+
+# setting c++ standard for the module
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(vkcv_gui_source ${PROJECT_SOURCE_DIR}/src)
+set(vkcv_gui_include ${PROJECT_SOURCE_DIR}/include)
+
+# Add source and header files to the module
+set(vkcv_gui_sources
+		${vkcv_gui_include}/vkcv/gui/GUI.hpp
+		${vkcv_gui_source}/vkcv/gui/GUI.cpp
+		)
+
+# Setup some path variables to load libraries
+set(vkcv_gui_lib lib)
+set(vkcv_gui_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_gui_lib})
+
+# Check and load IMGUI
+include(config/ImGui.cmake)
+
+# adding source files to the module
+add_library(vkcv_gui STATIC ${vkcv_gui_sources} ${vkcv_imgui_sources})
+
+# link the required libraries to the module
+target_link_libraries(vkcv_gui ${vkcv_gui_libraries} vkcv ${vkcv_libraries})
+
+# including headers of dependencies and the VkCV framework
+target_include_directories(vkcv_gui SYSTEM BEFORE PRIVATE ${vkcv_gui_includes} ${vkcv_include} ${vkcv_includes})
+
+# add the own include directory for public headers
+target_include_directories(vkcv_gui BEFORE PUBLIC ${vkcv_gui_include} ${vkcv_imgui_includes})
diff --git a/modules/gui/config/ImGui.cmake b/modules/gui/config/ImGui.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..3f55ad05c34783ba0e82c41d2cbc4e5b204d60e7
--- /dev/null
+++ b/modules/gui/config/ImGui.cmake
@@ -0,0 +1,17 @@
+
+if (EXISTS "${vkcv_gui_lib_path}/imgui")
+	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_vulkan.cpp )
+	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui.cpp)
+	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_draw.cpp)
+	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_demo.cpp)
+	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_tables.cpp)
+	list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_widgets.cpp)
+	
+	list(APPEND vkcv_imgui_includes ${vkcv_gui_lib}/imgui)
+	list(APPEND vkcv_imgui_includes ${vkcv_gui_lib}/imgui/backend)
+	
+	list(APPEND vkcv_gui_include ${vkcv_gui_lib})
+else()
+	message(WARNING "IMGUI is required..! Update the submodules!")
+endif ()
diff --git a/modules/gui/include/vkcv/gui/GUI.hpp b/modules/gui/include/vkcv/gui/GUI.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d1a9986c5f69bfd9d4392bd5ae50f0b1f8b60642
--- /dev/null
+++ b/modules/gui/include/vkcv/gui/GUI.hpp
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "imgui/imgui.h"
+#include "imgui/backends/imgui_impl_glfw.h"
+#include "imgui/backends/imgui_impl_vulkan.h"
+
+#include <vkcv/Core.hpp>
+#include <vkcv/Window.hpp>
+
+namespace vkcv::gui {
+
+	class GUI final {
+	private:
+		Window& m_window;
+		Core& m_core;
+		
+		const Context& m_context;
+		
+		ImGuiContext* m_gui_context;
+		
+		vk::DescriptorPool m_descriptor_pool;
+		vk::RenderPass m_render_pass;
+		
+		event_handle<int,int,int> f_mouseButton;
+		event_handle<double,double> f_mouseScroll;
+		event_handle<int,int,int,int> f_key;
+		event_handle<unsigned int> f_char;
+		
+	public:
+		/**
+		 * Constructor of a new instance of ImGui management
+		 *
+		 * @param core Valid #Core instance of the framework
+		 * @param window Valid #Window instance of the framework
+		 */
+		GUI(Core& core, Window& window);
+		
+		GUI(const GUI& other) = delete;
+		GUI(GUI&& other) = delete;
+		
+		GUI& operator=(const GUI& other) = delete;
+		GUI& operator=(GUI&& other) = delete;
+		
+		/**
+		 * Destructor of a #GUI instance
+		 */
+		virtual ~GUI();
+		
+		/**
+		 * Sets up a new frame for ImGui to draw
+		 */
+		void beginGUI();
+		
+		/**
+		 * Ends a frame for ImGui, renders it and draws it onto
+		 * the currently active swapchain image of the core (ready to present).
+		 */
+		void endGUI();
+		
+	};
+
+}
diff --git a/modules/gui/lib/imgui b/modules/gui/lib/imgui
new file mode 160000
index 0000000000000000000000000000000000000000..d5828cd988db525f27128edeadb1a689cd2d7461
--- /dev/null
+++ b/modules/gui/lib/imgui
@@ -0,0 +1 @@
+Subproject commit d5828cd988db525f27128edeadb1a689cd2d7461
diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..096a857a13f01840d8a3a7e2bf74ba571bd2c249
--- /dev/null
+++ b/modules/gui/src/vkcv/gui/GUI.cpp
@@ -0,0 +1,239 @@
+
+#include "vkcv/gui/GUI.hpp"
+
+#include <GLFW/glfw3.h>
+#include <vkcv/Logger.hpp>
+
+namespace vkcv::gui {
+	
+	static void checkVulkanResult(VkResult resultCode) {
+		if (resultCode == 0)
+			return;
+		
+		const auto result = vk::Result(resultCode);
+		
+		vkcv_log(LogLevel::ERROR, "ImGui has a problem with Vulkan! (%s)", vk::to_string(result).c_str());
+	}
+	
+	GUI::GUI(Core& core, Window& window) :
+	m_window(window),
+	m_core(core),
+	m_context(m_core.getContext()),
+	m_gui_context(nullptr) {
+		IMGUI_CHECKVERSION();
+		
+		m_gui_context = ImGui::CreateContext();
+		
+		ImGui_ImplGlfw_InitForVulkan(m_window.getWindow(), false);
+		
+		f_mouseButton = m_window.e_mouseButton.add([&](int button, int action, int mods) {
+			ImGui_ImplGlfw_MouseButtonCallback(m_window.getWindow(), button, action, mods);
+		});
+		
+		f_mouseScroll = m_window.e_mouseScroll.add([&](double xoffset, double yoffset) {
+			ImGui_ImplGlfw_ScrollCallback(m_window.getWindow(), xoffset, yoffset);
+		});
+		
+		f_key = m_window.e_key.add([&](int key, int scancode, int action, int mods) {
+			ImGui_ImplGlfw_KeyCallback(m_window.getWindow(), key, scancode, action, mods);
+		});
+		
+		f_char = m_window.e_char.add([&](unsigned int c) {
+			ImGui_ImplGlfw_CharCallback(m_window.getWindow(), c);
+		});
+		
+		vk::DescriptorPoolSize pool_sizes[] = {
+				vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eStorageImage, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eUniformTexelBuffer, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eStorageTexelBuffer, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000),
+				vk::DescriptorPoolSize(vk::DescriptorType::eInputAttachment, 1000)
+		};
+		
+		const vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo (
+				vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
+				static_cast<uint32_t>(1000 * IM_ARRAYSIZE(pool_sizes)),
+				static_cast<uint32_t>(IM_ARRAYSIZE(pool_sizes)),
+				pool_sizes
+		);
+		
+		m_descriptor_pool = m_context.getDevice().createDescriptorPool(descriptorPoolCreateInfo);
+		
+		const vk::PhysicalDevice& physicalDevice = m_context.getPhysicalDevice();
+		const Swapchain& swapchain = m_core.getSwapchain();
+		
+		const uint32_t graphicsQueueFamilyIndex = (
+				m_context.getQueueManager().getGraphicsQueues()[0].familyIndex
+		);
+		
+		ImGui_ImplVulkan_InitInfo init_info = {};
+		init_info.Instance = m_context.getInstance();
+		init_info.PhysicalDevice = m_context.getPhysicalDevice();
+		init_info.Device = m_context.getDevice();
+		init_info.QueueFamily = graphicsQueueFamilyIndex;
+		init_info.Queue = m_context.getQueueManager().getGraphicsQueues()[0].handle;
+		init_info.PipelineCache = nullptr;
+		init_info.DescriptorPool = m_descriptor_pool;
+		init_info.Allocator = nullptr;
+		init_info.MinImageCount = swapchain.getImageCount();
+		init_info.ImageCount = swapchain.getImageCount();
+		init_info.CheckVkResultFn = checkVulkanResult;
+		
+		const vk::AttachmentDescription attachment (
+				vk::AttachmentDescriptionFlags(),
+				swapchain.getFormat(),
+				vk::SampleCountFlagBits::e1,
+				vk::AttachmentLoadOp::eLoad,
+				vk::AttachmentStoreOp::eStore,
+				vk::AttachmentLoadOp::eDontCare,
+				vk::AttachmentStoreOp::eDontCare,
+				vk::ImageLayout::eUndefined,
+				vk::ImageLayout::ePresentSrcKHR
+		);
+		
+		const vk::AttachmentReference attachmentReference (
+				0,
+				vk::ImageLayout::eColorAttachmentOptimal
+		);
+		
+		const vk::SubpassDescription subpass (
+				vk::SubpassDescriptionFlags(),
+				vk::PipelineBindPoint::eGraphics,
+				0,
+				nullptr,
+				1,
+				&attachmentReference,
+				nullptr,
+				nullptr,
+				0,
+				nullptr
+		);
+		
+		const vk::SubpassDependency dependency (
+				VK_SUBPASS_EXTERNAL,
+				0,
+				vk::PipelineStageFlagBits::eColorAttachmentOutput,
+				vk::PipelineStageFlagBits::eColorAttachmentOutput,
+				vk::AccessFlags(),
+				vk::AccessFlagBits::eColorAttachmentWrite,
+				vk::DependencyFlags()
+		);
+		
+		const vk::RenderPassCreateInfo passCreateInfo (
+				vk::RenderPassCreateFlags(),
+				1,
+				&attachment,
+				1,
+				&subpass,
+				1,
+				&dependency
+		);
+		
+		m_render_pass = m_context.getDevice().createRenderPass(passCreateInfo);
+		
+		ImGui_ImplVulkan_Init(&init_info, m_render_pass);
+		
+		const SubmitInfo submitInfo { QueueType::Graphics, {}, {} };
+		
+		m_core.recordAndSubmitCommands(submitInfo, [](const vk::CommandBuffer& commandBuffer) {
+			ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
+		}, []() {
+			ImGui_ImplVulkan_DestroyFontUploadObjects();
+		});
+		
+		m_context.getDevice().waitIdle();
+	}
+	
+	GUI::~GUI() {
+		m_context.getDevice().waitIdle();
+		
+		ImGui_ImplVulkan_Shutdown();
+		
+		m_context.getDevice().destroyRenderPass(m_render_pass);
+		m_context.getDevice().destroyDescriptorPool(m_descriptor_pool);
+		
+		ImGui_ImplGlfw_Shutdown();
+		
+		m_window.e_mouseButton.remove(f_mouseButton);
+		m_window.e_mouseScroll.remove(f_mouseScroll);
+		m_window.e_key.remove(f_key);
+		m_window.e_char.remove(f_char);
+		
+		if (m_gui_context) {
+			ImGui::DestroyContext(m_gui_context);
+		}
+	}
+	
+	void GUI::beginGUI() {
+		const Swapchain& swapchain = m_core.getSwapchain();
+		const auto extent = swapchain.getExtent();
+		
+		if ((extent.width > 0) && (extent.height > 0)) {
+			ImGui_ImplVulkan_SetMinImageCount(swapchain.getImageCount());
+		}
+		
+		ImGui_ImplVulkan_NewFrame();
+		ImGui_ImplGlfw_NewFrame();
+		ImGui::NewFrame();
+	}
+	
+	void GUI::endGUI() {
+		ImGui::Render();
+		
+		ImDrawData* drawData = ImGui::GetDrawData();
+		
+		if ((!drawData) ||
+			(drawData->DisplaySize.x <= 0.0f) ||
+			(drawData->DisplaySize.y <= 0.0f)) {
+			return;
+		}
+		
+		const Swapchain& swapchain = m_core.getSwapchain();
+		const auto extent = swapchain.getExtent();
+		
+		const vk::FramebufferCreateInfo framebufferCreateInfo (
+				vk::FramebufferCreateFlags(),
+				m_render_pass,
+				1,
+				&m_core.getSwapchainImageView(),
+				extent.width,
+				extent.height,
+				1
+		);
+		
+		const vk::Framebuffer framebuffer = m_context.getDevice().createFramebuffer(framebufferCreateInfo);
+		
+		SubmitInfo submitInfo;
+		submitInfo.queueType = QueueType::Graphics;
+		
+		m_core.recordAndSubmitCommands(submitInfo, [&](const vk::CommandBuffer& commandBuffer) {
+			const vk::Rect2D renderArea (
+					vk::Offset2D(0, 0),
+					extent
+			);
+			
+			const vk::RenderPassBeginInfo beginInfo (
+					m_render_pass,
+					framebuffer,
+					renderArea,
+					0,
+					nullptr
+			);
+			
+			commandBuffer.beginRenderPass(beginInfo, vk::SubpassContents::eInline);
+			
+			ImGui_ImplVulkan_RenderDrawData(drawData, commandBuffer);
+			
+			commandBuffer.endRenderPass();
+		}, [&]() {
+			m_context.getDevice().destroyFramebuffer(framebuffer);
+		});
+	}
+	
+}
diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
index 7214e208b068ba7b9002363e594f76d66123bffd..9e07dec255d283b4b8a8d4fcc769083498c10264 100644
--- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
@@ -167,12 +167,13 @@ namespace vkcv::shader {
 		}
 		
 		std::streamsize fileSize = file.tellg();
-		std::vector<char> buffer (fileSize);
+		std::vector<char> buffer (fileSize + 1);
 		
 		file.seekg(0);
 		file.read(buffer.data(), fileSize);
 		file.close();
 		
+		buffer[fileSize] = '\0';
 		return buffer;
 	}
 	
diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp
index c33f1adc985b40566aa25c5f51e2a1c622dfa280..7ec54582aac6b16a484b74183036539e91cfe731 100644
--- a/projects/cmd_sync_test/src/main.cpp
+++ b/projects/cmd_sync_test/src/main.cpp
@@ -86,7 +86,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchainImageFormat()
+		core.getSwapchain().getFormat()
 	);
 	
 	const vkcv::AttachmentDescription depth_attachment(
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 8ffe501747fe516de9ab10834de788f110ad8722..6377a6726d3e9d1830518206133dd7780593d576 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -63,7 +63,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchainImageFormat()
+		core.getSwapchain().getFormat()
 	);
 	
 	const vkcv::AttachmentDescription depth_attachment(
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index 5a59edf7549dfd50877e78e3ca5071bba72098b3..00a862cfd77b522e9d83b51e703ea48ce45e5d5c 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -112,7 +112,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchainImageFormat()
+		core.getSwapchain().getFormat()
 	);
 
 	const vkcv::AttachmentDescription depth_attachment(
diff --git a/projects/first_triangle/CMakeLists.txt b/projects/first_triangle/CMakeLists.txt
index 7e606b2348ea82486c2a57ee1062ef34150e46a0..ba8c83c06fc804082e6a0a14c3c0414899ef3057 100644
--- a/projects/first_triangle/CMakeLists.txt
+++ b/projects/first_triangle/CMakeLists.txt
@@ -22,7 +22,7 @@ if(MSVC)
 endif()
 
 # 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})
+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})
 
 # linking with libraries from all dependencies and the VkCV framework
-target_link_libraries(first_triangle vkcv vkcv_testing vkcv_camera vkcv_shader_compiler)
+target_link_libraries(first_triangle vkcv vkcv_testing vkcv_camera vkcv_shader_compiler vkcv_gui)
diff --git a/projects/first_triangle/shaders/shader.frag b/projects/first_triangle/shaders/shader.frag
index d26446a73020111695aa2c86166205796dfa5e44..080678beb011afe4b03aed3bf7ae7148b77932dc 100644
--- a/projects/first_triangle/shaders/shader.frag
+++ b/projects/first_triangle/shaders/shader.frag
@@ -4,6 +4,6 @@
 layout(location = 0) in vec3 fragColor;
 layout(location = 0) out vec4 outColor;
 
-void main()	{
+void main() {
 	outColor = vec4(fragColor, 1.0);
 }
\ No newline at end of file
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 1c6f96041874a262b481727caf41e0b1142f5570..5a962b8983f6735530b38de5be679096fa997bd5 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -5,6 +5,7 @@
 #include <chrono>
 
 #include <vkcv/shader/GLSLCompiler.hpp>
+#include <vkcv/gui/GUI.hpp>
 
 int main(int argc, const char** argv) {
 	const char* applicationName = "First Triangle";
@@ -28,6 +29,8 @@ int main(int argc, const char** argv) {
 		{},
 		{ "VK_KHR_swapchain" }
 	);
+	
+	vkcv::gui::GUI gui (core, window);
 
 	const auto& context = core.getContext();
 	const vk::Instance& instance = context.getInstance();
@@ -81,7 +84,7 @@ int main(int argc, const char** argv) {
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchainImageFormat());
+		core.getSwapchain().getFormat());
 
 	vkcv::PassConfig trianglePassDefinition({ present_color_attachment });
 	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
@@ -215,6 +218,14 @@ int main(int argc, const char** argv) {
 
 		core.prepareSwapchainImageForPresent(cmdStream);
 		core.submitCommandStream(cmdStream);
+		
+		gui.beginGUI();
+		
+		ImGui::Begin("Hello world");
+		ImGui::Text("This is a test!");
+		ImGui::End();
+		
+		gui.endGUI();
 	    
 	    core.endFrame();
 	}
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 44e7111e1f4941ef2f0f8114ac788d7db4a13b5a..49707d4cffc18719d8fbb18a9e632e12ba679c2e 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -35,7 +35,7 @@ namespace vkcv
         		deviceExtensions
 		);
 
-        SwapChain swapChain = SwapChain::create(window, context);
+        Swapchain swapChain = Swapchain::create(window, context);
 
         std::vector<vk::ImageView> imageViews;
         imageViews = createImageViews( context, swapChain);
@@ -54,8 +54,12 @@ namespace vkcv
     {
         return m_Context;
     }
+    
+    const Swapchain& Core::getSwapchain() const {
+    	return m_swapchain;
+    }
 
-    Core::Core(Context &&context, Window &window, const SwapChain& swapChain,  std::vector<vk::ImageView> imageViews,
+    Core::Core(Context &&context, Window &window, const Swapchain& swapChain,  std::vector<vk::ImageView> imageViews,
         const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
             m_Context(std::move(context)),
             m_window(window),
@@ -76,8 +80,8 @@ namespace vkcv
 		m_CommandStreamManager->init(this);
 
 		m_ImageManager->m_core = this;
-
-		e_resizeHandle = window.e_resize.add( [&](int width, int height) {
+		
+		e_resizeHandle = m_window.e_resize.add( [&](int width, int height) {
 			m_swapchain.signalSwapchainRecreation();
 		});
 
@@ -86,6 +90,8 @@ namespace vkcv
 	}
 
 	Core::~Core() noexcept {
+    	m_window.e_resize.remove(e_resizeHandle);
+    	
 		m_Context.getDevice().waitIdle();
 		for (auto image : m_swapchainImageViews) {
 			m_Context.m_Device.destroyImageView(image);
@@ -232,7 +238,6 @@ namespace vkcv
 			attachmentsViews.push_back(targetHandle);
 		}
 		
-		vk::Framebuffer framebuffer = nullptr;
         const vk::FramebufferCreateInfo createInfo(
             {},
             renderpass,
@@ -240,16 +245,21 @@ namespace vkcv
             attachmentsViews.data(),
             width,
             height,
-            1);
-        if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess)
-        {
+            1
+		);
+		
+		vk::Framebuffer framebuffer = m_Context.m_Device.createFramebuffer(createInfo);
+        
+        if (!framebuffer) {
 			vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
             return;
         }
 
-        vk::Viewport dynamicViewport(0.0f, 0.0f,
-            static_cast<float>(width), static_cast<float>(height),
-            0.0f, 1.0f);
+        vk::Viewport dynamicViewport(
+        		0.0f, 0.0f,
+            	static_cast<float>(width), static_cast<float>(height),
+            0.0f, 1.0f
+		);
 
         vk::Rect2D dynamicScissor({0, 0}, {width, height});
 
@@ -349,15 +359,17 @@ namespace vkcv
 		const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain());
 
 		const auto& queueManager = m_Context.getQueueManager();
-		std::array<vk::Semaphore, 2> waitSemaphores{ 
-			m_SyncResources.renderFinished, 
-			m_SyncResources.swapchainImageAcquired };
+		std::array<vk::Semaphore, 2> waitSemaphores{
+			m_SyncResources.renderFinished,
+			m_SyncResources.swapchainImageAcquired
+		};
 
 		const vk::SwapchainKHR& swapchain = m_swapchain.getSwapchain();
 		const vk::PresentInfoKHR presentInfo(
 			waitSemaphores,
 			swapchain,
-			m_currentSwapchainImageIndex);
+			m_currentSwapchainImageIndex
+		);
 		
 		vk::Result result;
 		
@@ -371,10 +383,6 @@ namespace vkcv
 			vkcv_log(LogLevel::ERROR, "Swapchain present failed (%s)", vk::to_string(result).c_str());
 		}
 	}
-
-	vk::Format Core::getSwapchainImageFormat() {
-		return m_swapchain.getSwapchainFormat();
-	}
 	
 	void Core::recordAndSubmitCommands(
 		const SubmitInfo &submitInfo, 
@@ -390,11 +398,19 @@ namespace vkcv
 		beginCommandBuffer(cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
 		record(cmdBuffer);
 		cmdBuffer.end();
-
-		const vk::Fence waitFence = createFence(device);
+		
+		vk::Fence waitFence;
+		
+		if (!submitInfo.fence) {
+			waitFence = createFence(device);
+		}
+		
 		submitCommandBufferToQueue(queue.handle, cmdBuffer, waitFence, submitInfo.waitSemaphores, submitInfo.signalSemaphores);
 		waitForFence(device, waitFence);
-		device.destroyFence(waitFence);
+		
+		if (!submitInfo.fence) {
+			device.destroyFence(waitFence);
+		}
 		
 		device.freeCommandBuffers(cmdPool, cmdBuffer);
 		
@@ -458,7 +474,7 @@ namespace vkcv
 		return m_DescriptorManager->getDescriptorSet(handle);
 	}
 
-    std::vector<vk::ImageView> Core::createImageViews( Context &context, SwapChain& swapChain){
+    std::vector<vk::ImageView> Core::createImageViews( Context &context, Swapchain& swapChain){
         std::vector<vk::ImageView> imageViews;
         std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain());
         imageViews.reserve( swapChainImages.size() );
@@ -477,7 +493,7 @@ namespace vkcv
                     vk::ImageViewCreateFlags(),
                     image,
                     vk::ImageViewType::e2D,
-                    swapChain.getSwapchainFormat(),
+                    swapChain.getFormat(),
                     componentMapping,
                     subResourceRange);
 
@@ -507,4 +523,9 @@ namespace vkcv
 			m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer);
 		}, nullptr);
 	}
+	
+	const vk::ImageView& Core::getSwapchainImageView() const {
+    	return m_swapchainImageViews[m_currentSwapchainImageIndex];
+    }
+	
 }
diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/Swapchain.cpp
similarity index 88%
rename from src/vkcv/SwapChain.cpp
rename to src/vkcv/Swapchain.cpp
index b787536b66cfd802dfd435a773a584c875eeb391..639e949bc442588ece4e13b92bd032ecbd513352 100644
--- a/src/vkcv/SwapChain.cpp
+++ b/src/vkcv/Swapchain.cpp
@@ -1,4 +1,4 @@
-#include <vkcv/SwapChain.hpp>
+#include <vkcv/Swapchain.hpp>
 #include <utility>
 
 #define GLFW_INCLUDE_VULKAN
@@ -27,44 +27,44 @@ namespace vkcv
         return vk::SurfaceKHR(surface);
     }
 
-    SwapChain::SwapChain(const Surface &surface,
+    Swapchain::Swapchain(const Surface &surface,
                          vk::SwapchainKHR swapchain,
                          vk::Format format,
                          vk::ColorSpaceKHR colorSpace,
                          vk::PresentModeKHR presentMode,
                          uint32_t imageCount,
 						 vk::Extent2D extent) noexcept :
-    m_Surface(surface),
-    m_Swapchain(swapchain),
-    m_SwapchainFormat(format),
-    m_SwapchainColorSpace(colorSpace),
-    m_SwapchainPresentMode(presentMode),
-    m_SwapchainImageCount(imageCount),
-	m_Extent(extent),
-    m_RecreationRequired(false)
+			m_Surface(surface),
+			m_Swapchain(swapchain),
+			m_Format(format),
+			m_ColorSpace(colorSpace),
+			m_PresentMode(presentMode),
+			m_ImageCount(imageCount),
+			m_Extent(extent),
+			m_RecreationRequired(false)
     {}
     
-    SwapChain::SwapChain(const SwapChain &other) :
+    Swapchain::Swapchain(const Swapchain &other) :
 			m_Surface(other.m_Surface),
 			m_Swapchain(other.m_Swapchain),
-			m_SwapchainFormat(other.m_SwapchainFormat),
-			m_SwapchainColorSpace(other.m_SwapchainColorSpace),
-			m_SwapchainPresentMode(other.m_SwapchainPresentMode),
-			m_SwapchainImageCount(other.m_SwapchainImageCount),
+			m_Format(other.m_Format),
+			m_ColorSpace(other.m_ColorSpace),
+			m_PresentMode(other.m_PresentMode),
+			m_ImageCount(other.m_ImageCount),
 			m_Extent(other.m_Extent),
 			m_RecreationRequired(other.m_RecreationRequired.load())
 	{}
 
-    const vk::SwapchainKHR& SwapChain::getSwapchain() const {
+    const vk::SwapchainKHR& Swapchain::getSwapchain() const {
         return m_Swapchain;
     }
 
-    vk::SurfaceKHR SwapChain::getSurface() const {
+    vk::SurfaceKHR Swapchain::getSurface() const {
         return m_Surface.handle;
     }
 
-    vk::Format SwapChain::getSwapchainFormat() const{
-        return m_SwapchainFormat;
+    vk::Format Swapchain::getFormat() const{
+        return m_Format;
     }
 
     /**
@@ -162,7 +162,7 @@ namespace vkcv
      * @param context that keeps instance, physicalDevice and a device.
      * @return swapchain
      */
-    SwapChain SwapChain::create(const Window &window, const Context &context) {
+    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();
@@ -199,7 +199,7 @@ namespace vkcv
 
         vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo);
 
-        return SwapChain(surface,
+        return Swapchain(surface,
                          swapchain,
                          chosenSurfaceFormat.format,
                          chosenSurfaceFormat.colorSpace,
@@ -208,11 +208,11 @@ namespace vkcv
 						 chosenExtent);
     }
     
-    bool SwapChain::shouldUpdateSwapchain() const {
+    bool Swapchain::shouldUpdateSwapchain() const {
     	return m_RecreationRequired;
     }
     
-    void SwapChain::updateSwapchain(const Context &context, const Window &window) {
+    void Swapchain::updateSwapchain(const Context &context, const Window &window) {
     	if (!m_RecreationRequired.exchange(false))
     		return;
     	
@@ -222,9 +222,9 @@ namespace vkcv
 		vk::SwapchainCreateInfoKHR swapchainCreateInfo(
 				vk::SwapchainCreateFlagsKHR(),
 				m_Surface.handle,
-				m_SwapchainImageCount,
-				m_SwapchainFormat,
-				m_SwapchainColorSpace,
+				m_ImageCount,
+				m_Format,
+				m_ColorSpace,
 				extent2D,
 				1,
 				vk::ImageUsageFlagBits::eColorAttachment,
@@ -233,7 +233,7 @@ namespace vkcv
 				nullptr,
 				vk::SurfaceTransformFlagBitsKHR::eIdentity,
 				vk::CompositeAlphaFlagBitsKHR::eOpaque,
-				m_SwapchainPresentMode,
+				m_PresentMode,
 				true,
 				oldSwapchain
 		);
@@ -244,19 +244,19 @@ namespace vkcv
 		m_Extent = extent2D;
     }
 
-    void SwapChain::signalSwapchainRecreation() {
+    void Swapchain::signalSwapchainRecreation() {
 		m_RecreationRequired = true;
     }
     
-    const vk::Extent2D& SwapChain::getExtent() const {
+    const vk::Extent2D& Swapchain::getExtent() const {
     	return m_Extent;
     }
 
-    SwapChain::~SwapChain() {
+    Swapchain::~Swapchain() {
         // needs to be destroyed by creator
     }
 
-	uint32_t SwapChain::getImageCount() {
-		return m_SwapchainImageCount;
+	uint32_t Swapchain::getImageCount() const {
+		return m_ImageCount;
 	}
 }
diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp
index c21271b78f7501721d5c0496d0344dd68e2e7e52..2436619300c24f035cba727481dfce8e1b397c9b 100644
--- a/src/vkcv/Window.cpp
+++ b/src/vkcv/Window.cpp
@@ -24,22 +24,25 @@ namespace vkcv {
             glfwTerminate();
         }
     }
+	
+    GLFWwindow* Window::createGLFWWindow(const char *windowTitle, int width, int height, bool resizable) {
+		if(s_WindowCount == 0) {
+			glfwInit();
+		}
+	
+		s_WindowCount++;
+	
+		width = std::max(width, 1);
+		height = std::max(height, 1);
+	
+		glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+		glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE);
+		
+		return glfwCreateWindow(width, height, windowTitle, nullptr, nullptr);
+    }
 
     Window Window::create( const char *windowTitle, int width, int height, bool resizable) {
-        if(s_WindowCount == 0) {
-            glfwInit();
-        }
-        s_WindowCount++;
-
-        width = std::max(width, 1);
-        height = std::max(height, 1);
-
-        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
-        glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE);
-        GLFWwindow *window;
-        window = glfwCreateWindow(width, height, windowTitle, nullptr, nullptr);
-
-        return Window(window);
+        return Window(createGLFWWindow(windowTitle, width, height, resizable));
     }
 
     void Window::initEvents() {
@@ -55,6 +58,8 @@ namespace vkcv {
         glfwSetKeyCallback(m_window, Window::onKeyEvent);
 
         glfwSetScrollCallback(m_window, Window::onMouseScrollEvent);
+	
+		glfwSetCharCallback(m_window, Window::onCharEvent);
     }
 
     void Window::pollEvents() {
@@ -62,7 +67,6 @@ namespace vkcv {
     }
 
     void Window::onMouseButtonEvent(GLFWwindow *callbackWindow, int button, int action, int mods) {
-
         auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
 
         if (window != nullptr) {
@@ -71,7 +75,6 @@ namespace vkcv {
     }
 
     void Window::onMouseMoveEvent(GLFWwindow *callbackWindow, double x, double y) {
-
         auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
 
         if (window != nullptr) {
@@ -88,7 +91,6 @@ namespace vkcv {
     }
 
     void Window::onResize(GLFWwindow *callbackWindow, int width, int height) {
-
         auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
 
         if (window != nullptr) {
@@ -97,13 +99,20 @@ namespace vkcv {
     }
 
     void Window::onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods) {
-
         auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
 
         if (window != nullptr) {
             window->e_key(key, scancode, action, mods);
         }
     }
+    
+    void Window::onCharEvent(GLFWwindow *callbackWindow, unsigned int c) {
+		auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
+	
+		if (window != nullptr) {
+			window->e_char(c);
+		}
+    }
 
     bool Window::isWindowOpen() const {
         return !glfwWindowShouldClose(m_window);