diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce1a69bb7e9309123a60d510746215045f8dfa65..4a6cb3804482f40940b9363d7ddfe4707c6da0d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,9 @@ message("> module")
 # Enable Vulkan Beta Extension needed for Vulkan Video
 add_compile_definitions(VK_ENABLE_BETA_EXTENSIONS)
 
+# Use OpenXR together with Vulkan
+add_compile_definitions(XR_USE_GRAPHICS_API_VULKAN)
+
 set(LIBLAVA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/liblava)
 set(LIBLAVA_EXT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext)
 set(LIBLAVA_RES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/res)
@@ -691,6 +694,7 @@ message("=======================================================================
             ${SRC_DIR}/headset/emulated_headset.hpp ${SRC_DIR}/headset/emulated_headset.cpp
             ${SRC_DIR}/headset/local_headset.hpp ${SRC_DIR}/headset/local_headset.cpp
             ${SRC_DIR}/headset/remote_headset.hpp ${SRC_DIR}/headset/remote_headset.cpp
+			${SRC_DIR}/headset/openxr_headset.hpp ${SRC_DIR}/headset/openxr_headset.cpp
             
             #Strategy
             ${SRC_DIR}/strategy/stereo_strategy.hpp ${SRC_DIR}/strategy/stereo_strategy.cpp
@@ -767,6 +771,7 @@ message("=======================================================================
         else ()
             target_link_libraries(${NAME} lava::app openvr_api)
         endif ()
+		target_link_libraries(${NAME} lava::app openxr_loader)
         target_link_libraries(${NAME} lava::app assimp::assimp)
         target_include_directories(${NAME} PUBLIC ${OPENVR_HEADER_DIR})
         target_link_libraries(${NAME} "${CMAKE_SOURCE_DIR}/ext/openvr/lib/win64/openvr_api.lib")
diff --git a/src/headset/headset.cpp b/src/headset/headset.cpp
index 68303cc28587b04855a34849cdea5c06d2a1908d..ac74909880009888dcfc0e6c34e0d6f0f7835804 100644
--- a/src/headset/headset.cpp
+++ b/src/headset/headset.cpp
@@ -1,6 +1,7 @@
 #include "headset.hpp"
 #include "emulated_headset.hpp"
 #include "local_headset.hpp"
+#include "openxr_headset.hpp"
 #include "remote_headset.hpp"
 
 void Headset::set_application(VRApplication* application)
@@ -45,6 +46,9 @@ Headset::Ptr make_headset(VRApplication* application, HeadsetType headset_type)
     case HEADSET_TYPE_LOCAL:
         headset = std::make_shared<LocalHeadset>();
         break;
+    case HEADSET_TYPE_OPENXR:
+        headset = std::make_shared<OpenXRHeadset>();
+        break;
     case HEADSET_TYPE_REMOTE:
         headset = std::make_shared<RemoteHeadset>();
         break;
diff --git a/src/headset/headset.hpp b/src/headset/headset.hpp
index 0c4825fd50c324c0c79f75caf9a7aac79a617585..3da65076a14ed1bbc977d8f6e0b0f9a66522cc53 100644
--- a/src/headset/headset.hpp
+++ b/src/headset/headset.hpp
@@ -33,6 +33,7 @@ enum HeadsetType
 {
     HEADSET_TYPE_EMULATED,
     HEADSET_TYPE_LOCAL,
+    HEADSET_TYPE_OPENXR,
     HEADSET_TYPE_REMOTE
 };
 
diff --git a/src/headset/openxr_headset.cpp b/src/headset/openxr_headset.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..52da5f19b7cf0c076ebafc543cb197cbbb09c671
--- /dev/null
+++ b/src/headset/openxr_headset.cpp
@@ -0,0 +1,674 @@
+#include "openxr_headset.hpp"
+#include "vr_application.hpp"
+
+#include <iostream>
+#include <vector>
+#include <array>
+
+PFN_xrGetVulkanGraphicsRequirementsKHR xrGetVulkanGraphicsRequirementsKHR = nullptr;
+PFN_xrGetVulkanInstanceExtensionsKHR xrGetVulkanInstanceExtensionsKHR = nullptr;
+PFN_xrGetVulkanDeviceExtensionsKHR xrGetVulkanDeviceExtensionsKHR = nullptr;
+PFN_xrGetVulkanGraphicsDeviceKHR xrGetVulkanGraphicsDeviceKHR = nullptr;
+
+bool OpenXRHeadset::on_setup_instance(lava::frame_config& config)
+{
+    std::vector<const char*> required_layers =
+    {
+
+    };
+
+    std::vector<const char*> required_extensions =
+    {
+        XR_KHR_VULKAN_ENABLE_EXTENSION_NAME
+    };
+
+    if (!this->check_layer_support(required_layers))
+    {
+        return false;
+    }
+    
+    if (!this->check_extension_support(required_extensions))
+    {
+        return false;
+    }
+
+    XrApplicationInfo application_info;
+    strncpy(application_info.applicationName, config.info.app_name, XR_MAX_APPLICATION_NAME_SIZE);
+    application_info.applicationVersion = XR_MAKE_VERSION(config.info.app_version.major, config.info.app_version.minor, config.info.app_version.patch);
+    strncpy(application_info.engineName, config.info.engine_name, XR_MAX_ENGINE_NAME_SIZE);
+    application_info.engineVersion = XR_MAKE_VERSION(config.info.engine_version.major, config.info.engine_version.minor, config.info.engine_version.patch);
+    application_info.apiVersion = XR_CURRENT_API_VERSION;
+    
+    XrInstanceCreateInfo create_info;
+    create_info.type = XR_TYPE_INSTANCE_CREATE_INFO;
+    create_info.next = nullptr;
+    create_info.createFlags = 0;
+    create_info.applicationInfo = application_info;
+    create_info.enabledApiLayerCount = required_layers.size();
+    create_info.enabledApiLayerNames = required_layers.data();
+    create_info.enabledExtensionCount = required_extensions.size();
+    create_info.enabledExtensionNames = required_extensions.data();
+
+    if (!this->check_result(xrCreateInstance(&create_info, &this->instance)))
+    {
+        return false;
+    }
+
+    XrSystemGetInfo get_info;
+    get_info.type = XR_TYPE_SYSTEM_GET_INFO;
+    get_info.next = nullptr;
+    get_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
+
+    if (!this->check_result(xrGetSystem(this->instance, &get_info, &this->system)))
+    {
+        return false;
+    }
+
+    if (!this->check_result(xrGetInstanceProcAddr(this->instance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&xrGetVulkanGraphicsRequirementsKHR)))
+    {
+        return false;
+    }
+
+    if (!this->check_result(xrGetInstanceProcAddr(this->instance, "xrGetVulkanInstanceExtensionsKHR", (PFN_xrVoidFunction*)&xrGetVulkanInstanceExtensionsKHR)))
+    {
+        return false;
+    }
+
+    if (!this->check_result(xrGetInstanceProcAddr(this->instance, "xrGetVulkanDeviceExtensionsKHR", (PFN_xrVoidFunction*)&xrGetVulkanDeviceExtensionsKHR)))
+    {
+        return false;
+    }
+
+    if (!this->check_result(xrGetInstanceProcAddr(this->instance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&xrGetVulkanGraphicsDeviceKHR)))
+    {
+        return false;
+    }
+   
+    XrGraphicsRequirementsVulkanKHR requirements;
+    memset(&requirements, 0, sizeof(requirements));
+    requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR;
+
+    if(!this->check_result(xrGetVulkanGraphicsRequirementsKHR(this->instance, this->system, &requirements))) 
+    {
+        return false;
+    }
+
+    uint32_t extension_count = 0;
+    if (!this->check_result(xrGetVulkanInstanceExtensionsKHR(this->instance, this->system, 0, &extension_count, nullptr)))
+    {
+        return false;
+    }
+
+    std::string extension_string(extension_count, '\0');
+    if (!this->check_result(xrGetVulkanInstanceExtensionsKHR(this->instance, this->system, extension_count, &extension_count, extension_string.data())))
+    {
+        return false;
+    }
+
+    this->instance_extensions = OpenXRHeadset::split_string(extension_string);
+
+    for (const std::string& extension : this->instance_extensions)
+    {
+        config.param.extensions.push_back(extension.c_str());
+    }
+
+    switch (XR_VERSION_MINOR(requirements.maxApiVersionSupported))
+    {
+    case 0:
+        config.info.req_api_version = lava::api_version::v1_0;
+        break;
+    case 1:
+        config.info.req_api_version = lava::api_version::v1_1;
+        break;
+    case 2:
+        config.info.req_api_version = lava::api_version::v1_2;
+        break;
+    default:
+        lava::log()->error("OpenXR: Unkown Vulkan version!");
+        return false;
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::on_setup_device(lava::device::create_param& parameters)
+{
+    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
+    if(!this->check_result(xrGetVulkanGraphicsDeviceKHR(this->instance, this->system, this->get_application()->get_instance().get(), &physical_device)))
+    {
+        if (physical_device != parameters.physical_device->get())
+        {
+            lava::log()->error("OpenXR: Incorrect physical device selected!");
+
+            return false;
+        }
+    }
+
+    uint32_t extension_count = 0;
+    if (!this->check_result(xrGetVulkanDeviceExtensionsKHR(this->instance, this->system, 0, &extension_count, nullptr)))
+    {
+        return false;
+    }
+
+    std::string extension_string(extension_count, '\0');
+    if (!this->check_result(xrGetVulkanDeviceExtensionsKHR(this->instance, this->system, extension_count, &extension_count, extension_string.data())))
+    {
+        return false;
+    }
+
+    this->device_extensions = OpenXRHeadset::split_string(extension_string);
+    
+    for (const std::string& extension : this->device_extensions)
+    {
+        parameters.extensions.push_back(extension.c_str());
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::on_create()
+{
+    XrGraphicsBindingVulkanKHR vulkan_info;
+    vulkan_info.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR;
+    vulkan_info.next = nullptr;
+    vulkan_info.instance = this->get_application()->get_instance().get();
+    vulkan_info.physicalDevice = this->get_application()->get_device()->get_physical_device()->get();
+    vulkan_info.device = this->get_application()->get_device()->get();
+    vulkan_info.queueFamilyIndex = this->get_application()->get_device()->get_graphics_queue().family;
+    vulkan_info.queueIndex = 0;
+
+    XrSessionCreateInfo create_info;
+    create_info.type = XR_TYPE_SESSION_CREATE_INFO;
+    create_info.next = &vulkan_info;
+    create_info.createFlags = 0;
+    create_info.systemId = this->system;
+
+    if(!this->check_result(xrCreateSession(this->instance, &create_info, &this->session)))
+    {
+        return false;
+    }
+
+    XrReferenceSpaceCreateInfo space_info;
+    space_info.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
+    space_info.next = nullptr;
+    space_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
+    memset(&space_info.poseInReferenceSpace, 0, sizeof(space_info.poseInReferenceSpace)); //TODO: The Quaternion is invalid!!
+ 
+    if(!this->check_result(xrCreateReferenceSpace(this->session, &space_info, &this->space)))
+    {
+        return false;
+    }
+
+    if (!this->check_swapchain_format_support(this->get_format()))
+    {
+        return false;
+    }
+
+    if (!this->check_view_type_support(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO))
+    {
+        return false;
+    }
+
+    if (!this->check_blend_mode_support(XR_ENVIRONMENT_BLEND_MODE_OPAQUE))
+    {
+        return false;
+    }
+
+    if (!this->create_framebuffers())
+    {
+        return false;
+    }
+
+    return true;
+}
+
+void OpenXRHeadset::on_destroy()
+{
+    //TODO: .......
+}
+
+bool OpenXRHeadset::on_interface()
+{
+    return false;
+}
+
+bool OpenXRHeadset::on_update(lava::delta delta_time)
+{
+    if (!this->poll_events())
+    {
+        return false;
+    }
+
+    if (this->active)
+    {
+        XrFrameWaitInfo wait_info;
+        wait_info.type = XR_TYPE_FRAME_WAIT_INFO;
+        wait_info.next = nullptr;
+
+        XrFrameState frame_state;
+        memset(&frame_state, 0, sizeof(frame_state));
+        frame_state.type = XR_TYPE_FRAME_STATE;
+
+        if(!this->check_result(xrWaitFrame(this->session, &wait_info, &frame_state)))
+        {
+            return false;
+        }
+
+        //TODO..... Begin Frame
+        //TODO..... Setup View and Projection Matrix
+    }
+
+    return false;
+}
+
+void OpenXRHeadset::submit_frame(VkCommandBuffer command_buffer, VkImageLayout frame_layout, FrameId frame_id)
+{
+    //TODO.... End Frame
+}
+
+VkFormat OpenXRHeadset::get_format() const
+{
+    return VK_FORMAT_R8G8B8A8_SRGB;
+}
+
+const glm::uvec2& OpenXRHeadset::get_resolution() const
+{
+    return this->resolution;
+}
+
+const glm::mat4& OpenXRHeadset::get_view_matrix() const
+{
+    return this->view_matrix;
+}
+
+const glm::mat4& OpenXRHeadset::get_head_to_eye_matrix(Eye eye) const
+{
+    return this->head_to_eye_matrices[eye];
+}
+
+const glm::mat4& OpenXRHeadset::get_projection_matrix(Eye eye) const
+{
+    return this->projection_matrices[eye];
+}
+
+lava::image::ptr OpenXRHeadset::get_framebuffer(FrameId frame_id) const
+{
+    return this->framebuffers[frame_id][this->framebuffer_index];
+}
+
+const char* OpenXRHeadset::get_name() const
+{
+    return "OpenXR Headset";
+}
+
+bool OpenXRHeadset::create_framebuffers()
+{
+    uint32_t view_count = 0;
+    if (!this->check_result(xrEnumerateViewConfigurationViews(this->instance, this->system, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &view_count, nullptr)))
+    {
+        return false;
+    }
+
+    if (view_count != 2)
+    {
+        lava::log()->error("OpenXR: Invalid number of views!");
+
+        return false;
+    }
+
+    XrViewConfigurationView view_template;
+    memset(&view_template, 0, sizeof(view_template));
+    view_template.type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
+
+    std::vector<XrViewConfigurationView> view_list(view_count, view_template);
+    if (!this->check_result(xrEnumerateViewConfigurationViews(this->instance, this->system, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, view_count, &view_count, view_list.data())))
+    {
+        return false;
+    }
+
+    this->resolution.x = view_list[0].recommendedImageRectWidth;
+    this->resolution.y = view_list[0].recommendedImageRectHeight;
+    uint32_t sample_count = view_list[0].recommendedSwapchainSampleCount;
+
+    for (uint32_t index = 0; index < view_count; index++)
+    {
+        XrSwapchainCreateInfo create_info;
+        create_info.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
+        create_info.next = nullptr;
+        create_info.createFlags = XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;
+        create_info.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT | XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT | XR_SWAPCHAIN_USAGE_SAMPLED_BIT;
+        create_info.format = this->get_format();
+        create_info.sampleCount = sample_count;
+        create_info.width = this->resolution.x;
+        create_info.height = this->resolution.y;
+        create_info.faceCount = 1;
+        create_info.arraySize = 1;
+        create_info.mipCount = 1;
+
+        XrSwapchain swapchain = XR_NULL_HANDLE;
+
+        if (!this->check_result(xrCreateSwapchain(this->session, &create_info, &swapchain)))
+        {
+            return false;
+        }
+
+        uint32_t image_count = 0;
+        if (!this->check_result(xrEnumerateSwapchainImages(swapchain, 0, &image_count, nullptr)))
+        {
+            return false;
+        }
+
+        XrSwapchainImageVulkanKHR image_template;
+        memset(&image_template, 0, sizeof(image_template));
+        image_template.type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
+
+        std::vector<XrSwapchainImageVulkanKHR> image_list(image_count, image_template);
+        if (!this->check_result(xrEnumerateSwapchainImages(swapchain, image_count, &image_count, (XrSwapchainImageBaseHeader*)image_list.data())))
+        {
+            return false;
+        }
+
+        for (XrSwapchainImageVulkanKHR swapchain_image : image_list)
+        {
+            this->framebuffers[index].push_back(lava::make_image(this->get_format(), swapchain_image.image));
+        }
+
+        this->swapchains.push_back(swapchain);
+    }
+
+    return true;
+}
+
+void OpenXRHeadset::destroy_framebuffers()
+{
+    //TODO: .....
+}
+
+bool OpenXRHeadset::poll_events()
+{
+    while (true)
+    {
+        XrEventDataBuffer event;
+        memset(&event, 0, sizeof(event));
+        event.type = XR_TYPE_EVENT_DATA_BUFFER;
+
+        XrResult result = xrPollEvent(this->instance, &event);
+
+        if (result == XR_EVENT_UNAVAILABLE)
+        {
+            break;
+        }
+
+        if (this->check_result(result))
+        {
+            if (!this->process_event(event))
+            {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::process_event(const XrEventDataBuffer& event)
+{
+    switch (event.type)
+    {
+    case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
+        {
+            const XrEventDataSessionStateChanged* state_change = (const XrEventDataSessionStateChanged*)&event;
+
+            switch (state_change->state)
+            {
+            case XR_SESSION_STATE_READY:
+                {
+                    XrSessionBeginInfo begin_info;
+                    begin_info.type = XR_TYPE_SESSION_BEGIN_INFO;
+                    begin_info.next = nullptr;
+                    begin_info.primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
+
+                    if (!this->check_result(xrBeginSession(this->session, &begin_info)))
+                    {
+                        return false;
+                    }
+
+                    this->active = true;
+            
+                    break;
+                }
+            case XR_SESSION_STATE_STOPPING:
+                if (!this->check_result(xrEndSession(this->session)))
+                {
+                    return false;
+                }
+
+                this->active = false;
+                break;
+            case XR_SESSION_STATE_EXITING:
+            case XR_SESSION_LOSS_PENDING:
+                return false;
+            default:
+                break;
+            }
+
+            break;
+        }
+    case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
+        return false;
+    default:
+        break;
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::check_result(XrResult result) const
+{
+    if (result != XR_SUCCESS)
+    {
+        if (this->instance != XR_NULL_HANDLE)
+        {
+            std::array<char, XR_MAX_RESULT_STRING_SIZE> result_string;
+            xrResultToString(this->instance, result, result_string.data());        
+            
+            lava::log()->error("OpenXR: Error '{}' detected!", result_string.data());
+        }
+
+        else
+        {
+            std::cout << "OpenXR: Error detected!" << std::endl;
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::check_layer_support(const std::vector<const char*>& required_layers) const
+{
+    uint32_t layer_count = 0;
+    if (!this->check_result(xrEnumerateApiLayerProperties(0, &layer_count, nullptr)))
+    {
+        return false;
+    }
+
+    XrApiLayerProperties layer_template;
+    memset(&layer_template, 0, sizeof(layer_template));
+    layer_template.type = XR_TYPE_API_LAYER_PROPERTIES;
+
+    std::vector<XrApiLayerProperties> layer_list(layer_count, layer_template);
+    if (!this->check_result(xrEnumerateApiLayerProperties(layer_count, &layer_count, layer_list.data())))
+    {
+        return false;
+    }
+
+    for (const char* required_layer : required_layers)
+    {
+        bool found = false;
+
+        for (const XrApiLayerProperties& layer : layer_list)
+        {
+            if (strcmp(required_layer, layer.layerName) == 0)
+            {
+                found = true;
+
+                break;
+            }
+        }
+
+        if (!found)
+        {
+            lava::log()->error("OpenXR: Required layer '{}' not supported!", required_layer);
+
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::check_extension_support(const std::vector<const char*>& required_extensions) const
+{
+    uint32_t extension_count = 0;
+    if(!this->check_result(xrEnumerateInstanceExtensionProperties(nullptr, 0, &extension_count, nullptr)))
+    {
+        return false;
+    }
+
+    XrExtensionProperties extension_template;
+    memset(&extension_template, 0, sizeof(extension_template));
+    extension_template.type = XR_TYPE_EXTENSION_PROPERTIES;
+
+    std::vector<XrExtensionProperties> extension_list(extension_count, extension_template);
+    if(!this->check_result(xrEnumerateInstanceExtensionProperties(nullptr, extension_count, &extension_count, extension_list.data())))
+    {
+        return false;
+    }
+
+    for (const char* required_extension : required_extensions)
+    {
+        bool found = false;
+
+        for (const XrExtensionProperties& extension : extension_list)
+        {
+            if (strcmp(required_extension, extension.extensionName) == 0)
+            {
+                found = true;
+
+                break;
+            }
+        }
+
+        if (!found)
+        {
+            lava::log()->error("OpenXR: Required extension '{}' not supported!", required_extension);
+
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::check_blend_mode_support(XrEnvironmentBlendMode required_mode) const
+{
+    uint32_t mode_count = 0;
+    if (!this->check_result(xrEnumerateEnvironmentBlendModes(this->instance, this->system, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &mode_count, nullptr)))
+    {
+        return false;
+    }
+
+    std::vector<XrEnvironmentBlendMode> mode_list(mode_count, (XrEnvironmentBlendMode)0);
+    if (!this->check_result(xrEnumerateEnvironmentBlendModes(this->instance, this->system, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, mode_count, &mode_count, mode_list.data())))
+    {
+        return false;
+    }
+
+    for (XrEnvironmentBlendMode mode : mode_list)
+    {
+        if (mode == required_mode)
+        {
+            return true;
+        }
+    }
+
+    lava::log()->error("OpenXR: The system does not support the required blend mode!");
+
+    return false;
+}
+
+bool OpenXRHeadset::check_view_type_support(XrViewConfigurationType required_type) const
+{
+    uint32_t view_type_count = 0;
+    if(!this->check_result(xrEnumerateViewConfigurations(this->instance, this->system, 0, &view_type_count, nullptr)))
+    {
+        return false;
+    }
+
+    std::vector<XrViewConfigurationType> view_type_list(view_type_count, (XrViewConfigurationType)0);
+    if (!this->check_result(xrEnumerateViewConfigurations(this->instance, this->system, view_type_count, &view_type_count, view_type_list.data())))
+    {
+        return false;
+    }
+
+    for (XrViewConfigurationType view_type : view_type_list)
+    {
+        if (view_type == required_type)
+        {
+            return true;
+        }
+    }
+
+    lava::log()->error("OpenXR: The system does not support the required view type!");
+
+    return false;
+}
+
+bool OpenXRHeadset::check_swapchain_format_support(int64_t required_format) const
+{
+    uint32_t format_count = 0;
+    if(!this->check_result(xrEnumerateSwapchainFormats(this->session, 0, &format_count, nullptr)))
+    {
+        return false;
+    }
+
+    std::vector<int64_t> format_list(format_count, 0);
+    if (!this->check_result(xrEnumerateSwapchainFormats(this->session, format_count, &format_count, format_list.data())))
+    {
+        return false;
+    }
+
+    for (int64_t format : format_list)
+    {
+        if (format == required_format)
+        {
+            return true;
+        }
+    }
+
+    lava::log()->error("OpenXR: The system does not support the required swapchain format!");
+
+    return false;
+}
+
+std::vector<std::string> OpenXRHeadset::split_string(std::string string, char delimiter)
+{
+    std::vector<std::string> strings;
+
+    while (true)
+    {
+        size_t next_occurence = string.find(delimiter);
+        strings.emplace_back(string.substr(0, next_occurence));
+
+        if (next_occurence == std::string::npos)
+        {
+            break;
+        }
+
+        string = string.substr(next_occurence + 1);
+    }
+
+    return strings;
+}
\ No newline at end of file
diff --git a/src/headset/openxr_headset.hpp b/src/headset/openxr_headset.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..efd0c14ef68c8448b03cf1fc1f6a286d4de4a5e4
--- /dev/null
+++ b/src/headset/openxr_headset.hpp
@@ -0,0 +1,74 @@
+#pragma once
+#include <liblava/lava.hpp>
+#include <glm/glm.hpp>
+#include <openxr/openxr.h>
+#include <openxr/openxr_platform.h>
+#include <memory>
+
+#include "headset.hpp"
+
+class OpenXRHeadset : public Headset
+{
+public:
+    typedef std::shared_ptr<OpenXRHeadset> Ptr;
+
+public:
+    OpenXRHeadset() = default;
+
+    bool on_setup_instance(lava::frame_config& config) override;
+    bool on_setup_device(lava::device::create_param& parameters) override;
+
+    bool on_create() override;
+    void on_destroy() override;
+
+    bool on_interface() override;
+    bool on_update(lava::delta delta_time) override;
+
+    void submit_frame(VkCommandBuffer command_buffer, VkImageLayout frame_layout, FrameId frame_id) override;
+
+    VkFormat get_format() const override;
+    const glm::uvec2& get_resolution() const override;
+    const glm::mat4& get_view_matrix() const override;
+    const glm::mat4& get_head_to_eye_matrix(Eye eye) const override;
+    const glm::mat4& get_projection_matrix(Eye eye) const override;
+
+    lava::image::ptr get_framebuffer(FrameId frame_id) const override;
+
+    const char* get_name() const override;
+
+private:
+    bool create_framebuffers();
+    void destroy_framebuffers();
+
+    bool poll_events();
+    bool process_event(const XrEventDataBuffer& event);
+
+    bool check_result(XrResult result) const;
+    bool check_layer_support(const std::vector<const char*>& required_layers) const;
+    bool check_extension_support(const std::vector<const char*>& required_extensions) const;
+    bool check_blend_mode_support(XrEnvironmentBlendMode required_mode) const;
+    bool check_view_type_support(XrViewConfigurationType required_type) const;
+    bool check_swapchain_format_support(int64_t required_format) const;
+
+    static std::vector<std::string> split_string(std::string string, char delimiter = ' ');
+
+private:
+    XrInstance instance = XR_NULL_HANDLE;
+    XrSystemId system = XR_NULL_SYSTEM_ID;
+    XrSession session = XR_NULL_HANDLE;
+    XrSpace space = XR_NULL_HANDLE;
+    std::vector<XrSwapchain> swapchains;
+
+    bool active = false;
+
+    std::vector<std::string> instance_extensions;
+    std::vector<std::string> device_extensions;
+
+    glm::uvec2 resolution;
+    glm::mat4 view_matrix;
+    std::array<glm::mat4, 2> head_to_eye_matrices;
+    std::array<glm::mat4, 2> projection_matrices;
+
+    std::array<std::vector<lava::image::ptr>, 2> framebuffers;
+    uint32_t framebuffer_index = 0;
+};
\ No newline at end of file
diff --git a/src/utility/command_parser.cpp b/src/utility/command_parser.cpp
index 2d5c46816086e73662538cb4c3dc9b010fb5c63c..9cf0d69753c90973bb5ababbaa48aba244bf0cfb 100644
--- a/src/utility/command_parser.cpp
+++ b/src/utility/command_parser.cpp
@@ -246,7 +246,7 @@ void CommandParser::show_help()
     std::cout << "   --benchmark                          Play animation once and close program after completion." << std::endl;
     std::cout << "                                        If not set, the application runs indefinitely and the interface is enabled." << std::endl;
     std::cout << "   --headset={headset}                  The headset that should be used." << std::endl;
-    std::cout << "                                        Options: emulated (default), local, remote" << std::endl;
+    std::cout << "                                        Options: emulated (default), local, openxr, remote" << std::endl;
     std::cout << "   --stereo-strategy={strategy}         The stereo strategy that should be used." << std::endl;
     std::cout << "                                        Options: native_forward (default), native_deferred, dpr" << std::endl;
     std::cout << "   --animation={animation_name}         The name of the animation that should be played." << std::endl;
@@ -278,6 +278,11 @@ bool CommandParser::set_headset(const std::string& name)
         this->headset = HEADSET_TYPE_LOCAL;
     }
 
+    else if (name == "openxr")
+    {
+        this->headset = HEADSET_TYPE_OPENXR;
+    }
+
     else if (name == "remote")
     {
         this->headset = HEADSET_TYPE_REMOTE;