diff --git a/config/Sources.cmake b/config/Sources.cmake
index 0d0a37876813861c605466566eced727a70f6488..9d2c7b1f2595beb17212a6daf1b5331d8926d76d 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -51,4 +51,6 @@ set(vkcv_sources
         
         ${vkcv_source}/vkcv/Framebuffer.hpp
         ${vkcv_source}/vkcv/Framebuffer.cpp
+
+		${vkcv_include}/vkcv/Event.hpp
 )
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 45e555151584e60f4edd29058e5a59e076f9fafc..065c21d225810f465f0909cb8c1479c1031aba8f 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -33,7 +33,7 @@ namespace vkcv
          *
          * @param context encapsulates various Vulkan objects
          */
-        Core(Context &&context, const Window &window, SwapChain swapChain,  std::vector<vk::ImageView> imageViews, 
+        Core(Context &&context, Window &window, SwapChain swapChain,  std::vector<vk::ImageView> imageViews,
 			const CommandResources& commandResources, const SyncResources& syncResources) noexcept;
         // explicit destruction of default constructor
         Core() = delete;
@@ -53,6 +53,14 @@ namespace vkcv
 		SyncResources m_SyncResources;
 		uint32_t m_currentSwapchainImageIndex;
 		std::vector<vk::Framebuffer> m_TemporaryFramebuffers;
+
+        /**
+         * recreates the swapchain
+         * @param[in] width new window width
+         * @param[in] height new window hight
+         */
+        static void recreateSwapchain(int width, int height);
+
     public:
         /**
          * Destructor of #Core destroys the Vulkan objects contained in the core's context.
@@ -107,7 +115,7 @@ namespace vkcv
              * @param[in] deviceExtensions (optional) Requested device extensions
              * @return New instance of #Context
              */
-        static Core create(const Window &window,
+        static Core create(Window &window,
                            const char *applicationName,
                            uint32_t applicationVersion,
                            std::vector<vk::QueueFlagBits> queueFlags    = {},
diff --git a/include/vkcv/Event.hpp b/include/vkcv/Event.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..092f271c025e63be80b994b6b3921795c3e99671
--- /dev/null
+++ b/include/vkcv/Event.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <functional>
+
+namespace vkcv {
+
+    template<typename... T>
+    struct event_function {
+        typedef std::function<void(T...)> type;
+    };
+
+    /**
+     * template for event handling
+     * @tparam T parameter list
+     */
+    template<typename... T>
+    struct event {
+    private:
+        std::vector<typename event_function<T...>::type> m_handles;
+
+    public:
+
+        /**
+         * calls all function handles with the given arguments
+         * @param arguments of the given function
+         */
+        void operator()(T... arguments) {
+            for (auto &handle : this->m_handles) {
+                handle(arguments...);
+            }
+        }
+
+        /**
+         * adds a function handle to the event to be called
+         * @param handle of the function
+         */
+        void add(typename event_function<T...>::type handle) {
+            this->m_handles.push_back(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()
+            );
+        }
+
+        event() = default;
+
+        event(const event &other) = delete;
+
+        event(event &&other) = delete;
+
+        ~event() = default;
+
+        event &operator=(const event &other) = delete;
+
+        event &operator=(event &&other) = delete;
+    };
+}
diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp
index 87c98a9281e6081c98487c7fd314d960b818190f..bb8081c166360e97595ff6994971390e53d6aa32 100644
--- a/include/vkcv/Window.hpp
+++ b/include/vkcv/Window.hpp
@@ -7,6 +7,7 @@
 
 #define NOMINMAX
 #include <algorithm>
+#include "Event.hpp"
 
 struct GLFWwindow;
 
@@ -23,6 +24,32 @@ namespace vkcv {
          */
         explicit Window(GLFWwindow *window);
 
+        /**
+         * mouse callback for moving the mouse on the screen
+         * @param[in] window The window that received the event.
+         * @param[in] xpos The new cursor x-coordinate, relative to the left edge of the content area.
+         * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the content area.
+         */
+        static void onMouseMoveEvent(GLFWwindow *window, double x, double y);
+
+        /**
+         * resize callback for the resize option of the window
+         * @param[in] window The window that was resized.
+         * @param[in] width The new width, in screen coordinates, of the window.
+         * @param[in] height The new height, in screen coordinates, of the window.
+         */
+        static void onResize(GLFWwindow *callbackWindow, int width, int height);
+
+        /**
+         * key callback for the pressed key
+         * @param[in] window The window that received the event.
+         * @param[in] key The [keyboard key](@ref keys) that was pressed or released.
+         * @param[in] scancode The system-specific scancode of the key.
+         * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`.
+         * @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);
+
     public:
         /**
          * creates a GLFWwindow with the parameters in the function
@@ -41,11 +68,23 @@ namespace vkcv {
         [[nodiscard]]
         bool isWindowOpen() const;
 
+        /**
+         * binds windowEvents to lambda events
+         */
+        void initEvents();
+
         /**
          * polls all events on the GLFWwindow
          */
         static void pollEvents();
 
+        /**
+         * basic events of the window
+         */
+        event< double, double > e_mouseMove;
+        event< int, int > e_resize;
+        event< int, int, int, int > e_key;
+
         /**
          * returns the current window
          * @return window handle
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 3c3f91de9ac1c4490859559db2bca5bdd089ecfa..d718da0989251b7a992d020324c2bf2131dbf19e 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -2,6 +2,7 @@
 #include <vkcv/Core.hpp>
 #include <vkcv/Window.hpp>
 #include <vkcv/ShaderProgram.hpp>
+#include <GLFW/glfw3.h>
 
 int main(int argc, const char** argv) {
     const char* applicationName = "First Triangle";
@@ -15,6 +16,32 @@ int main(int argc, const char** argv) {
 		false
     );
 
+    // showing basic usage lambda events of window
+    window.e_mouseMove.add([&](double x, double y){
+        std::cout << "movement: " << x << " , " << y << std::endl;
+    });
+
+    window.e_key.add([&](int key, int scancode, int action, int mods){
+        switch (key) {
+            case GLFW_KEY_W:
+                std::cout << "Move forward" << std::endl;
+                break;
+            case GLFW_KEY_A:
+                std::cout << "Move left" << std::endl;
+                break;
+            case GLFW_KEY_S:
+                std::cout << "Move backward" << std::endl;
+                break;
+            case GLFW_KEY_D:
+                std::cout << "Move right" << std::endl;
+                break;
+            default:
+                std::cout << "this key is not supported yet: " << std::endl;
+        }
+    });
+
+    window.initEvents();
+
 	vkcv::Core core = vkcv::Core::create(
             window,
             applicationName,
@@ -102,8 +129,6 @@ int main(int argc, const char** argv) {
 		core.beginFrame();
 	    core.renderTriangle(trianglePass, trianglePipeline, windowWidth, windowHeight);
 	    core.endFrame();
-
-		window.pollEvents();
 	}
 	return 0;
 }
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 41c2ac6f821a4dbd122b65fd06c3585d1fccd79d..488715116cbb3b978dfab79e1e0e3d8e05c0f4dc 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -16,7 +16,7 @@
 namespace vkcv
 {
 
-    Core Core::create(const Window &window,
+    Core Core::create(Window &window,
                       const char *applicationName,
                       uint32_t applicationVersion,
                       std::vector<vk::QueueFlagBits> queueFlags,
@@ -70,6 +70,10 @@ namespace vkcv
 		const auto defaultCommandResources = createDefaultCommandResources(context.getDevice(), graphicQueueFamilyIndex);
 		const auto defaultSyncResources = createDefaultSyncResources(context.getDevice());
 
+        window.e_resize.add([&](int width, int height){
+            recreateSwapchain(width,height);
+        });
+
         return Core(std::move(context) , window, swapChain, imageViews, defaultCommandResources, defaultSyncResources);
     }
 
@@ -78,7 +82,7 @@ namespace vkcv
         return m_Context;
     }
 
-	Core::Core(Context &&context, const Window &window , SwapChain swapChain,  std::vector<vk::ImageView> imageViews, 
+	Core::Core(Context &&context, Window &window , SwapChain swapChain,  std::vector<vk::ImageView> imageViews,
 		const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
             m_Context(std::move(context)),
             m_window(window),
@@ -154,7 +158,7 @@ namespace vkcv
     	if (acquireSwapchainImage() != Result::SUCCESS) {
     		return;
     	}
-		
+		m_window.pollEvents();
 		m_Context.getDevice().waitIdle();	// FIMXE: this is a sin against graphics programming, but its getting late - Alex
 		destroyTemporaryFramebuffers();
 		const vk::CommandBufferUsageFlags beginFlags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
@@ -213,4 +217,9 @@ namespace vkcv
 	vk::Format Core::getSwapchainImageFormat() {
 		return m_swapchain.getSurfaceFormat().format;
 	}
+
+    void Core::recreateSwapchain(int width, int height) {
+        /* boilerplate for #34 */
+        std::cout << "Resized to : " << width << " , " << height << std::endl;
+    }
 }
diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp
index 376f363a95c1e873c435825ba97e155205851347..87f302c146f79f82a9b5334fd6a651fa00a92616 100644
--- a/src/vkcv/Window.cpp
+++ b/src/vkcv/Window.cpp
@@ -42,14 +42,52 @@ namespace vkcv {
         return Window(window);
     }
 
-    bool Window::isWindowOpen() const {
-        return !glfwWindowShouldClose(m_window);
+    void Window::initEvents() {
+        glfwSetWindowUserPointer(m_window, this);
+
+        // combine Callbacks with Events
+        glfwSetCursorPosCallback(m_window, Window::onMouseMoveEvent);
+
+        glfwSetWindowSizeCallback(m_window, Window::onResize);
+
+        glfwSetKeyCallback(m_window, Window::onKeyEvent);
     }
 
     void Window::pollEvents() {
         glfwPollEvents();
     }
 
+    void Window::onMouseMoveEvent(GLFWwindow *callbackWindow, double x, double y) {
+
+        auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
+
+        if (window != nullptr) {
+            window->e_mouseMove(x, y);
+        }
+    }
+
+    void Window::onResize(GLFWwindow *callbackWindow, int width, int height) {
+
+        auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow));
+
+        if (window != nullptr) {
+            window->e_resize(width, height);
+        }
+    }
+
+    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);
+        }
+    }
+
+    bool Window::isWindowOpen() const {
+        return !glfwWindowShouldClose(m_window);
+    }
+
     int Window::getWidth() const {
         int width;
         glfwGetWindowSize(m_window, &width, nullptr);