diff --git a/CMakeLists.txt b/CMakeLists.txt
index 51775f56c9ea503cbccb09fc4ec55a41655fa982..08c0ced9017ee1cc9e264e9a01100b437c03e8bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,7 +33,6 @@ endif ()
 target_precompile_headers(${PROJECT_NAME} PRIVATE
         <algorithm>
         <concepts>
-        <expected>
         <fstream>
         <functional>
         <iostream>
@@ -86,6 +85,7 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
 target_link_libraries(${PROJECT_NAME} PRIVATE VulkanMemoryAllocator)
 
 # GLFW
+set(GLFW_VULKAN_STATIC ON)
 FetchContent_Declare(GLFW
         GIT_REPOSITORY https://github.com/glfw/glfw.git
         GIT_TAG 3.3.9
diff --git a/docs/lectures/01.md b/docs/lectures/01.md
index 436502535205a36353ca32b4d07cd0cd13998f54..4f95dbfe9eaad71ec121c0d28551660d762136b1 100644
--- a/docs/lectures/01.md
+++ b/docs/lectures/01.md
@@ -14,7 +14,7 @@ A workshop folyamán a [Vulkan hivatalos C++ binding-ja](https://github.com/Khro
 
 Bármilyen Vulkan kód kiinduló eleme egy `vk::Instance` (C-ben `VkInstance`) objektum. Ez mondja meg, hogy milyen Vulkan verziót kívánunk használni, és milyen konfigurációkkal.
 
-!!! note inline end ""
+!!! info inline end ""
 
     A C++ binding-ban [RAII támogatás](https://github.com/KhronosGroup/Vulkan-Hpp/blob/main/vk_raii_ProgrammingGuide.md) is adott. De ez tapasztalat alapján nekünk inkább csak a fordítást fogja lassítani, minthogy a kódolásban könnyedséget okozna.
 
@@ -36,3 +36,300 @@ Mivel ez egy Vulkan handle, ezért használat után nekünk kell "felszabadítan
     };
     ```
 
+    Mint minden, Vulkan-ban, az Instance létrehozása is explicit. Így ezt a kódot kiszervezzük egy külön függvénybe.
+
+    ```cpp title="Renderer.cpp"
+    #include "Renderer.hpp"
+
+    [[nodiscard]] auto create_instance() -> vk::UniqueInstance {
+        return {};
+    }
+
+    Renderer::Renderer() : m_instance{ create_instance() } {}
+    ```
+
+Bizonyos játékmotorokhoz külön hardveres támogatás van, amit a Vulkan-nak ilyenkor lehet jelezni. Nekünk erre nem lesz szükség. Egyedül a maximum Vulkan API verziót kell jeleznünk, amit használni tervezünk. Ez jelen esetben *1.1*.
+
+??? example "A `vk::ApplicationInfo` beállításai"
+
+    ```cpp
+    constexpr vk::ApplicationInfo application_info{
+        .apiVersion = VK_API_VERSION_1_1
+    };
+    ```
+
+!!! info inline end "Vulkan layers"
+
+    A mi kódunk és a Vulkan függvényeken keresztül hívott kód közé [**layer**](https://renderdoc.org/vulkan-layer-guide.html)-eket helyezhetünk el profiling-hoz, debug-oláshoz, stb...
+
+Debug-oláshoz beállítünk [egy layer](https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers)-t, ami majd üzenet küld, ha elrontottunk valamit.
+
+??? example "Ezt egy globális változóba szervezzük, mert még később is jól jöhet."
+
+    ```cpp
+    const std::vector<std::string> g_layers{
+    #ifdef ENGINE_VULKAN_DEBUG
+        "VK_LAYER_KHRONOS_validation"
+    #endif
+    };
+    ```
+
+!!! info ""
+
+    A debug üzenetek megformázásához szokás egy úgynevezett [DebugUtilsMessenger](https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers#page_Message-callback) használata. Mi ezzel most nem foglalkozunk.
+
+Ezeknék több mindent is beállíthatnánk még az Instance létrehozásához, de egyelőre megelékszünk ennyivel.
+
+!!! example ""
+
+    ```cpp
+    const std::vector<const char*> g_layers{
+    #ifdef ENGINE_VULKAN_DEBUG
+        "VK_LAYER_KHRONOS_validation"
+    #endif
+    };
+
+    [[nodiscard]] auto create_instance() -> vk::UniqueInstance
+    {
+        constexpr static vk::ApplicationInfo application_info{
+            .apiVersion = VK_API_VERSION_1_1
+        };
+
+        const vk::InstanceCreateInfo create_info{
+            .pApplicationInfo  = &application_info,
+            .enabledLayerCount = static_cast<uint32_t>(g_layers.size()),
+            .ppEnabledLayerNames = g_layers.data(),
+        };
+
+        return vk::createInstanceUnique(create_info);
+    }
+    ```
+
+## Physical Device
+
+Minden a gépen jelen levő Vulkan-képes processzort egy `vk::PhysicalDevice` reprezentál könyvtár. Ezeket a `vk::Instance::enumeratePhysicalDevices` függvénnyel le is kérhetjük.
+
+Érdemes egy diszkrét GPU-val dolgozni, ha az jelen van, rosszabb esetben integrálttal. Így válasszuk ki a számunkra legmegfelelőbb egységet.
+
+!!! example ""
+
+    ```cpp
+        [[nodiscard]] auto choose_physical_device(vk::Instance t_instance) -> vk::PhysicalDevice
+        {
+        const auto physical_devices{ t_instance.enumeratePhysicalDevices() };
+
+        if (std::ranges::empty(physical_devices)) {
+            throw std::runtime_error{ "No Vulkan physical device is available." };
+        }
+
+        auto ranked_devices_view{
+            physical_devices
+            | std::views::transform([](vk::PhysicalDevice t_physical_device) {
+                switch (t_physical_device.getProperties().deviceType) {
+                    case vk::PhysicalDeviceType::eDiscreteGpu:
+                        return std::make_pair(t_physical_device, 2);
+                    case vk::PhysicalDeviceType::eIntegratedGpu:
+                        return std::make_pair(t_physical_device, 1);
+                    default: return std::make_pair(t_physical_device, 0);
+                }
+            })
+        };
+        std::vector ranked_devices(
+            ranked_devices_view.begin(), ranked_devices_view.end()
+        );
+
+        std::ranges::sort(
+            ranked_devices,
+            std::ranges::greater{},
+            &std::pair<vk::PhysicalDevice, int>::second
+        );
+
+        return ranked_devices.front().first;
+    }
+    ```
+
+!!! danger "*A PhysicalDevice-t már nem szabad felszabadítani!*"
+
+## (Logical) Device
+
+Mielőtt elkezdünk a GPU-n dolgozni, azelőtt elengedhetetlen a használni tervezett funkciók megadása. Habár, mi most ezek közül nem fogunk sokat használni, azért érdemes ezt is megemlíteni.
+
+A (Logical) Device szintaktikailag nagyon hasonlít az Instance-hez. Itt is lesz olyan amit majd csak később állítunk be. A mostani alkalommal egyedül a `vk::Queue`-kra fogunk koncentrálni.
+
+A grafikus kártya egy hihetetlenül parallelizált eszköz. Ám ennek a kihasználásához adatot kell neki küldeni, és megmondani hogy mit csináljon. Ez a parancs feldolgozás *Queue*-kon keresztül történik, amelyek képesek párhuzamosan több "command" végrehajtására.
+
+!!! note ""
+
+    Habár egy `vk::Queue` egyszerre több `vk::CommandBuffer` végrehajtására is képes, `vk::CommandBuffer`-eket feldolgozásra küldeni egy `vk::Queue`-nak továbbra is csak egy szálon lehetséges.
+
+Egy `vk::Queue` többféle feladat végrehajtására is képes - legyen az grafikai, általános, adat-átvitel, vagy valami más. A GPU tervezők számunkra a hasonló tulajdonságokkal rendelkező *Queue*-kat úgynevezett *Queue family*-kben teszik elérhetővé.
+
+Válasszunk ki egy grafikai munkát támogató családot (ezek megkötése, hogy adat-átvitelre is képesek legyenek), és abból is egy *Queue*-t. A mi céljainkhoz ez az egy elég lesz mindenre.
+
+!!! example ""
+
+    ```cpp
+    [[nodiscard]] auto find_graphics_queue_family(
+        vk::PhysicalDevice t_physical_device
+    ) -> uint32_t
+    {
+        uint32_t index{};
+        for (const auto& properties : t_physical_device.getQueueFamilyProperties())
+        {
+            if (properties.queueFlags & vk::QueueFlagBits::eGraphics) {
+                return index;
+            }
+            index++;
+        }
+        throw std::runtime_error{ "Could not find graphics queue family" };
+    }
+    ```
+
+Végül hozzuk létre a *Device*-t is.
+
+!!! example ""
+
+    ```cpp
+    [[nodiscard]] auto create_device(const vk::PhysicalDevice t_physical_device)
+        -> vk::UniqueDevice
+    {
+        const vk::DeviceQueueCreateInfo queue_create_info{
+            .queueFamilyIndex = find_graphics_queue_family(t_physical_device),
+            .queueCount       = 1,
+        };
+
+        vk::DeviceCreateInfo device_create_info{
+            .queueCreateInfoCount = 1,
+            .pQueueCreateInfos    = &queue_create_info,
+        };
+
+        return t_physical_device.createDeviceUnique(device_create_info);
+    }
+    ```
+
+!!! tip ""
+
+    A `Renderer`-hez adjuk hozzá az így létrejövő `vk::UniqueDevice`-t, és a kiválasztott `vk::Queue`-t is. (Utóbbi lentebb a végső kódban látható.)
+
+## Elkészült kód
+
+!!! example ""
+
+    ```cpp title="Renderer.hpp"
+    #pragma once
+
+    #include <vulkan/vulkan.hpp>
+
+    class Renderer {
+    public:
+        Renderer();
+
+    private:
+        vk::UniqueInstance m_instance;
+        vk::UniqueDevice m_device;
+        vk::Queue m_graphics_queue;
+    };
+    ```
+
+    ```cpp title="Renderer.cpp"
+    #include "Renderer.hpp"
+
+    #include <algorithm>
+    #include <ranges>
+    #include <vector>
+
+    const std::vector<const char*> g_layers{
+    #ifdef ENGINE_VULKAN_DEBUG
+        "VK_LAYER_KHRONOS_validation"
+    #endif
+    };
+
+    [[nodiscard]] auto create_instance() -> vk::UniqueInstance
+    {
+        constexpr static vk::ApplicationInfo application_info{
+            .apiVersion = VK_API_VERSION_1_1
+        };
+
+        const vk::InstanceCreateInfo create_info{
+            .pApplicationInfo    = &application_info,
+            .enabledLayerCount   = static_cast<uint32_t>(g_layers.size()),
+            .ppEnabledLayerNames = g_layers.data(),
+        };
+
+        return vk::createInstanceUnique(create_info);
+    }
+
+    [[nodiscard]] auto choose_physical_device(const vk::Instance t_instance)
+        -> vk::PhysicalDevice
+    {
+        const auto physical_devices{ t_instance.enumeratePhysicalDevices() };
+
+        if (std::ranges::empty(physical_devices)) {
+            throw std::runtime_error{ "No Vulkan physical device is available." };
+        }
+
+        auto ranked_devices_view{
+            physical_devices
+            | std::views::transform([](vk::PhysicalDevice t_physical_device) {
+                switch (t_physical_device.getProperties().deviceType) {
+                    case vk::PhysicalDeviceType::eDiscreteGpu:
+                        return std::make_pair(t_physical_device, 2);
+                    case vk::PhysicalDeviceType::eIntegratedGpu:
+                        return std::make_pair(t_physical_device, 1);
+                    default: return std::make_pair(t_physical_device, 0);
+                }
+            })
+        };
+        std::vector ranked_devices(
+            ranked_devices_view.begin(), ranked_devices_view.end()
+        );
+
+        std::ranges::sort(
+            ranked_devices,
+            std::ranges::greater{},
+            &std::pair<vk::PhysicalDevice, int>::second
+        );
+
+        return ranked_devices.front().first;
+    }
+
+    [[nodiscard]] auto find_graphics_queue_family(
+        const vk::PhysicalDevice t_physical_device
+    ) -> uint32_t
+    {
+        uint32_t index{};
+        for (const auto& properties : t_physical_device.getQueueFamilyProperties())
+        {
+            if (properties.queueFlags & vk::QueueFlagBits::eGraphics) {
+                return index;
+            }
+            index++;
+        }
+        throw std::runtime_error{ "Could not find graphics queue family" };
+    }
+
+    [[nodiscard]] auto create_device(const vk::PhysicalDevice t_physical_device)
+        -> vk::UniqueDevice
+    {
+        const vk::DeviceQueueCreateInfo queue_create_info{
+            .queueFamilyIndex = find_graphics_queue_family(t_physical_device),
+            .queueCount       = 1,
+        };
+
+        vk::DeviceCreateInfo device_create_info{
+            .queueCreateInfoCount = 1,
+            .pQueueCreateInfos    = &queue_create_info,
+        };
+
+        return t_physical_device.createDeviceUnique(device_create_info);
+    }
+
+    Renderer::Renderer()
+        : m_instance{ create_instance() },
+        m_device{ create_device(choose_physical_device(*m_instance)) },
+        m_graphics_queue{ m_device->getQueue(
+            find_graphics_queue_family(choose_physical_device(*m_instance)),
+            0
+        ) }
+    {}
+    ```
diff --git a/src/App.cpp b/src/App.cpp
deleted file mode 100644
index f7f656ff21a8ec6432e75d39bb4df60ef7f7526e..0000000000000000000000000000000000000000
--- a/src/App.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "App.hpp"
-
-#include <iostream>
-
-void App::run()
-{
-    std::cout << "Hello World!\n";
-}
diff --git a/src/App.hpp b/src/App.hpp
deleted file mode 100644
index 31131e74438cc58985cfc65466bb111bb825255b..0000000000000000000000000000000000000000
--- a/src/App.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-class App {
-public:
-    void run();
-};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c1f9dfdc7ae6913c677cf223c70353b742ca654c..9ebb656bf34b033eda29a4abfc3c67d608bb7235 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,4 @@
 target_sources(${PROJECT_NAME} PRIVATE
-        App.cpp
         main.cpp
         Renderer.cpp
-)
\ No newline at end of file
+)
diff --git a/src/Renderer.cpp b/src/Renderer.cpp
index 38dad77cecc5d961bce9f0400300efa87c7eda4c..76a1ecb614b4e9ff8936d433c7671228f4efe9f1 100644
--- a/src/Renderer.cpp
+++ b/src/Renderer.cpp
@@ -1,5 +1,100 @@
 #include "Renderer.hpp"
 
-[[nodiscard]] auto create_instance() -> vk::UniqueInstance {}
+#include <algorithm>
+#include <ranges>
+#include <vector>
 
-Renderer::Renderer() : m_instance{ create_instance() } {}
+const std::vector<const char*> g_layers{
+#ifdef ENGINE_VULKAN_DEBUG
+    "VK_LAYER_KHRONOS_validation"
+#endif
+};
+
+[[nodiscard]] auto create_instance() -> vk::UniqueInstance
+{
+    constexpr static vk::ApplicationInfo application_info{
+        .apiVersion = VK_API_VERSION_1_1
+    };
+
+    const vk::InstanceCreateInfo create_info{
+        .pApplicationInfo    = &application_info,
+        .enabledLayerCount   = static_cast<uint32_t>(g_layers.size()),
+        .ppEnabledLayerNames = g_layers.data(),
+    };
+
+    return vk::createInstanceUnique(create_info);
+}
+
+[[nodiscard]] auto choose_physical_device(const vk::Instance t_instance)
+    -> vk::PhysicalDevice
+{
+    const auto physical_devices{ t_instance.enumeratePhysicalDevices() };
+
+    if (std::ranges::empty(physical_devices)) {
+        throw std::runtime_error{ "No Vulkan physical device is available." };
+    }
+
+    auto ranked_devices_view{
+        physical_devices
+        | std::views::transform([](vk::PhysicalDevice t_physical_device) {
+              switch (t_physical_device.getProperties().deviceType) {
+                  case vk::PhysicalDeviceType::eDiscreteGpu:
+                      return std::make_pair(t_physical_device, 2);
+                  case vk::PhysicalDeviceType::eIntegratedGpu:
+                      return std::make_pair(t_physical_device, 1);
+                  default: return std::make_pair(t_physical_device, 0);
+              }
+          })
+    };
+    std::vector ranked_devices(
+        ranked_devices_view.begin(), ranked_devices_view.end()
+    );
+
+    std::ranges::sort(
+        ranked_devices,
+        std::ranges::greater{},
+        &std::pair<vk::PhysicalDevice, int>::second
+    );
+
+    return ranked_devices.front().first;
+}
+
+[[nodiscard]] auto find_graphics_queue_family(
+    const vk::PhysicalDevice t_physical_device
+) -> uint32_t
+{
+    uint32_t index{};
+    for (const auto& properties : t_physical_device.getQueueFamilyProperties())
+    {
+        if (properties.queueFlags & vk::QueueFlagBits::eGraphics) {
+            return index;
+        }
+        index++;
+    }
+    throw std::runtime_error{ "Could not find graphics queue family" };
+}
+
+[[nodiscard]] auto create_device(const vk::PhysicalDevice t_physical_device)
+    -> vk::UniqueDevice
+{
+    const vk::DeviceQueueCreateInfo queue_create_info{
+        .queueFamilyIndex = find_graphics_queue_family(t_physical_device),
+        .queueCount       = 1,
+    };
+
+    vk::DeviceCreateInfo device_create_info{
+        .queueCreateInfoCount = 1,
+        .pQueueCreateInfos    = &queue_create_info,
+    };
+
+    return t_physical_device.createDeviceUnique(device_create_info);
+}
+
+Renderer::Renderer()
+    : m_instance{ create_instance() },
+      m_device{ create_device(choose_physical_device(*m_instance)) },
+      m_graphics_queue{ m_device->getQueue(
+          find_graphics_queue_family(choose_physical_device(*m_instance)),
+          0
+      ) }
+{}
diff --git a/src/Renderer.hpp b/src/Renderer.hpp
index 26ff61c937cae06d3ad4cdbe155f8db13c5b5b8f..e55d08541b18396db24ca39881bbed427904c890 100644
--- a/src/Renderer.hpp
+++ b/src/Renderer.hpp
@@ -8,4 +8,6 @@ public:
 
 private:
     vk::UniqueInstance m_instance;
+    vk::UniqueDevice m_device;
+    vk::Queue m_graphics_queue;
 };
diff --git a/src/main.cpp b/src/main.cpp
index f1161cf34310181e86d92e32bbcc143b1fe7906b..54e778569d47041fd567fa669db60c6230d5d6b7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,6 @@
-#include "App.hpp"
+#include <iostream>
 
 int main()
 {
-    App{}.run();
+    std::cout << "Hello World!\n";
 }