diff --git a/conanfile.py b/conanfile.py
index 550e2e251f56223e7aa58ef3dd65019070df498f..8b074ea48bfe90284c9dd7a660005b0bd7e82d28 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -24,7 +24,7 @@ from conans import ConanFile, CMake
 
 class ProjectPhoenix(ConanFile):
     name = "phx"
-    version = "18.01.0"
+    version = "18.02.0"
     license = "3-Clause BSD License"
     description = """Project Phoenix"""
     settings = "os", "compiler", "build_type", "arch"
diff --git a/demos/viewer/src/navigation_behavior.cpp b/demos/viewer/src/navigation_behavior.cpp
index 71d6a2e2b04a717693d9a5f77e4068480e1ea39e..1dd78c59f213a0a2c67cc4830b821d8d0dee89f7 100644
--- a/demos/viewer/src/navigation_behavior.cpp
+++ b/demos/viewer/src/navigation_behavior.cpp
@@ -28,7 +28,7 @@
 #include "glm/glm.hpp"
 #include "glm/gtc/matrix_access.hpp"
 
-#include "phx/display_system.hpp"
+#include "phx/display_system_openvr.hpp"
 #include "phx/engine.hpp"
 #include "phx/entity.hpp"
 #include "phx/hmd.hpp"
@@ -37,13 +37,16 @@
 
 void NavigationBehavior::OnUpdate() {
   // If there exists an HMD and a transform.
-  const auto hmd = GetEntity()
-                       ->GetScene()
-                       ->GetEngine()
-                       ->GetSystem<phx::DisplaySystem>()
-                       ->GetHMD();
+  const auto display_system_hmd = GetEntity()
+                                      ->GetScene()
+                                      ->GetEngine()
+                                      ->GetSystem<phx::DisplaySystemOpenVR>();
+  phx::HMD* hmd = nullptr;
+  if (display_system_hmd != nullptr) {
+    hmd = display_system_hmd->GetHMD();
+  }
   const auto transform = GetEntity()->GetFirstComponent<phx::Transform>();
-  if (!hmd || !transform) return;
+  if (hmd == nullptr || transform == nullptr) return;
 
   auto indices = hmd->GetControllerIndices();
 
diff --git a/demos/viewer/src/viewer.cpp b/demos/viewer/src/viewer.cpp
index 3992fcfa5c26a70c3a7b140ff2d333e5823236a0..bb293a384a638272b18eca2dd3b178a20fd135c8 100644
--- a/demos/viewer/src/viewer.cpp
+++ b/demos/viewer/src/viewer.cpp
@@ -28,7 +28,7 @@
 #include <vector>
 
 #include "phx/assimp_model_loader.hpp"
-#include "phx/display_system.hpp"
+#include "phx/display_system_window.hpp"
 #include "phx/engine.hpp"
 #include "phx/entity.hpp"
 #include "phx/input_system.hpp"
@@ -42,6 +42,7 @@
 #include "phx/rendering_system.hpp"
 #include "phx/resource_declaration.hpp"
 #include "phx/resource_manager.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 #include "phx/runtime_component.hpp"
 #include "phx/scene.hpp"
@@ -51,63 +52,20 @@
 #include "phx/transform.hpp"
 #include "phx/window.hpp"
 
-#include "controller_behavior.hpp"
 #include "navigation_behavior.hpp"
+#include "phx/display_system_openvr.hpp"
 #include "rotation_behavior.hpp"
 #include "viewer_system.hpp"
 
-void AddControllerEntity(const std::shared_ptr<phx::Scene>& scene,
-                         phx::ResourceProxy* mesh_proxy,
-                         phx::ResourceProxy* material_proxy,
-                         ControllerBehavior::Side side) {
-  phx::Entity* controller = scene->CreateEntity();
-  controller->AddComponent<phx::MeshHandle>()->SetMeshProxy(mesh_proxy);
-  controller->AddComponent<phx::Transform>();
-  controller->AddComponent<phx::MaterialHandle>()->SetMaterialProxy(
-      material_proxy);
-  controller->AddComponent<ControllerBehavior>()->SetSide(side);
-}
-
-void AddController(const std::shared_ptr<phx::Scene>& scene,
-                   ControllerBehavior::Side side) {
-  auto& resource_manager = phx::ResourceManager::instance();
-
-  phx::ResourceDeclaration mesh_declaration{
-      {"TYPE", "openVR"},
-      {"OpenVR_type", "mesh"},
-      {"side", (side == ControllerBehavior::RIGHT ? "right" : "left")}};
-  auto mesh_proxy =
-      phx::ResourceManager::instance().DeclareResource(mesh_declaration);
-  mesh_proxy->Load();
-
-  phx::ResourceDeclaration material_declaration{{"TYPE", "openVR"},
-                                                {"OpenVR_type", "material"}};
-  auto material_proxy = resource_manager.DeclareResource(material_declaration);
-  material_proxy->Load();
-
-  if (mesh_proxy->GetAs<phx::Mesh>() != nullptr) {
-    AddControllerEntity(scene, mesh_proxy, material_proxy, side);
-  }
-}
-
-void SetupOpenVRController(const std::shared_ptr<phx::Scene>& scene,
-                           phx::HMD* hmd) {
-  auto& resource_manager = phx::ResourceManager::instance();
-  auto openvr_loader = std::make_unique<phx::OpenVRResourceLoader>(hmd);
-  resource_manager.RegisterResourceType("openVR", std::move(openvr_loader));
-
-  AddController(scene, ControllerBehavior::RIGHT);
-  AddController(scene, ControllerBehavior::LEFT);
-}
-
 int main(int, char**) {
   std::unique_ptr<phx::Engine> engine = phx::Setup::CreateDefaultEngine();
   auto scene = engine->GetScene();
 
   phx::SplashScreen splash(
-      engine->GetSystem<phx::DisplaySystem>()->GetWindow());
+      engine->GetSystem<phx::DisplaySystemWindow>()->GetWindow());
   splash.Draw();
-  auto assimp_loader = std::make_unique<phx::AssimpModelLoader>();
+  auto assimp_loader = static_cast<phx::AssimpModelLoader*>(
+      phx::ResourceManager::instance().GetLoaderForType(".obj"));
   assimp_loader->SetProgressUpdateCallback([&splash](float progress) {
     splash.SetLoadProgress(progress);
     splash.Draw();
@@ -122,11 +80,6 @@ int main(int, char**) {
       viewer_system->SetShowFramerate(!viewer_system->GetShowFramerate());
   });
 
-  auto hmd = engine->GetSystem<phx::DisplaySystem>()->GetHMD();
-  if (hmd != nullptr) {
-    SetupOpenVRController(scene, hmd);
-  }
-
   phx::SceneLoader::InsertModelIntoScene(
       "models/UniversityScene/Univers20171013.obj", scene.get());
 
@@ -157,7 +110,7 @@ int main(int, char**) {
               phx::RuntimeComponent<phx::USER_PLATFORM>>()[0]
           ->GetFirstComponent<phx::Transform>();
 
-  virtual_platform_transform->SetLocalTranslation(glm::vec3(0, 1.0, 5.0));
+  virtual_platform_transform->SetLocalTranslation(glm::vec3(0.f, -1.f, -2.f));
 
   phx::Entity* camera = scene->CreateEntity();
   auto camera_transform = camera->AddComponent<phx::Transform>();
diff --git a/library/phx/assimp_model_loader.cpp b/library/phx/assimp_model_loader.cpp
index 74b525a957e21d6fe4b506c98c4381d90d0a0284..0882122dfde8d46b32060ef1211600f9feed06e1 100644
--- a/library/phx/assimp_model_loader.cpp
+++ b/library/phx/assimp_model_loader.cpp
@@ -77,13 +77,13 @@ std::unique_ptr<phx::Resource> AssimpModelLoader::Load(
   auto resource = std::make_unique<phx::Model>();
 
   for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
-    auto material_proxy = phx::ResourceUtils::LoadResourceFromFile(
+    auto material_proxy = phx::ResourceUtils::LoadResourceFromFile<Material>(
         file_name, {{"material_index", i}}, true);
     resource->AddMaterial(material_proxy);
   }
 
   for (unsigned int i = 0; i < scene->mNumMeshes; i++) {
-    auto mesh_proxy = phx::ResourceUtils::LoadResourceFromFile(
+    auto mesh_proxy = phx::ResourceUtils::LoadResourceFromFile<Mesh>(
         file_name, {{"mesh_index", i}}, true);
     resource->AddMesh(mesh_proxy);
     if (last_material_index_ != -1) {
@@ -147,19 +147,19 @@ std::unique_ptr<phx::Material> AssimpModelLoader::LoadSingleMaterial(
   aiString relative_path;
   if (AI_SUCCESS ==
       material->GetTexture(aiTextureType_AMBIENT, 0, &relative_path)) {
-    auto image_proxy = ResourceUtils::LoadResourceFromFile(
+    auto image_proxy = ResourceUtils::LoadResourceFromFile<Image>(
         filepath + "/" + std::string(relative_path.C_Str()), {}, true);
     resource->SetAmbientImage(image_proxy);
   }
   if (AI_SUCCESS ==
       material->GetTexture(aiTextureType_DIFFUSE, 0, &relative_path)) {
-    auto image_proxy = ResourceUtils::LoadResourceFromFile(
+    auto image_proxy = ResourceUtils::LoadResourceFromFile<Image>(
         filepath + "/" + std::string(relative_path.C_Str()), {}, true);
     resource->SetDiffuseImage(image_proxy);
   }
   if (AI_SUCCESS ==
       material->GetTexture(aiTextureType_SPECULAR, 0, &relative_path)) {
-    auto image_proxy = ResourceUtils::LoadResourceFromFile(
+    auto image_proxy = ResourceUtils::LoadResourceFromFile<Image>(
         filepath + "/" + std::string(relative_path.C_Str()), {}, true);
     resource->SetSpecularImage(image_proxy);
   }
diff --git a/library/phx/behavior.hpp b/library/phx/behavior.hpp
index 6de30dc82b4f860f979f65f876cde355fc36b3cb..4ec2fa75798671f089d942c469464825e45b9f2d 100644
--- a/library/phx/behavior.hpp
+++ b/library/phx/behavior.hpp
@@ -37,7 +37,7 @@ class PHOENIX_EXPORT Behavior : public Component {
   friend BehaviorSystem;
 
  public:
-  virtual void OnUpdate() {}
+  virtual void OnUpdate() = 0;
 
   std::string ToString() const override;
 
diff --git a/library/phx/component.hpp b/library/phx/component.hpp
index e47c01d7e4a963200db8780b6e2fdf8c84498280..ccd93f7d9c0e91371bd88a8a26a4df46e33e9f02 100644
--- a/library/phx/component.hpp
+++ b/library/phx/component.hpp
@@ -34,19 +34,21 @@ namespace phx {
 class Entity;
 
 class PHOENIX_EXPORT Component : public Loggable {
-  friend class Entity;
-
  public:
+  // Entity should be the only one to construct Components
+  // has to be befriended to all derived Components, since friendship is not
+  // inheritable
+  friend class Entity;
   virtual ~Component() = default;
 
   Entity* GetEntity() const;
 
  protected:
   Component() = default;
-  Component(const Component&) = default;
+  Component(const Component&) = delete;
   Component(Component&&) = default;
 
-  Component& operator=(const Component&) = default;
+  Component& operator=(const Component&) = delete;
   Component& operator=(Component&&) = default;
 
  private:
diff --git a/library/phx/display_system.cpp b/library/phx/display_system.cpp
index 80e7a9a440e1c3f81bed4cc6c627909598397af1..675f964211c9f8d7d852aa198436487b267a04ae 100644
--- a/library/phx/display_system.cpp
+++ b/library/phx/display_system.cpp
@@ -22,72 +22,8 @@
 
 #include "display_system.hpp"
 
-#include <algorithm>
-#include <memory>
-#include <stdexcept>
-#include <string>
-#include <vector>
-
-#include "SDL2/SDL_video.h"
-
-#include "logger.hpp"
-#include "rendering_system.hpp"
-
-#undef CreateWindow
-
 namespace phx {
-DisplaySystem::DisplaySystem(Engine* engine) : System(engine) {
-  if (SDL_VideoInit(nullptr) != 0)
-    throw std::runtime_error(
-        "Unable to initialize SDL video subsystem. Error: " +
-        std::string(SDL_GetError()));
-}
-DisplaySystem::~DisplaySystem() { SDL_VideoQuit(); }
-
-void DisplaySystem::DestroyWindow() {
-  window_.reset();
-  /*windows_.erase(
-      std::remove_if(windows_.begin(), windows_.end(),
-                     [window](const std::unique_ptr<Window>& iteratee) {
-                       return window == iteratee.get();
-                     }));*/
-}
-
-Window* DisplaySystem::GetWindow() {
-  /*std::vector<Window*> windows(windows_.size());
-  std::transform(
-      windows_.begin(), windows_.end(), windows.begin(),
-      [](const std::unique_ptr<Window>& iteratee) { return iteratee.get(); });*/
-  return window_.get();
-}
-
-phx::HMD* DisplaySystem::CreateHMD() {
-  if (hmd_ == nullptr) {
-    hmd_ = std::make_unique<HMD>();
-    CreateWindow("Phoenix HMD Companion", glm::uvec2(10, 10),
-                 hmd_->GetViewportSize());
-  } else {
-    warn("[DisplaySystem] HMD already created, so far only one is supported.");
-  }
-  return hmd_.get();
-}
-
-void DisplaySystem::DestroyHMD() { hmd_.reset(); }
-
-phx::HMD* DisplaySystem::GetHMD() { return hmd_.get(); }
+DisplaySystem::DisplaySystem(Engine* engine) : System(engine) {}
+DisplaySystem::~DisplaySystem() {}
 
-void DisplaySystem::Update(const FrameTimer::TimeInfo&) {
-  if (window_ != nullptr) {
-    window_->Swap();
-  }
-  if (hmd_ != nullptr) {
-    auto rendering_system = engine_->GetSystem<RenderingSystem>();
-    auto left_texture =
-        rendering_system->GetLeftRenderTarget()->GetColorTexture();
-    hmd_->Submit(HMD::LEFT_EYE, left_texture);
-    auto right_texture =
-        rendering_system->GetRightRenderTarget()->GetColorTexture();
-    hmd_->Submit(HMD::RIGHT_EYE, right_texture);
-  }
-}
 }  // namespace phx
diff --git a/library/phx/display_system.hpp b/library/phx/display_system.hpp
index ffcc68492dda98db366bf20f8bf9cd684590e1e8..98b84f3ceb0a433000582e059730885a7e00bb47 100644
--- a/library/phx/display_system.hpp
+++ b/library/phx/display_system.hpp
@@ -28,11 +28,8 @@
 
 #include "phx/engine.hpp"
 #include "phx/export.hpp"
-#include "phx/hmd.hpp"
+#include "phx/render_target.hpp"
 #include "phx/system.hpp"
-#include "phx/window.hpp"
-
-#undef CreateWindow
 
 namespace phx {
 
@@ -45,31 +42,15 @@ class PHOENIX_EXPORT DisplaySystem : public System {
   DisplaySystem& operator=(const DisplaySystem&) = delete;
   DisplaySystem& operator=(DisplaySystem&&) = default;
 
-  template <typename... Arguments>
-  Window* CreateWindow(Arguments&&... arguments);
-  void DestroyWindow();
-  Window* GetWindow();
-
-  HMD* CreateHMD();
-  void DestroyHMD();
-  HMD* GetHMD();
+  void Update(const FrameTimer::TimeInfo&) override = 0;
 
-  void Update(const FrameTimer::TimeInfo&) override;
+  virtual std::vector<std::unique_ptr<RenderTarget>> CreateRenderTargets() = 0;
 
  protected:
   explicit DisplaySystem(Engine* engine);
   friend DisplaySystem* Engine::CreateSystem<DisplaySystem>();
-
-  std::unique_ptr<Window> window_;
-  std::unique_ptr<HMD> hmd_;
 };
 
-template <typename... Arguments>
-Window* DisplaySystem::CreateWindow(Arguments&&... arguments) {
-  // Do not use make_unique due to the friendship to Window.
-  window_ = std::unique_ptr<Window>(new Window(arguments...));
-  return window_.get();
-}
 }  // namespace phx
 
 #endif  // LIBRARY_PHX_DISPLAY_SYSTEM_HPP_
diff --git a/library/phx/display_system_openvr.cpp b/library/phx/display_system_openvr.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..909eeb69c0334a2bfac89ab77c0e68c70baaf526
--- /dev/null
+++ b/library/phx/display_system_openvr.cpp
@@ -0,0 +1,87 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include "display_system_openvr.hpp"
+
+#include <algorithm>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "logger.hpp"
+#include "rendering_system.hpp"
+
+#undef CreateWindow
+
+namespace phx {
+DisplaySystemOpenVR::DisplaySystemOpenVR(Engine* engine)
+    : DisplaySystem(engine) {}
+DisplaySystemOpenVR::~DisplaySystemOpenVR() {}
+
+phx::HMD* DisplaySystemOpenVR::CreateHMD() {
+  if (hmd_ == nullptr) {
+    hmd_ = std::make_unique<HMD>();
+  } else {
+    warn(
+        "[DisplaySystemOpenVR] HMD already created, so far only one is "
+        "supported.");
+  }
+  return hmd_.get();
+}
+
+void DisplaySystemOpenVR::DestroyHMD() { hmd_.reset(); }
+
+phx::HMD* DisplaySystemOpenVR::GetHMD() { return hmd_.get(); }
+
+void DisplaySystemOpenVR::Update(const FrameTimer::TimeInfo&) {
+  if (hmd_ != nullptr) {
+    auto rendering_system = engine_->GetSystem<RenderingSystem>();
+    if (rendering_system != nullptr) {
+      auto render_targets = rendering_system->GetRenderTargets();
+      if (render_targets.size() >= 2) {
+        auto right_texture = render_targets[0]->GetColorTexture();
+        hmd_->Submit(HMD::RIGHT_EYE, right_texture);
+        auto left_texture = render_targets[1]->GetColorTexture();
+        hmd_->Submit(HMD::LEFT_EYE, left_texture);
+      }
+    }
+  }
+}
+
+std::vector<std::unique_ptr<RenderTarget>>
+DisplaySystemOpenVR::CreateRenderTargets() {
+  std::vector<std::unique_ptr<RenderTarget>> render_targets;
+  if (GetHMD() == nullptr) {
+    error("Cannot create render targets: no HMD.");
+    return std::move(render_targets);
+  }
+
+  render_targets.push_back(
+      std::make_unique<RenderTarget>(GetHMD()->GetViewportSize()));
+  render_targets.push_back(
+      std::make_unique<RenderTarget>(GetHMD()->GetViewportSize()));
+  return std::move(render_targets);
+}
+
+}  // namespace phx
diff --git a/library/phx/display_system_openvr.hpp b/library/phx/display_system_openvr.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e0962cc327aa78984354bc48b5630f078723cbb
--- /dev/null
+++ b/library/phx/display_system_openvr.hpp
@@ -0,0 +1,60 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#ifndef LIBRARY_PHX_DISPLAY_SYSTEM_OPENVR_HPP_
+#define LIBRARY_PHX_DISPLAY_SYSTEM_OPENVR_HPP_
+
+#include <memory>
+#include <vector>
+
+#include "phx/display_system.hpp"
+#include "phx/export.hpp"
+#include "phx/hmd.hpp"
+#include "phx/window.hpp"
+
+namespace phx {
+
+class PHOENIX_EXPORT DisplaySystemOpenVR : public DisplaySystem {
+ public:
+  explicit DisplaySystemOpenVR(Engine* engine);
+  DisplaySystemOpenVR(const DisplaySystemOpenVR&) = delete;
+  DisplaySystemOpenVR(DisplaySystemOpenVR&&) = default;
+  ~DisplaySystemOpenVR();
+
+  DisplaySystemOpenVR& operator=(const DisplaySystemOpenVR&) = delete;
+  DisplaySystemOpenVR& operator=(DisplaySystemOpenVR&&) = default;
+
+  HMD* CreateHMD();
+  void DestroyHMD();
+  HMD* GetHMD();
+
+  void Update(const FrameTimer::TimeInfo&) override;
+
+  std::vector<std::unique_ptr<RenderTarget>> CreateRenderTargets() override;
+
+ protected:
+  std::unique_ptr<HMD> hmd_;
+};
+
+}  // namespace phx
+
+#endif  // LIBRARY_PHX_DISPLAY_SYSTEM_OPENVR_HPP_
diff --git a/library/phx/display_system_window.cpp b/library/phx/display_system_window.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f87978aa75274c4396227f799d406b573a68773
--- /dev/null
+++ b/library/phx/display_system_window.cpp
@@ -0,0 +1,85 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include "display_system_window.hpp"
+
+#include <algorithm>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "SDL2/SDL_video.h"
+
+#include "logger.hpp"
+#include "rendering_system.hpp"
+
+#undef CreateWindow
+
+namespace phx {
+DisplaySystemWindow::DisplaySystemWindow(Engine* engine)
+    : DisplaySystem(engine) {
+  if (SDL_VideoInit(nullptr) != 0)
+    throw std::runtime_error(
+        "Unable to initialize SDL video subsystem. Error: " +
+        std::string(SDL_GetError()));
+}
+DisplaySystemWindow::~DisplaySystemWindow() { SDL_VideoQuit(); }
+
+void DisplaySystemWindow::DestroyWindow() {
+  window_.reset();
+  /*windows_.erase(
+      std::remove_if(windows_.begin(), windows_.end(),
+                     [window](const std::unique_ptr<Window>& iteratee) {
+                       return window == iteratee.get();
+                     }));*/
+}
+
+Window* DisplaySystemWindow::GetWindow() {
+  /*std::vector<Window*> windows(windows_.size());
+  std::transform(
+      windows_.begin(), windows_.end(), windows.begin(),
+      [](const std::unique_ptr<Window>& iteratee) { return iteratee.get(); });*/
+  return window_.get();
+}
+
+void DisplaySystemWindow::Update(const FrameTimer::TimeInfo&) {
+  if (window_ != nullptr) {
+    window_->Swap();
+  }
+}
+
+std::vector<std::unique_ptr<RenderTarget>>
+DisplaySystemWindow::CreateRenderTargets() {
+  std::vector<std::unique_ptr<RenderTarget>> render_targets;
+  if (GetWindow() == nullptr) {
+    error("Cannot create render target: no window.");
+    return std::move(render_targets);
+  }
+
+  render_targets.push_back(
+      std::make_unique<RenderTarget>(GetWindow()->GetSize()));
+  return std::move(render_targets);
+}
+
+}  // namespace phx
diff --git a/library/phx/display_system_window.hpp b/library/phx/display_system_window.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8abfcee03022c9af1d00355b788690bfbf9ffd55
--- /dev/null
+++ b/library/phx/display_system_window.hpp
@@ -0,0 +1,69 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#ifndef LIBRARY_PHX_DISPLAY_SYSTEM_WINDOW_HPP_
+#define LIBRARY_PHX_DISPLAY_SYSTEM_WINDOW_HPP_
+
+#include <memory>
+#include <vector>
+
+#include "phx/display_system.hpp"
+#include "phx/export.hpp"
+#include "phx/render_target.hpp"
+#include "phx/window.hpp"
+
+#undef CreateWindow
+
+namespace phx {
+
+class PHOENIX_EXPORT DisplaySystemWindow : public DisplaySystem {
+ public:
+  explicit DisplaySystemWindow(Engine* engine);
+  DisplaySystemWindow(const DisplaySystemWindow&) = delete;
+  DisplaySystemWindow(DisplaySystemWindow&&) = default;
+  ~DisplaySystemWindow();
+
+  DisplaySystemWindow& operator=(const DisplaySystemWindow&) = delete;
+  DisplaySystemWindow& operator=(DisplaySystemWindow&&) = default;
+
+  template <typename... Arguments>
+  Window* CreateWindow(Arguments&&... arguments);
+  void DestroyWindow();
+  Window* GetWindow();
+
+  void Update(const FrameTimer::TimeInfo&) override;
+
+  std::vector<std::unique_ptr<RenderTarget>> CreateRenderTargets() override;
+
+ protected:
+  std::unique_ptr<Window> window_;
+};
+
+template <typename... Arguments>
+Window* DisplaySystemWindow::CreateWindow(Arguments&&... arguments) {
+  // Do not use make_unique due to the friendship to Window.
+  window_ = std::unique_ptr<Window>(new Window(arguments...));
+  return window_.get();
+}
+}  // namespace phx
+
+#endif  // LIBRARY_PHX_DISPLAY_SYSTEM_WINDOW_HPP_
diff --git a/library/phx/engine.cpp b/library/phx/engine.cpp
index 315ac6ae015c0562bb1c78c3a0461c275943469b..cf624f5649bf511076bd400694a41354051da84e 100644
--- a/library/phx/engine.cpp
+++ b/library/phx/engine.cpp
@@ -25,6 +25,7 @@
 #include <iostream>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "phx/logger.hpp"
@@ -90,9 +91,75 @@ void Engine::SetScene(const std::shared_ptr<Scene>& new_scene) {
   if (scene_ != nullptr) {
     scene_->engine_ = nullptr;
   }
+  scene_changed_signal_(scene_, new_scene);
   // attach to new scene
   scene_ = new_scene;
   scene_->engine_ = this;
 }
 
+boost::signals2::connection Engine::AddSceneChangedCallback(
+    const std::function<void(std::shared_ptr<Scene>, std::shared_ptr<Scene>)>&
+        callback) {
+  return scene_changed_signal_.connect(callback);
+}
+
+void Engine::UpdateOrder::MoveToFront(System* system) const {
+  auto it = FindSystem(system);
+  if (it == engine_->systems_.end()) {
+    error("Cannot move system to front of update order: system not found");
+    return;
+  }
+  auto system_temp = std::move(*it);
+  engine_->systems_.erase(it);
+  engine_->systems_.insert(engine_->systems_.begin(), std::move(system_temp));
+}
+
+void Engine::UpdateOrder::MoveToBack(System* system) const {
+  auto it = FindSystem(system);
+  if (it == engine_->systems_.end()) {
+    error("Cannot move system to back of update order: system not found");
+    return;
+  }
+  auto system_temp = std::move(*it);
+  engine_->systems_.erase(it);
+  engine_->systems_.insert(engine_->systems_.end(), std::move(system_temp));
+}
+
+void Engine::UpdateOrder::MoveAfter(System* system, System* after) const {
+  MoveBeforeRelative(system, after, 1);
+}
+
+void Engine::UpdateOrder::MoveBefore(System* system, System* before) const {
+  MoveBeforeRelative(system, before, 0);
+}
+
+std::vector<std::unique_ptr<phx::System>>::iterator
+Engine::UpdateOrder::FindSystem(System* system) const {
+  auto find_func = [system](const std::unique_ptr<System>& sys) {
+    return sys.get() == system;
+  };
+  return std::find_if(engine_->systems_.begin(), engine_->systems_.end(),
+                      find_func);
+}
+
+void Engine::UpdateOrder::MoveBeforeRelative(System* system,
+                                             System* relative_to,
+                                             int distance) const {
+  if (system == relative_to) return;
+  auto it_sys = FindSystem(system);
+  if (it_sys == engine_->systems_.end()) {
+    error("Cannot change update order: system not found");
+    return;
+  }
+  if (FindSystem(relative_to) == engine_->systems_.end()) {
+    error("Cannot change update order: target system not found");
+    return;
+  }
+  auto system_temp = std::move(*it_sys);
+  engine_->systems_.erase(it_sys);
+  auto it_target = FindSystem(relative_to);
+  it_target += distance;
+  engine_->systems_.insert(it_target, std::move(system_temp));
+}
+
 }  // namespace phx
diff --git a/library/phx/engine.hpp b/library/phx/engine.hpp
index 481afbe06eac5f947da28688362e5256427d1ad5..99898cfeb8760fa6665d5a385b1001e6cd658bea 100644
--- a/library/phx/engine.hpp
+++ b/library/phx/engine.hpp
@@ -32,6 +32,12 @@
 #include <utility>
 #include <vector>
 
+SUPPRESS_WARNINGS_BEGIN
+#define BOOST_BIND_NO_PLACEHOLDERS
+#include "boost/signals2/connection.hpp"
+#include "boost/signals2/signal.hpp"
+SUPPRESS_WARNINGS_END
+
 #include "phx/behavior.hpp"
 #include "phx/export.hpp"
 #include "phx/frame_timer.hpp"
@@ -56,7 +62,7 @@ class PHOENIX_EXPORT Engine final : public Loggable {
   template <typename SystemType, typename... SystemArguments>
   SystemType* CreateSystem(SystemArguments&&... arguments) {
     static_assert(std::is_base_of<System, SystemType>::value,
-                  "The type does not inherit from system.");
+                  "The type does not inherit from System.");
     auto system =
         std::unique_ptr<SystemType>(new SystemType(this, arguments...));
     systems_.push_back(std::move(system));
@@ -65,7 +71,7 @@ class PHOENIX_EXPORT Engine final : public Loggable {
   template <typename SystemType>
   SystemType* GetSystem() {
     static_assert(std::is_base_of<System, SystemType>::value,
-                  "The type does not inherit from system.");
+                  "The type does not inherit from System.");
     auto iterator = std::find_if(systems_.begin(), systems_.end(),
                                  SystemMatchPredicate<SystemType>);
     return iterator != systems_.end()
@@ -73,9 +79,22 @@ class PHOENIX_EXPORT Engine final : public Loggable {
                : nullptr;
   }
   template <typename SystemType>
+  std::vector<SystemType*> GetSystems() {
+    static_assert(std::is_base_of<System, SystemType>::value,
+                  "The type does not inherit from System.");
+
+    std::vector<SystemType*> systems;
+    for (const auto& system : systems_) {
+      if (SystemMatchPredicate<SystemType>(system)) {
+        systems.push_back(static_cast<SystemType*>(system.get()));
+      }
+    }
+    return systems;
+  }
+  template <typename SystemType>
   void RemoveSystem() {
     static_assert(std::is_base_of<System, SystemType>::value,
-                  "The type does not inherit from system.");
+                  "The type does not inherit from System.");
     systems_.erase(std::remove_if(systems_.begin(), systems_.end(),
                                   SystemMatchPredicate<SystemType>),
                    systems_.end());
@@ -89,6 +108,10 @@ class PHOENIX_EXPORT Engine final : public Loggable {
 
   void SetScene(const std::shared_ptr<Scene>& new_scene);
   std::shared_ptr<Scene> GetScene() const;
+  // Parameters to the callback are: (old scene, new scene)
+  boost::signals2::connection AddSceneChangedCallback(
+      const std::function<void(std::shared_ptr<Scene>, std::shared_ptr<Scene>)>&
+          callback);
 
   const FrameTimer& GetFrameTimer();
 
@@ -101,11 +124,29 @@ class PHOENIX_EXPORT Engine final : public Loggable {
   template <typename... Components>
   std::vector<std::tuple<Components*...>> GetFirstComponentsMany() const;
 
+  // Update order
+  class UpdateOrder {
+   public:
+    explicit UpdateOrder(Engine* engine) : engine_(engine) {}
+    void MoveToFront(System* system) const;
+    void MoveToBack(System* system) const;
+    void MoveAfter(System* system, System* after) const;
+    void MoveBefore(System* system, System* before) const;
+
+   private:
+    std::vector<std::unique_ptr<System>>::iterator FindSystem(
+        System* system) const;
+    void MoveBeforeRelative(System* system, System* relative_to,
+                            int distance) const;
+    Engine* engine_;
+  };
+
+  const UpdateOrder& GetUpdateOrder() const { return update_order_; }
+
  private:
   template <typename SystemType>
   static bool SystemMatchPredicate(const std::unique_ptr<System>& iteratee) {
-    const auto& system = *iteratee.get();
-    return typeid(SystemType) == typeid(system);
+    return (dynamic_cast<SystemType*>(iteratee.get()) != nullptr);
   }
 
   void UpdateSystems();
@@ -114,8 +155,11 @@ class PHOENIX_EXPORT Engine final : public Loggable {
   bool is_running_ = false;
 
   std::shared_ptr<Scene> scene_;
+  boost::signals2::signal<void(std::shared_ptr<Scene>, std::shared_ptr<Scene>)>
+      scene_changed_signal_;
 
   FrameTimer frame_timer_;
+  UpdateOrder update_order_ = UpdateOrder(this);
 };
 
 template <typename... Components>
diff --git a/library/phx/entity.hpp b/library/phx/entity.hpp
index 5cfb7e533d5d953c71c8091b4f21a2cac8611194..d902b8da6cb494ecfaa9f8ec218508f0bce5d6ca 100644
--- a/library/phx/entity.hpp
+++ b/library/phx/entity.hpp
@@ -56,8 +56,8 @@ class PHOENIX_EXPORT Entity : public Nameable, public Loggable {
   ComponentType* AddComponent() {
     static_assert(std::is_base_of<phx::Component, ComponentType>::value,
                   "ComponentType is not derived from phx::Component.");
-    components_.push_back(std::make_unique<ComponentType>());
-    auto component_ptr = static_cast<ComponentType*>(components_.back().get());
+    auto component_ptr = new ComponentType();
+    components_.push_back(std::unique_ptr<ComponentType>(component_ptr));
     component_ptr->entity_ = this;
     return component_ptr;
   }
diff --git a/library/phx/frame_graph.hpp b/library/phx/frame_graph.hpp
index c8d83a8051172fa58c06d15a8007674787927977..09079b5ead43296d5791c92d895756d114840e10 100644
--- a/library/phx/frame_graph.hpp
+++ b/library/phx/frame_graph.hpp
@@ -26,6 +26,7 @@
 #include <list>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "phx/export.hpp"
 #include "phx/render_pass.hpp"
@@ -47,10 +48,27 @@ class PHOENIX_EXPORT FrameGraph {
   std::size_t GetNumberOfPasses();
   RenderPass* AddRenderPass(std::unique_ptr<RenderPass> render_pass);
 
+  template <typename RenderPassType>
+  std::vector<RenderPassType*> GetRenderPasses() const;
+
  private:
   std::list<std::unique_ptr<RenderPass>> render_passes_;
 };
 
+template <typename RenderPassType>
+std::vector<RenderPassType*> phx::FrameGraph::GetRenderPasses() const {
+  static_assert(std::is_base_of<RenderPass, RenderPassType>::value,
+                "The type does not inherit from RenderPass.");
+  std::vector<RenderPassType*> render_passes;
+  for (const auto& render_pass : render_passes_) {
+    auto pass_pointer = dynamic_cast<RenderPassType*>(render_pass.get());
+    if (pass_pointer != nullptr) {
+      render_passes.push_back(pass_pointer);
+    }
+  }
+  return render_passes;
+}
+
 }  // namespace phx
 
 #endif  // LIBRARY_PHX_FRAME_GRAPH_HPP_
diff --git a/library/phx/geometry_pass.cpp b/library/phx/geometry_pass.cpp
index 01fd54e7d25011d18f4b237252237df445adcdf3..3f464d4bb203e979cdc723b8ea6c2c8ed4ff78b7 100644
--- a/library/phx/geometry_pass.cpp
+++ b/library/phx/geometry_pass.cpp
@@ -38,6 +38,7 @@
 #include "phx/resource_proxy.hpp"
 #include "phx/resource_utils.hpp"
 #include "phx/transform.hpp"
+#include "phx/shader_source.hpp"
 
 namespace phx {
 
@@ -139,15 +140,15 @@ void GeometryPass::Initialize() {
 }
 
 void GeometryPass::SetUpShaders() {
-  auto vertex_shader_proxy =
-      ResourceUtils::LoadResourceFromFile("shader/phong.vert");
-  auto fragment_shader_proxy =
-      ResourceUtils::LoadResourceFromFile("shader/phong.frag");
+  auto vertex_shader =
+      ResourceUtils::LoadResourceFromFile<ShaderSource>("shader/phong.vert");
+  auto fragment_shader =
+      ResourceUtils::LoadResourceFromFile<ShaderSource>("shader/phong.frag");
 
   shader_program_ = std::make_unique<ShaderProgram>();
-  shader_program_->SetShaderProxy(ShaderProgram::VERTEX, vertex_shader_proxy);
-  shader_program_->SetShaderProxy(ShaderProgram::FRAGMENT,
-                                  fragment_shader_proxy);
+  shader_program_->SetShader(ShaderProgram::VERTEX, vertex_shader);
+  shader_program_->SetShader(ShaderProgram::FRAGMENT,
+                                  fragment_shader);
   shader_program_->Link();
 }
 
diff --git a/library/phx/hmd.cpp b/library/phx/hmd.cpp
index 847f58f078f0aa03293d97fbd52729f2e387b6ba..4f8c5d3e7edd18133fe39a504e9924a9548f1e20 100644
--- a/library/phx/hmd.cpp
+++ b/library/phx/hmd.cpp
@@ -39,6 +39,7 @@ SUPPRESS_WARNINGS_END
 #include "gl/texture.hpp"
 #include "phx/logger.hpp"
 #include "phx/resource_manager.hpp"
+#include "phx/resource_pointer.hpp"
 
 namespace phx {
 HMD::HMD() {
@@ -79,6 +80,11 @@ std::vector<vr::TrackedDeviceIndex_t> HMD::GetControllerIndices() {
   return std::move(indices);
 }
 
+vr::ETrackedControllerRole HMD::GetControllerRoleForTrackedDeviceIndex(
+    vr::TrackedDeviceIndex_t device_index) const {
+  return vr_system_->GetControllerRoleForTrackedDeviceIndex(device_index);
+}
+
 const glm::uvec2& HMD::GetViewportSize() const { return viewport_size_; }
 
 const glm::mat4& HMD::GetProjectionMatrix(Side side) const {
@@ -136,7 +142,9 @@ glm::mat4 HMD::GetRightControllerTransformation() {
 
 std::unique_ptr<phx::Mesh> HMD::GetControllerMesh(Controller controller) {
   auto model = GetControllerModel(controller);
-  if (model == nullptr) return nullptr;
+  if (model == nullptr) {
+    return nullptr;
+  }
   auto mesh = std::make_unique<phx::Mesh>();
   std::vector<glm::vec3> vertices;
   std::vector<glm::vec3> normals;
@@ -176,7 +184,7 @@ vr::RenderModel_t* HMD::GetControllerModel(Controller controller) {
     }
   }
 
-  vr::RenderModel_t* model;
+  vr::RenderModel_t* model = nullptr;
   while (vr::VRRenderModels()->LoadRenderModel_Async(
              &rendermodel_name[0], &model) == vr::VRRenderModelError_Loading) {
     std::this_thread::sleep_for(std::chrono::milliseconds(50));
@@ -203,7 +211,7 @@ std::unique_ptr<Material> HMD::GetControllerMaterial(Controller controller) {
        {"side",
         controller == HMD::Controller::LEFT_CONTROLLER ? "left" : "right"}});
   texture_proxy->Load();
-  material->SetDiffuseImage(texture_proxy);
+  material->SetDiffuseImage(ResourcePointer<Image>(texture_proxy));
 
   return material;
 }
@@ -224,9 +232,9 @@ std::unique_ptr<Image> HMD::GetControllerTexture(int id) {
             texture_map->rubTextureMapData + image_data.size(),
             image_data.begin());
   auto image = std::make_unique<phx::Image>(
-      image_data, std::array<std::size_t, 2>{
+      &image_data[0], std::array<std::size_t, 2>{
                       {static_cast<std::size_t>(texture_map->unWidth),
-                       static_cast<std::size_t>(texture_map->unHeight)}});
+                       static_cast<std::size_t>(texture_map->unHeight)}}, 32);
 
   return image;
 }
diff --git a/library/phx/hmd.hpp b/library/phx/hmd.hpp
index a3e0b7cfb165fc91f4e9622a6261cf803889fd59..82bedf2cfaf9e305a32b7126ec7415fd6635d45b 100644
--- a/library/phx/hmd.hpp
+++ b/library/phx/hmd.hpp
@@ -78,6 +78,8 @@ class PHOENIX_EXPORT HMD {
   void Submit(Side side, gl::texture_2d* texture);
 
   std::vector<vr::TrackedDeviceIndex_t> GetControllerIndices();
+  vr::ETrackedControllerRole GetControllerRoleForTrackedDeviceIndex(
+      vr::TrackedDeviceIndex_t device_index) const;
 
  private:
   glm::mat4 GetTransformationForRole(vr::ETrackedControllerRole role);
diff --git a/library/phx/image.hpp b/library/phx/image.hpp
index 5f686d332ed717a515565219c031645531368082..b9ccc8bcf7a0cb9f6cec1b2c406a9a6f15f1f941 100644
--- a/library/phx/image.hpp
+++ b/library/phx/image.hpp
@@ -71,7 +71,8 @@ class PHOENIX_EXPORT Image : public Resource, public Loggable {
         static_cast<std::int32_t>(dimensions[1]),
         static_cast<std::int32_t>((bits_per_pixel * dimensions[0] + 31) / 32 *
                                   4),
-        static_cast<std::int32_t>(bits_per_pixel), 0, 0, 0, false);
+        static_cast<std::int32_t>(bits_per_pixel), FI_RGBA_RED_MASK,
+        FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, false);
     if (!native_) {
       throw std::runtime_error("FreeImage_ConvertFromRawBitsEx failed.");
     }
diff --git a/library/phx/light.hpp b/library/phx/light.hpp
index 5a11219010eca50a2698680a66c4e5b9cbb8f4b3..53e590f1ef6303c9cb3bf79d7c1d3ccbd0adffd6 100644
--- a/library/phx/light.hpp
+++ b/library/phx/light.hpp
@@ -36,7 +36,7 @@ namespace phx {
 
 SUPPRESS_WARNINGS_BEGIN_PADDED
 
-class PHOENIX_EXPORT Light : public Component {
+class PHOENIX_EXPORT Light final : public Component {
  public:
   enum class Type {
     kPoint,
@@ -61,6 +61,15 @@ class PHOENIX_EXPORT Light : public Component {
 
   std::string ToString() const override;
 
+ protected:
+  friend Entity;
+  Light() = default;
+  Light(const Light&) = delete;
+  Light(Light&&) = default;
+
+  Light& operator=(const Light&) = delete;
+  Light& operator=(Light&&) = default;
+
  private:
   Type type_ = Type::kDirectional;
   glm::vec3 color_ = glm::vec3(1.0f, 1.0f, 1.0f);
diff --git a/library/phx/material.cpp b/library/phx/material.cpp
index 63810ec40e612451032117ef1a52c8ce57faa7c8..59f16c5abedb7d7e765abf358b97a6c1a8b71545 100644
--- a/library/phx/material.cpp
+++ b/library/phx/material.cpp
@@ -32,38 +32,48 @@ namespace phx {
 glm::vec3 Material::GetDiffuseColor() const { return diffuse_color_; }
 void Material::SetDiffuseColor(glm::vec3 color) { diffuse_color_ = color; }
 
-ResourceProxy* Material::GetDiffuseImage() const { return diffuse_image_; }
-void Material::SetDiffuseImage(ResourceProxy* image) { diffuse_image_ = image; }
+ResourcePointer<Image> Material::GetDiffuseImage() const {
+  return diffuse_image_;
+}
+void Material::SetDiffuseImage(ResourcePointer<Image> image) {
+  diffuse_image_ = image;
+}
 
 gl::texture_2d* Material::GetDiffuseTexture() {
   if (diffuse_image_ && !diffuse_texture_)
-    SetTexture(diffuse_image_->GetAs<phx::Image>(), &diffuse_texture_);
+    SetTexture(diffuse_image_, &diffuse_texture_);
   return diffuse_texture_.get();
 }
 
 glm::vec3 Material::GetAmbientColor() const { return ambient_color_; }
 void Material::SetAmbientColor(glm::vec3 color) { ambient_color_ = color; }
 
-ResourceProxy* Material::GetAmbientImage() const { return ambient_image_; }
-void Material::SetAmbientImage(ResourceProxy* image) { ambient_image_ = image; }
+ResourcePointer<Image> Material::GetAmbientImage() const {
+  return ambient_image_;
+}
+void Material::SetAmbientImage(ResourcePointer<Image> image) {
+  ambient_image_ = image;
+}
 
 gl::texture_2d* Material::GetAmbientTexture() {
   if (ambient_image_ && !ambient_texture_)
-    SetTexture(ambient_image_->GetAs<phx::Image>(), &ambient_texture_);
+    SetTexture(ambient_image_, &ambient_texture_);
   return ambient_texture_.get();
 }
 
 glm::vec3 Material::GetSpecularColor() const { return specular_color_; }
 void Material::SetSpecularColor(glm::vec3 color) { specular_color_ = color; }
 
-ResourceProxy* Material::GetSpecularImage() const { return specular_image_; }
-void Material::SetSpecularImage(ResourceProxy* image) {
+ResourcePointer<Image> Material::GetSpecularImage() const {
+  return specular_image_;
+}
+void Material::SetSpecularImage(ResourcePointer<Image> image) {
   specular_image_ = image;
 }
 
 gl::texture_2d* Material::GetSpecularTexture() {
   if (specular_image_ && !specular_texture_)
-    SetTexture(specular_image_->GetAs<phx::Image>(), &specular_texture_);
+    SetTexture(specular_image_, &specular_texture_);
   return specular_texture_.get();
 }
 
@@ -82,9 +92,9 @@ void Material::SetShininess(float shininess) {
 const std::string& Material::GetName() const { return name_; }
 void Material::SetName(const std::string& name) { name_ = name; }
 
-void Material::SetTexture(Image* image,
+void Material::SetTexture(ResourcePointer<Image> image,
                           std::shared_ptr<gl::texture_2d>* texture) {
-  if (!image) return;
+  if (!image.GetProxy()->IsOnline()) return;
   if (*texture && (*texture)->is_valid()) {
     gl::texture_handle handle(*texture->get());
     handle.set_resident(false);
diff --git a/library/phx/material.hpp b/library/phx/material.hpp
index 4a51fff148501d114972656629bd1439ff76dea3..3de50a4d1f860ba3292faef1aa29e6d9178c7ae8 100644
--- a/library/phx/material.hpp
+++ b/library/phx/material.hpp
@@ -36,6 +36,7 @@ SUPPRESS_WARNINGS_END
 #include "phx/export.hpp"
 #include "phx/image.hpp"
 #include "phx/resource.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 
 namespace phx {
@@ -46,24 +47,24 @@ class PHOENIX_EXPORT Material : public Resource {
   glm::vec3 GetDiffuseColor() const;
   void SetDiffuseColor(glm::vec3 color);
 
-  ResourceProxy* GetDiffuseImage() const;
-  void SetDiffuseImage(ResourceProxy* proxy);
+  ResourcePointer<Image> GetDiffuseImage() const;
+  void SetDiffuseImage(ResourcePointer<Image> proxy);
 
   gl::texture_2d* GetDiffuseTexture();
 
   glm::vec3 GetAmbientColor() const;
   void SetAmbientColor(glm::vec3 color);
 
-  ResourceProxy* GetAmbientImage() const;
-  void SetAmbientImage(ResourceProxy* proxy);
+  ResourcePointer<Image> GetAmbientImage() const;
+  void SetAmbientImage(ResourcePointer<Image> proxy);
 
   gl::texture_2d* GetAmbientTexture();
 
   glm::vec3 GetSpecularColor() const;
   void SetSpecularColor(glm::vec3 color);
 
-  ResourceProxy* GetSpecularImage() const;
-  void SetSpecularImage(ResourceProxy* image);
+  ResourcePointer<Image> GetSpecularImage() const;
+  void SetSpecularImage(ResourcePointer<Image> image);
 
   gl::texture_2d* GetSpecularTexture();
 
@@ -74,14 +75,15 @@ class PHOENIX_EXPORT Material : public Resource {
   void SetName(const std::string& name);
 
  private:
-  void SetTexture(Image* image, std::shared_ptr<gl::texture_2d>* texture);
+  void SetTexture(ResourcePointer<Image> image,
+                  std::shared_ptr<gl::texture_2d>* texture);
 
   glm::vec3 ambient_color_ = glm::vec3(0, 0, 0);
   glm::vec3 diffuse_color_ = glm::vec3(1, 0, 0);
   glm::vec3 specular_color_ = glm::vec3(1, 1, 1);
-  ResourceProxy* ambient_image_ = nullptr;
-  ResourceProxy* diffuse_image_ = nullptr;
-  ResourceProxy* specular_image_ = nullptr;
+  ResourcePointer<Image> ambient_image_{nullptr};
+  ResourcePointer<Image> diffuse_image_{nullptr};
+  ResourcePointer<Image> specular_image_{nullptr};
   std::shared_ptr<gl::texture_2d> ambient_texture_ = nullptr;
   std::shared_ptr<gl::texture_2d> diffuse_texture_ = nullptr;
   std::shared_ptr<gl::texture_2d> specular_texture_ = nullptr;
diff --git a/library/phx/material_handle.cpp b/library/phx/material_handle.cpp
index 67059f6cac8f098c38c705ce999d22286b17fca6..ecafabb6b67ee45ee2c2fd99868b29712b00b2fd 100644
--- a/library/phx/material_handle.cpp
+++ b/library/phx/material_handle.cpp
@@ -29,16 +29,12 @@
 
 namespace phx {
 
-void MaterialHandle::SetMaterialProxy(ResourceProxy* proxy) {
-  material_proxy_ = proxy;
+void MaterialHandle::SetMaterial(ResourcePointer<Material> material) {
+  material_ = material;
 }
 
-phx::ResourceProxy* MaterialHandle::GetMaterialProxy() const {
-  return material_proxy_;
-}
-
-phx::Material* MaterialHandle::GetMaterial() const {
-  return material_proxy_->GetAs<phx::Material>();
+ResourcePointer<Material> MaterialHandle::GetMaterial() const {
+  return material_;
 }
 
 std::string MaterialHandle::ToString() const {
diff --git a/library/phx/material_handle.hpp b/library/phx/material_handle.hpp
index 5f9a71380d5941a6cef266b26d71370f2a9daa4f..0a5e866be3725faa7f3ea74678070f5fc0a449cb 100644
--- a/library/phx/material_handle.hpp
+++ b/library/phx/material_handle.hpp
@@ -34,21 +34,29 @@ SUPPRESS_WARNINGS_END
 #include "phx/export.hpp"
 #include "phx/material.hpp"
 #include "phx/nameable.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 
 namespace phx {
 
-class PHOENIX_EXPORT MaterialHandle : public Component, public Nameable {
+class PHOENIX_EXPORT MaterialHandle final : public Component, public Nameable {
  public:
-  void SetMaterialProxy(ResourceProxy* proxy);
-  ResourceProxy* GetMaterialProxy() const;
-
-  Material* GetMaterial() const;
+  void SetMaterial(ResourcePointer<Material> material);
+  ResourcePointer<Material> GetMaterial() const;
 
   std::string ToString() const override;
 
+ protected:
+  friend Entity;
+  MaterialHandle() = default;
+  MaterialHandle(const MaterialHandle&) = delete;
+  MaterialHandle(MaterialHandle&&) = default;
+
+  MaterialHandle& operator=(const MaterialHandle&) = delete;
+  MaterialHandle& operator=(MaterialHandle&&) = default;
+
  private:
-  ResourceProxy* material_proxy_ = nullptr;
+  ResourcePointer<Material> material_{nullptr};
 };
 
 }  // namespace phx
diff --git a/library/phx/mesh_handle.cpp b/library/phx/mesh_handle.cpp
index cae2c5ddd8dc8a3016d3a6159621913e2cb418e9..abaaac234aaaf3497634dc9d8c234737c96ee6b9 100644
--- a/library/phx/mesh_handle.cpp
+++ b/library/phx/mesh_handle.cpp
@@ -28,16 +28,12 @@
 
 namespace phx {
 
-void MeshHandle::SetMeshProxy(ResourceProxy* proxy) { mesh_proxy_ = proxy; }
+void MeshHandle::SetMesh(ResourcePointer<Mesh> mesh) { mesh_ = mesh; }
 
-phx::ResourceProxy* MeshHandle::GetMeshProxy() const { return mesh_proxy_; }
-
-phx::Mesh* MeshHandle::GetMesh() const {
-  return mesh_proxy_->GetAs<phx::Mesh>();
-}
+ResourcePointer<Mesh> MeshHandle::GetMesh() const { return mesh_; }
 
 std::string MeshHandle::ToString() const {
-  if (mesh_proxy_ == nullptr) return GetName() + " (MeshHandle <empty>)";
+  if (mesh_ == nullptr) return GetName() + " (MeshHandle <empty>)";
 
   auto mesh = this->GetMesh();
   return GetName() + " (MeshHandle" +
diff --git a/library/phx/mesh_handle.hpp b/library/phx/mesh_handle.hpp
index a9a01cd181bd5419810eebfdaf894e8ca6aade6d..4b83c9f87d76a5c59a5f2c93217db90f13611985 100644
--- a/library/phx/mesh_handle.hpp
+++ b/library/phx/mesh_handle.hpp
@@ -25,34 +25,37 @@
 #include <string>
 
 #include "phx/component.hpp"
+#include "phx/export.hpp"
 #include "phx/mesh.hpp"
 #include "phx/nameable.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 
 namespace phx {
 /**
  * A component holding a simple pointer to a mesh
  */
-class MeshHandle : public Component, public Nameable {
+class PHOENIX_EXPORT MeshHandle final : public Component, public Nameable {
  public:
-  MeshHandle() = default;
-  MeshHandle(const MeshHandle&) = default;
-  MeshHandle(MeshHandle&&) = default;
-  ~MeshHandle() = default;
+  virtual ~MeshHandle() = default;
 
-  MeshHandle& operator=(const MeshHandle&) = default;
-  MeshHandle& operator=(MeshHandle&&) = default;
+  void SetMesh(ResourcePointer<Mesh> mesh);
+  ResourcePointer<Mesh> GetMesh() const;
 
-  void SetMeshProxy(ResourceProxy* proxy);
-  ResourceProxy* GetMeshProxy() const;
+  std::string ToString() const override;
 
-  Mesh* GetMesh() const;
+ protected:
+  friend Entity;
+  MeshHandle() = default;
+  MeshHandle(const MeshHandle&) = delete;
+  MeshHandle(MeshHandle&&) = default;
 
-  std::string ToString() const override;
+  MeshHandle& operator=(const MeshHandle&) = delete;
+  MeshHandle& operator=(MeshHandle&&) = default;
 
  protected:
  private:
-  ResourceProxy* mesh_proxy_{nullptr};
+  ResourcePointer<Mesh> mesh_{nullptr};
 };
 }  // namespace phx
 
diff --git a/library/phx/model.cpp b/library/phx/model.cpp
index a97604037e6f72888cb786023f37c3a2b4bb0966..164b63f8b447d5e7c570d1dab35f4f0a7f3bb3ff 100644
--- a/library/phx/model.cpp
+++ b/library/phx/model.cpp
@@ -24,29 +24,35 @@
 
 #include <vector>
 
+#include "phx/material.hpp"
+
 namespace phx {
 
-const std::vector<phx::ResourceProxy*>& Model::GetMeshes() const {
+const std::vector<ResourcePointer<Mesh>>& Model::GetMeshes() const {
   return mesh_proxies_;
 }
 
-void Model::AddMesh(ResourceProxy* mesh) { mesh_proxies_.push_back(mesh); }
+void Model::AddMesh(ResourcePointer<Mesh> mesh) {
+  mesh_proxies_.push_back(mesh);
+}
 
-const std::vector<phx::ResourceProxy*>& Model::GetMaterials() const {
+const std::vector<ResourcePointer<Material>>& Model::GetMaterials() const {
   return material_proxies_;
 }
 
-void Model::AddMaterial(ResourceProxy* material) {
+void Model::AddMaterial(ResourcePointer<Material> material) {
   material_proxies_.push_back(material);
 }
 
-phx::ResourceProxy* Model::GetMaterialForMesh(ResourceProxy* mesh) const {
+ResourcePointer<Material> Model::GetMaterialForMesh(
+    ResourcePointer<Mesh> mesh) const {
   auto it = material_by_mesh_.find(mesh);
-  if (it == material_by_mesh_.end()) return nullptr;
+  if (it == material_by_mesh_.end()) return ResourcePointer<Material>(nullptr);
   return it->second;
 }
 
-void Model::SetMaterialForMesh(ResourceProxy* mesh, ResourceProxy* material) {
+void Model::SetMaterialForMesh(ResourcePointer<Mesh> mesh,
+                               ResourcePointer<Material> material) {
   material_by_mesh_[mesh] = material;
 }
 
diff --git a/library/phx/model.hpp b/library/phx/model.hpp
index 5a26f3a0befaf5d514dcbc7f9f670a0a38383a8a..16b569d9be23be17abafeca3e35a6c3e1cb3a57c 100644
--- a/library/phx/model.hpp
+++ b/library/phx/model.hpp
@@ -26,15 +26,16 @@
 #include <map>
 #include <string>
 #include <vector>
-#include "resource_proxy.hpp"
 
 SUPPRESS_WARNINGS_BEGIN
 #include "glm/glm.hpp"
 SUPPRESS_WARNINGS_END
 
 #include "phx/export.hpp"
+#include "phx/material.hpp"
 #include "phx/mesh.hpp"
 #include "phx/resource.hpp"
+#include "phx/resource_pointer.hpp"
 
 namespace phx {
 
@@ -49,19 +50,21 @@ class PHOENIX_EXPORT Model : public Resource {
   Model& operator=(const Model&) = default;
   Model& operator=(Model&&) = default;
 
-  const std::vector<phx::ResourceProxy*>& GetMeshes() const;
-  void AddMesh(ResourceProxy* mesh);
+  const std::vector<ResourcePointer<Mesh>>& GetMeshes() const;
+  void AddMesh(ResourcePointer<Mesh> mesh);
 
-  const std::vector<phx::ResourceProxy*>& GetMaterials() const;
-  void AddMaterial(ResourceProxy* material);
+  const std::vector<ResourcePointer<Material>>& GetMaterials() const;
+  void AddMaterial(ResourcePointer<Material> material);
 
-  ResourceProxy* GetMaterialForMesh(ResourceProxy* mesh) const;
-  void SetMaterialForMesh(ResourceProxy* mesh, ResourceProxy* material);
+  ResourcePointer<Material> GetMaterialForMesh(
+      ResourcePointer<Mesh> mesh) const;
+  void SetMaterialForMesh(ResourcePointer<Mesh> mesh,
+                          ResourcePointer<Material> material);
 
  private:
-  std::vector<ResourceProxy*> mesh_proxies_;
-  std::vector<ResourceProxy*> material_proxies_;
-  std::map<ResourceProxy*, ResourceProxy*> material_by_mesh_;
+  std::vector<ResourcePointer<Mesh>> mesh_proxies_;
+  std::vector<ResourcePointer<Material>> material_proxies_;
+  std::map<ResourcePointer<Mesh>, ResourcePointer<Material>> material_by_mesh_;
 };
 
 }  // namespace phx
diff --git a/library/phx/opengl_image_buffer_data.hpp b/library/phx/opengl_image_buffer_data.hpp
index f697e4468592ae0219a5d722bf51a6047dfed3b6..ec22c55097df8da5951da12b871f77c7edb5bf86 100644
--- a/library/phx/opengl_image_buffer_data.hpp
+++ b/library/phx/opengl_image_buffer_data.hpp
@@ -353,9 +353,9 @@ void phx::OpenGLImageBufferData<T>::SaveToFilePNG(
 template <typename T>
 phx::OpenGLImageBufferData<T> phx::OpenGLImageBufferData<T>::ReadFromFilePNG(
     const std::string& filename) {
-  auto img_proxy = phx::ResourceUtils::LoadResourceFromFile(filename, {}, true);
-  auto image = img_proxy->GetAs<phx::Image>();
-  auto buffer = OpenGLImageBufferData<T>::CreateFromImage(image);
+  auto image =
+      phx::ResourceUtils::LoadResourceFromFile<Image>(filename, {}, true);
+  auto buffer = OpenGLImageBufferData<T>::CreateFromImage(image.Get());
   auto* buffer_pointer = buffer.release();
   return *buffer_pointer;
 }
diff --git a/demos/viewer/src/controller_behavior.cpp b/library/phx/openvr_controller_behavior.cpp
similarity index 84%
rename from demos/viewer/src/controller_behavior.cpp
rename to library/phx/openvr_controller_behavior.cpp
index f4fc9a45a6bcdc867ff836d6a039a9039a924f09..51620fe1f74a172e3890a0207fa47f23c91a4383 100644
--- a/demos/viewer/src/controller_behavior.cpp
+++ b/library/phx/openvr_controller_behavior.cpp
@@ -20,14 +20,15 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
-#include "controller_behavior.hpp"
+#include "openvr_controller_behavior.hpp"
 
 #include "phx/entity.hpp"
 #include "phx/runtime_component.hpp"
 #include "phx/scene.hpp"
 #include "phx/transform.hpp"
 
-void ControllerBehavior::OnUpdate() {
+namespace phx {
+void OpenVRControllerBehavior::OnUpdate() {
   phx::Scene* scene = GetEntity()->GetScene();
   phx::Entity* runtime_entity = nullptr;
   if (side_ == Side::LEFT) {
@@ -48,8 +49,14 @@ void ControllerBehavior::OnUpdate() {
       !(GetEntity()->GetFirstComponent<phx::Transform>()->GetParent() ==
         runtime_entity->GetFirstComponent<phx::Transform>())) {
     GetEntity()->GetFirstComponent<phx::Transform>()->SetParent(
-        runtime_entity->GetFirstComponent<phx::Transform>());
+        runtime_entity->GetFirstComponent<phx::Transform>(), false);
   }
 }
 
-void ControllerBehavior::SetSide(Side side) { side_ = side; }
+void OpenVRControllerBehavior::SetSide(Side side) { side_ = side; }
+
+OpenVRControllerBehavior::Side OpenVRControllerBehavior::GetSide() const {
+  return side_;
+}
+
+}  // namespace phx
diff --git a/demos/viewer/src/controller_behavior.hpp b/library/phx/openvr_controller_behavior.hpp
similarity index 79%
rename from demos/viewer/src/controller_behavior.hpp
rename to library/phx/openvr_controller_behavior.hpp
index 5f6855c2736df123f19220e24df2f6ccbd571a1a..c8fb9898d17f86bb238273837acb31dcc97df088 100644
--- a/demos/viewer/src/controller_behavior.hpp
+++ b/library/phx/openvr_controller_behavior.hpp
@@ -20,21 +20,26 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
-#ifndef DEMOS_VIEWER_SRC_CONTROLLER_BEHAVIOR_HPP_
-#define DEMOS_VIEWER_SRC_CONTROLLER_BEHAVIOR_HPP_
+#ifndef LIBRARY_PHX_OPENVR_CONTROLLER_BEHAVIOR_HPP_
+#define LIBRARY_PHX_OPENVR_CONTROLLER_BEHAVIOR_HPP_
 
 #include "phx/behavior.hpp"
+#include "phx/export.hpp"
 
-class ControllerBehavior : public phx::Behavior {
+namespace phx {
+
+class PHOENIX_EXPORT OpenVRControllerBehavior : public Behavior {
  public:
   enum Side { LEFT, RIGHT };
 
   void OnUpdate() override;
 
   void SetSide(Side side);
+  Side GetSide() const;
 
  private:
   Side side_ = Side::LEFT;
 };
+}  // namespace phx
 
-#endif  // DEMOS_VIEWER_SRC_CONTROLLER_BEHAVIOR_HPP_
+#endif  // LIBRARY_PHX_OPENVR_CONTROLLER_BEHAVIOR_HPP_
diff --git a/library/phx/openvr_controller_system.cpp b/library/phx/openvr_controller_system.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..737f3be65a0201f4929455f29bf46e43456cccc9
--- /dev/null
+++ b/library/phx/openvr_controller_system.cpp
@@ -0,0 +1,146 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include "openvr_controller_system.hpp"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "display_system_openvr.hpp"
+#include "logger.hpp"
+#include "material_handle.hpp"
+#include "mesh_handle.hpp"
+#include "openvr_controller_behavior.hpp"
+#include "openvr_resource_loader.hpp"
+#include "resource_manager.hpp"
+#include "resource_pointer.hpp"
+#include "transform.hpp"
+
+namespace phx {
+
+OpenVRControllerSystem::OpenVRControllerSystem(Engine* engine,
+                                               DisplaySystem* display_system)
+    : System(engine) {
+  // find HMD
+  hmd_ = dynamic_cast<DisplaySystemOpenVR*>(display_system)->GetHMD();
+  if (hmd_ == nullptr) {
+    error("Cannot use OpenVRControllerSystem without an HMD!");
+    return;
+  }
+
+  auto& resource_manager = ResourceManager::instance();
+  auto openvr_loader = std::make_unique<OpenVRResourceLoader>(hmd_);
+  resource_manager.RegisterResourceType("openVR", std::move(openvr_loader));
+}
+
+Entity* AddControllerEntity(const std::shared_ptr<phx::Scene>& scene,
+                            ResourcePointer<Mesh> mesh,
+                            ResourcePointer<Material> material,
+                            OpenVRControllerBehavior::Side side) {
+  Entity* controller = scene->CreateEntity();
+  controller->AddComponent<MeshHandle>()->SetMesh(mesh);
+  controller->AddComponent<Transform>();
+  controller->AddComponent<MaterialHandle>()->SetMaterial(material);
+  controller->AddComponent<OpenVRControllerBehavior>()->SetSide(side);
+
+  return controller;
+}
+
+Entity* AddController(const std::shared_ptr<phx::Scene>& scene,
+                      OpenVRControllerBehavior::Side side) {
+  auto& resource_manager = ResourceManager::instance();
+  std::string side_string =
+      side == OpenVRControllerBehavior::LEFT ? "left" : "right";
+
+  ResourceDeclaration mesh_declaration{
+      {"TYPE", "openVR"}, {"OpenVR_type", "mesh"}, {"side", side_string}};
+  auto mesh_proxy =
+      ResourceManager::instance().DeclareResource(mesh_declaration);
+  mesh_proxy->Load();
+
+  ResourceDeclaration material_declaration{
+      {"TYPE", "openVR"}, {"OpenVR_type", "material"}, {"side", side_string}};
+  auto material_proxy = resource_manager.DeclareResource(material_declaration);
+  material_proxy->Load();
+
+  if (mesh_proxy->GetAs<Mesh>() != nullptr) {
+    return AddControllerEntity(scene, ResourcePointer<Mesh>(mesh_proxy),
+                               ResourcePointer<Material>(material_proxy), side);
+  }
+  return nullptr;
+}
+
+void OpenVRControllerSystem::Update(const FrameTimer::TimeInfo&) {
+  // check which controllers are active and update their scene representation,
+  // if necessary
+  if (!hmd_) return;
+  auto scene = GetEngine()->GetScene();
+  if (scene == nullptr) return;
+
+  // get controller entities in the scene
+  Entity* left_controller_entity = nullptr;
+  Entity* right_controller_entity = nullptr;
+  auto controller_entities =
+      GetEngine()->GetEntitiesWithComponents<OpenVRControllerBehavior>();
+  for (auto entity : controller_entities) {
+    if (entity->GetFirstComponent<OpenVRControllerBehavior>()->GetSide() ==
+        OpenVRControllerBehavior::LEFT) {
+      left_controller_entity = entity;
+    } else {
+      right_controller_entity = entity;
+    }
+  }
+
+  auto controller_indices = hmd_->GetControllerIndices();
+  bool left_controller_active = false;
+  bool right_controller_active = false;
+  for (auto idx : controller_indices) {
+    // is it a left controller?
+    auto role = hmd_->GetControllerRoleForTrackedDeviceIndex(idx);
+    if (role == vr::TrackedControllerRole_LeftHand) {
+      // do we have a left controller in the scene?
+      if (left_controller_entity == nullptr) {
+        // create that controller
+        left_controller_entity =
+            AddController(scene, OpenVRControllerBehavior::LEFT);
+      }
+      left_controller_active = true;
+    } else if (role == vr::TrackedControllerRole_RightHand) {
+      if (right_controller_entity == nullptr) {
+        right_controller_entity =
+            AddController(scene, OpenVRControllerBehavior::RIGHT);
+      }
+      right_controller_active = true;
+    }
+  }
+
+  // remove unnecessary entities
+  if (!left_controller_active && left_controller_entity != nullptr) {
+    scene->RemoveEntity(left_controller_entity);
+  }
+  if (!right_controller_active && right_controller_entity != nullptr) {
+    scene->RemoveEntity(right_controller_entity);
+  }
+}
+
+}  // namespace phx
diff --git a/library/phx/tracking_system.hpp b/library/phx/openvr_controller_system.hpp
similarity index 62%
rename from library/phx/tracking_system.hpp
rename to library/phx/openvr_controller_system.hpp
index 4022d7e7f2c28358e62a4d665862f84ea1228751..21a3f8b91e243cd6643f34ed9921a31980561ed2 100644
--- a/library/phx/tracking_system.hpp
+++ b/library/phx/openvr_controller_system.hpp
@@ -20,49 +20,44 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
-#ifndef LIBRARY_PHX_TRACKING_SYSTEM_HPP_
-#define LIBRARY_PHX_TRACKING_SYSTEM_HPP_
+#ifndef LIBRARY_PHX_OPENVR_CONTROLLER_SYSTEM_HPP_
+#define LIBRARY_PHX_OPENVR_CONTROLLER_SYSTEM_HPP_
 
-#include <string>
+#include <memory>
+#include <vector>
+
+SUPPRESS_WARNINGS_BEGIN
+#include "glm/glm.hpp"
+SUPPRESS_WARNINGS_END
 
 #include "phx/display_system.hpp"
 #include "phx/engine.hpp"
 #include "phx/export.hpp"
+#include "phx/hmd.hpp"
 #include "phx/system.hpp"
 
 namespace phx {
-
-class PHOENIX_EXPORT TrackingSystem : public System {
+class PHOENIX_EXPORT OpenVRControllerSystem : public System {
  public:
-  TrackingSystem() = delete;
-  TrackingSystem(const TrackingSystem&) = delete;
-  TrackingSystem(TrackingSystem&&) = default;
-  ~TrackingSystem() = default;
+  OpenVRControllerSystem() = delete;
+  OpenVRControllerSystem(const OpenVRControllerSystem&) = delete;
+  OpenVRControllerSystem(OpenVRControllerSystem&&) = default;
+  virtual ~OpenVRControllerSystem() = default;
 
-  TrackingSystem& operator=(const TrackingSystem&) = delete;
-  TrackingSystem& operator=(TrackingSystem&&) = default;
+  OpenVRControllerSystem& operator=(const OpenVRControllerSystem&) = delete;
+  OpenVRControllerSystem& operator=(OpenVRControllerSystem&&) = default;
 
   void Update(const FrameTimer::TimeInfo&) override;
 
-  std::string ToString() const override;
-
  protected:
-  TrackingSystem(Engine* engine, DisplaySystem* display_system);
-
- private:
-  void CreateRuntimeEntities();
-
   template <typename SystemType, typename... SystemArguments>
   friend SystemType* Engine::CreateSystem(SystemArguments&&... arguments);
-  explicit TrackingSystem(Engine* engine);
+  OpenVRControllerSystem(Engine* engine, DisplaySystem* display_system);
 
-  Entity* hmd_entity_ = nullptr;
-  Entity* left_eye_entity_ = nullptr;
-  Entity* right_eye_entity_ = nullptr;
-  Entity* left_controller_entity_ = nullptr;
-  Entity* right_controller_entity_ = nullptr;
+ private:
+  HMD* hmd_ = nullptr;
 };
 
 }  // namespace phx
 
-#endif  // LIBRARY_PHX_TRACKING_SYSTEM_HPP_
+#endif  // LIBRARY_PHX_OPENVR_CONTROLLER_SYSTEM_HPP_
diff --git a/library/phx/projection.hpp b/library/phx/projection.hpp
index 3acec40ce95d14ac23957110bf0255567481eb59..5f882493183b25de522b786c91ed9e1d564a56a4 100644
--- a/library/phx/projection.hpp
+++ b/library/phx/projection.hpp
@@ -34,7 +34,7 @@ SUPPRESS_WARNINGS_END
 
 namespace phx {
 
-class PHOENIX_EXPORT Projection : public Component {
+class PHOENIX_EXPORT Projection final : public Component {
  public:
   const glm::mat4& GetMatrix() const;
 
@@ -45,6 +45,15 @@ class PHOENIX_EXPORT Projection : public Component {
 
   std::string ToString() const override;
 
+ protected:
+  friend Entity;
+  Projection() = default;
+  Projection(const Projection&) = delete;
+  Projection(Projection&&) = default;
+
+  Projection& operator=(const Projection&) = delete;
+  Projection& operator=(Projection&&) = default;
+
  private:
   glm::mat4 matrix_;
 };
diff --git a/library/phx/render_target.hpp b/library/phx/render_target.hpp
index 4f9b65a69ebb1a780c0c6ac9176523a7afa78236..b87da3212c45b003218067c09ff3d5199976c41b 100644
--- a/library/phx/render_target.hpp
+++ b/library/phx/render_target.hpp
@@ -37,7 +37,6 @@ SUPPRESS_WARNINGS_END
 #include "gl/texture.hpp"
 
 #include "phx/export.hpp"
-#include "phx/hmd.hpp"
 
 namespace phx {
 
diff --git a/library/phx/rendering_system.cpp b/library/phx/rendering_system.cpp
index 15a17eb3ef60a938bec74ec15002c0bc98ff0310..45d55f276d7a08076cb91a6274c69c4fb5819544 100644
--- a/library/phx/rendering_system.cpp
+++ b/library/phx/rendering_system.cpp
@@ -31,7 +31,8 @@
 
 #include "blit_pass.hpp"
 #include "clear_pass.hpp"
-#include "display_system.hpp"
+#include "display_system_openvr.hpp"
+#include "display_system_window.hpp"
 #include "engine.hpp"
 #include "light.hpp"
 #include "logger.hpp"
@@ -39,6 +40,7 @@
 #include "mesh.hpp"
 #include "mesh_handle.hpp"
 #include "projection.hpp"
+#include "runtime_component.hpp"
 #include "scene.hpp"
 #include "system.hpp"
 #include "transform.hpp"
@@ -51,7 +53,6 @@ RenderingSystem::RenderingSystem(Engine* engine, DisplaySystem* display_system)
     : System(engine) {
   if (!display_system) error("RenderingSystem needs a valid DisplaySystem.");
   InitializeOpenGL();
-  InitializeRenderTargets();
   SetupFramegraph();
 }
 
@@ -63,59 +64,9 @@ void RenderingSystem::InitializeOpenGL() {
   gl::print_error(prefix.c_str());
 }
 
-void RenderingSystem::InitializeRenderTargets() {
-  const auto displaySystem = engine_->GetSystem<DisplaySystem>();
-  if (displaySystem == nullptr) {
-    error(
-        "The Rendering System cannot be initialized without a display system");
-    return;
-  }
-
-  // TODO(all) Support multiple windows and HMD?
-  if (displaySystem->GetHMD() != nullptr) {
-    HMD* hmd = displaySystem->GetHMD();
-    right_render_target_ =
-        std::make_unique<RenderTarget>(hmd->GetViewportSize());
-    left_render_target_ =
-        std::make_unique<RenderTarget>(hmd->GetViewportSize());
-  } else if (displaySystem->GetWindow() != nullptr) {
-    auto window = displaySystem->GetWindow();
-    window_render_target_ = std::make_unique<RenderTarget>(window->GetSize());
-  }
-}
-
 void RenderingSystem::SetupFramegraph() {
+  // set up an empty frame graph, just so we always have one...
   frame_graph_ = std::make_unique<FrameGraph>();
-
-  if (right_render_target_ != nullptr && left_render_target_ != nullptr) {
-    frame_graph_->AddRenderPass(
-        std::make_unique<ClearPass>(right_render_target_.get()));
-    frame_graph_->AddRenderPass(
-        std::make_unique<ClearPass>(left_render_target_.get()));
-    auto geometry_pass = static_cast<GeometryPass*>(frame_graph_->AddRenderPass(
-        std::make_unique<GeometryPass>(right_render_target_.get())));
-    geometry_passes_.push_back(geometry_pass);
-    geometry_pass = static_cast<GeometryPass*>(frame_graph_->AddRenderPass(
-        std::make_unique<GeometryPass>(left_render_target_.get())));
-    geometry_passes_.push_back(geometry_pass);
-
-    frame_graph_->AddRenderPass(
-        std::make_unique<BlitPass>(right_render_target_.get()));
-  } else if (window_render_target_ != nullptr) {
-    frame_graph_->AddRenderPass(
-        std::make_unique<ClearPass>(window_render_target_.get()));
-    auto geometry_pass = static_cast<GeometryPass*>(frame_graph_->AddRenderPass(
-        std::make_unique<GeometryPass>(window_render_target_.get())));
-    geometry_passes_.push_back(geometry_pass);
-    frame_graph_->AddRenderPass(
-        std::make_unique<BlitPass>(window_render_target_.get()));
-  } else {
-    error(
-        "[RenderingSystem] No Render Targets are defined, so no framegraph "
-        "will be created.");
-    return;
-  }
-
   frame_graph_->Initialize();
 }
 
@@ -127,16 +78,30 @@ void RenderingSystem::Update(const FrameTimer::TimeInfo&) {
   if (GetEngine()->GetScene() == nullptr) {
     return;
   }
+  if (render_targets_.empty()) {
+    return;
+  }
 
-  // TODO(@all) refactor this part, once there is a way to get entities by name
-  for (auto& entity : GetEngine()->GetEntities()) {
-    if (entity->GetName() == "RuntimeEntityEyeLeft") {
-      left_render_target_->SetView(
-          inverse(entity->GetFirstComponent<Transform>()->GetGlobalMatrix()));
+  const auto display_system_window = engine_->GetSystem<DisplaySystemWindow>();
+  const auto display_system_hmd = engine_->GetSystem<DisplaySystemOpenVR>();
+
+  // @TODO(anyone): these render parameters should be extracted from the scene
+  // somehow, the RenderingSystem shouldn't have to know about this.
+  if (display_system_hmd != nullptr && render_targets_.size() >= 2) {
+    auto right_eye_entities =
+        GetEngine()->GetEntitiesWithComponents<RuntimeComponent<RIGHT_EYE>>();
+    if (!right_eye_entities.empty()) {
+      render_targets_[0]->SetView(inverse(right_eye_entities[0]
+                                              ->GetFirstComponent<Transform>()
+                                              ->GetGlobalMatrix()));
     }
-    if (entity->GetName() == "RuntimeEntityEyeRight") {
-      right_render_target_->SetView(
-          inverse(entity->GetFirstComponent<Transform>()->GetGlobalMatrix()));
+
+    auto left_eye_entities =
+        GetEngine()->GetEntitiesWithComponents<RuntimeComponent<LEFT_EYE>>();
+    if (!left_eye_entities.empty()) {
+      render_targets_[1]->SetView(inverse(left_eye_entities[0]
+                                              ->GetFirstComponent<Transform>()
+                                              ->GetGlobalMatrix()));
     }
   }
 
@@ -150,9 +115,9 @@ void RenderingSystem::Update(const FrameTimer::TimeInfo&) {
       if (mesh_handle != nullptr) {
         Material* material = nullptr;
         if (material_handle != nullptr)
-          material = material_handle->GetMaterial();
+          material = material_handle->GetMaterial().Get();
         rendering_instances.push_back(
-            {mesh_handle->GetMesh(), material, transform});
+            {mesh_handle->GetMesh().Get(), material, transform});
       } else if (light != nullptr) {
         light_transform_pairs.push_back(
             std::pair<Light*, Transform*>(light, transform));
@@ -162,22 +127,25 @@ void RenderingSystem::Update(const FrameTimer::TimeInfo&) {
       }
     }
   }
-  for (auto geometry_pass : geometry_passes_) {
+  auto geometry_passes = frame_graph_->GetRenderPasses<GeometryPass>();
+  for (auto geometry_pass : geometry_passes) {
     geometry_pass->SetData(rendering_instances, light_transform_pairs);
   }
 
-  HMD* hmd = engine_->GetSystem<DisplaySystem>()->GetHMD();
-  if (left_render_target_ != nullptr) {
-    left_render_target_->SetProjection(hmd->GetProjectionMatrix(HMD::LEFT_EYE));
+  // @TODO(anyone) see above, should also not be in the RenderingSystem, but
+  // the scene (Camera?) should store the connection between render target
+  // and Camera
+  if (display_system_hmd != nullptr && render_targets_.size() >= 2) {
+    HMD* hmd = display_system_hmd->GetHMD();
+    render_targets_[0]->SetProjection(hmd->GetProjectionMatrix(HMD::RIGHT_EYE));
+    render_targets_[1]->SetProjection(hmd->GetProjectionMatrix(HMD::LEFT_EYE));
   }
-  if (right_render_target_ != nullptr) {
-    right_render_target_->SetProjection(
-        hmd->GetProjectionMatrix(HMD::RIGHT_EYE));
-  }
-  if (window_render_target_ != nullptr && !projection_transform_pairs.empty()) {
-    window_render_target_->SetProjection(
+
+  if (display_system_hmd == nullptr && display_system_window != nullptr &&
+      !render_targets_.empty() && !projection_transform_pairs.empty()) {
+    render_targets_[0]->SetProjection(
         projection_transform_pairs[0].first->GetMatrix());
-    window_render_target_->SetView(
+    render_targets_[0]->SetView(
         glm::inverse(projection_transform_pairs[0].second->GetGlobalMatrix()));
   }
 
@@ -188,17 +156,27 @@ FrameGraph* RenderingSystem::GetFrameGraph() const {
   return frame_graph_.get();
 }
 
+void RenderingSystem::SetFrameGraph(std::unique_ptr<FrameGraph> frame_graph) {
+  frame_graph_ = std::move(frame_graph);
+}
+
 std::string RenderingSystem::ToString() const {
   return "RenderingSystem with #FrameGraph-Passes: " +
          std::to_string(frame_graph_->GetNumberOfPasses());
 }
 
-phx::RenderTarget* RenderingSystem::GetRightRenderTarget() const {
-  return right_render_target_.get();
+void RenderingSystem::SetRenderTargets(
+    std::vector<std::unique_ptr<RenderTarget>>* render_targets) {
+  render_targets_ = std::move(*render_targets);
 }
 
-phx::RenderTarget* RenderingSystem::GetLeftRenderTarget() const {
-  return left_render_target_.get();
+std::vector<RenderTarget*> RenderingSystem::GetRenderTargets() const {
+  std::vector<RenderTarget*> render_targets;
+  std::transform(
+      render_targets_.begin(), render_targets_.end(),
+      std::back_inserter(render_targets),
+      [](const std::unique_ptr<RenderTarget>& ptr) { return ptr.get(); });
+  return render_targets;
 }
 
 }  // namespace phx
diff --git a/library/phx/rendering_system.hpp b/library/phx/rendering_system.hpp
index 43ca9b6df6fd09ce363ab4c7e2ee76a73fec3ff7..886f321b624c15f9b0859086ff2e96c7898fea23 100644
--- a/library/phx/rendering_system.hpp
+++ b/library/phx/rendering_system.hpp
@@ -49,35 +49,29 @@ class PHOENIX_EXPORT RenderingSystem : public System {
   void Update(const FrameTimer::TimeInfo& time_info) override;
 
   FrameGraph* GetFrameGraph() const;
+  void SetFrameGraph(std::unique_ptr<FrameGraph> frame_graph);
 
   std::string ToString() const override;
 
   RenderingSystem& operator=(const RenderingSystem&) = delete;
   RenderingSystem& operator=(RenderingSystem&&) = default;
 
-  RenderTarget* GetRightRenderTarget() const;
-  RenderTarget* GetLeftRenderTarget() const;
+  void SetRenderTargets(
+      std::vector<std::unique_ptr<RenderTarget>>* render_targets);
+  std::vector<RenderTarget*> GetRenderTargets() const;
 
  protected:
+  template <typename SystemType, typename... SystemArguments>
+  friend SystemType* Engine::CreateSystem(SystemArguments&&... arguments);
   RenderingSystem(Engine* engine, DisplaySystem* display_system);
 
  private:
   void InitializeOpenGL();
-  void InitializeRenderTargets();
   void SetupFramegraph();
 
-  template <typename SystemType, typename... SystemArguments>
-  friend SystemType* Engine::CreateSystem(SystemArguments&&... arguments);
-  explicit RenderingSystem(Engine* engine);
-
   std::unique_ptr<FrameGraph> frame_graph_;
 
-  // either window_render_target or the other two are nullptr
-  std::unique_ptr<RenderTarget> right_render_target_;
-  std::unique_ptr<RenderTarget> left_render_target_;
-  std::unique_ptr<RenderTarget> window_render_target_;
-
-  std::vector<GeometryPass*> geometry_passes_;
+  std::vector<std::unique_ptr<RenderTarget>> render_targets_;
 };
 
 }  // namespace phx
diff --git a/library/phx/resource_manager.cpp b/library/phx/resource_manager.cpp
index 158befcea4a783d3111d9d3e1f18b3008e62495c..2d566f968c9e5be02d7bd71eb0f1017d849d83aa 100644
--- a/library/phx/resource_manager.cpp
+++ b/library/phx/resource_manager.cpp
@@ -64,7 +64,7 @@ std::unique_ptr<phx::Resource> ResourceManager::Load(
     const ResourceDeclaration &declaration) {
   ResourceLoadStrategy *loader = nullptr;
   if (declaration.find("TYPE") != declaration.end()) {
-    loader = DetermineLoader(declaration["TYPE"]);
+    loader = GetLoaderForType(declaration["TYPE"]);
   } else {
     warn(
         "No Loader for Resource Declaration {}, can be determined, since it "
@@ -75,7 +75,7 @@ std::unique_ptr<phx::Resource> ResourceManager::Load(
   return loader->Load(declaration);
 }
 
-phx::ResourceLoadStrategy *ResourceManager::DetermineLoader(
+phx::ResourceLoadStrategy *ResourceManager::GetLoaderForType(
     const std::string &type) const {
   auto loader_iterator = loaders_by_type_.find(type);
   if (loader_iterator == loaders_by_type_.end()) {
diff --git a/library/phx/resource_manager.hpp b/library/phx/resource_manager.hpp
index 926c47832edc9a5d039b4ab95560f9b1e7e67f55..25e9bc943e903033fcf876e8a4b1a55e43c36797 100644
--- a/library/phx/resource_manager.hpp
+++ b/library/phx/resource_manager.hpp
@@ -52,6 +52,8 @@ class PHOENIX_EXPORT ResourceManager final : public singleton<ResourceManager> {
 
   ResourceProxy* DeclareResource(const ResourceDeclaration& declaration);
 
+  ResourceLoadStrategy* GetLoaderForType(const std::string& type) const;
+
  protected:
   friend ResourceManager& phx::singleton<ResourceManager>::instance<>();
   ResourceManager();
@@ -63,8 +65,6 @@ class PHOENIX_EXPORT ResourceManager final : public singleton<ResourceManager> {
 
   std::unique_ptr<Resource> Load(const ResourceDeclaration& declaration);
 
-  ResourceLoadStrategy* DetermineLoader(const std::string& type) const;
-
  private:
   void RegisterShaderResourceExtensions();
   void RegisterMeshResourceExtensions();
diff --git a/library/phx/resource_pointer.hpp b/library/phx/resource_pointer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2cb9391373e770bcf040f78424061c920453f15
--- /dev/null
+++ b/library/phx/resource_pointer.hpp
@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#ifndef LIBRARY_PHX_RESOURCE_POINTER_HPP_
+#define LIBRARY_PHX_RESOURCE_POINTER_HPP_
+
+#include "phx/export.hpp"
+#include "resource_proxy.hpp"
+
+namespace phx {
+
+template <class ResourceType>
+class PHOENIX_EXPORT ResourcePointer {
+ public:
+  ResourcePointer() : proxy_(nullptr) {}
+  explicit ResourcePointer(nullptr_t) : proxy_(nullptr) {}
+  explicit ResourcePointer(ResourceProxy *proxy) : proxy_(proxy) {}
+  ResourcePointer(const ResourcePointer &) = default;
+  ResourcePointer(ResourcePointer &&) = default;
+  ResourcePointer &operator=(const ResourcePointer &) = default;
+  ResourcePointer &operator=(ResourcePointer &&) = default;
+  ~ResourcePointer() = default;
+
+  ResourceType *operator->() { return proxy_->GetAs<ResourceType>(); }
+  bool operator==(const ResourcePointer<ResourceType> &a) const {
+    return a.GetProxy() == proxy_;
+  }
+  bool operator==(nullptr_t) const {
+    return proxy_ == nullptr || !proxy_->IsOnline();
+  }
+  bool operator!=(const ResourcePointer<ResourceType> &a) const {
+    return a.GetProxy() != proxy_;
+  }
+  bool operator!=(nullptr_t) const {
+    return proxy_ != nullptr && proxy_->IsOnline();
+  }
+  bool operator<(const ResourcePointer<ResourceType> &a) const {
+    return a.GetProxy() < proxy_;
+  }
+  operator bool() const { return proxy_ != nullptr && proxy_->IsOnline(); }
+
+  ResourceProxy *GetProxy() const { return proxy_; }
+  ResourceType *Get() const { return proxy_->GetAs<ResourceType>(); }
+
+ private:
+  ResourceProxy *proxy_;
+};
+
+}  // namespace phx
+
+#endif  // LIBRARY_PHX_RESOURCE_POINTER_HPP_
diff --git a/library/phx/resource_utils.cpp b/library/phx/resource_utils.cpp
index b6f88334f32210acfc6e6bc1d17460808e0235e5..e4e7f6990c71a92f781618f91ee2418e89f66f26 100644
--- a/library/phx/resource_utils.cpp
+++ b/library/phx/resource_utils.cpp
@@ -51,13 +51,4 @@ std::string ResourceUtils::ExtractFileExtension(const std::string& file_name) {
   return extension;
 }
 
-phx::ResourceProxy* ResourceUtils::LoadResourceFromFile(
-    const std::string& file_name, nlohmann::json additional_info /*= {}*/,
-    bool absolute_path /*= false*/) {
-  auto proxy = phx::ResourceManager::instance().DeclareResource(
-      DeclarationFromFile(file_name, additional_info, absolute_path));
-  proxy->Load();
-  return proxy;
-}
-
 }  // namespace phx
diff --git a/library/phx/resource_utils.hpp b/library/phx/resource_utils.hpp
index 8a7546f4b94a86bb9f0b72d456d5512fc485d0cc..b599385d96f4231bce773898872d0db9b6fb7341 100644
--- a/library/phx/resource_utils.hpp
+++ b/library/phx/resource_utils.hpp
@@ -33,14 +33,15 @@
 #include "phx/logger.hpp"
 #include "phx/resource_declaration.hpp"
 #include "phx/resource_load_strategy.hpp"
+#include "phx/resource_manager.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 #include "phx/singleton.hpp"
 
 namespace phx {
 /**
- *  The ResourceManager is the central instance for the management of all
- *  externally provided content, aka resources. Resources have to be declared
- *  first before being available in the system.
+ * The ResourceUtils class contains static convenience methods to simplify
+ * interactions with the resource system. It should never hold any state.
  */
 class PHOENIX_EXPORT ResourceUtils final {
  public:
@@ -48,9 +49,16 @@ class PHOENIX_EXPORT ResourceUtils final {
   static ResourceDeclaration DeclarationFromFile(
       const std::string& file_name, nlohmann::json additional_info = {},
       bool absolute_path = false);
-  static ResourceProxy* LoadResourceFromFile(
+
+  template <class ResourceType>
+  static ResourcePointer<ResourceType> LoadResourceFromFile(
       const std::string& file_name, nlohmann::json additional_info = {},
-      bool absolute_path = false);
+      bool absolute_path = false) {
+    auto proxy = phx::ResourceManager::instance().DeclareResource(
+        DeclarationFromFile(file_name, additional_info, absolute_path));
+    proxy->Load();
+    return ResourcePointer<ResourceType>(proxy);
+  }
 };
 
 }  // namespace phx
diff --git a/library/phx/scene_loader.cpp b/library/phx/scene_loader.cpp
index 0c02dc743854508df0e4a20290b9806287c08800..a112b8884c0fe1aa8f192d5fcb820c7f72073867 100644
--- a/library/phx/scene_loader.cpp
+++ b/library/phx/scene_loader.cpp
@@ -35,20 +35,18 @@ namespace phx {
 
 bool SceneLoader::InsertModelIntoScene(const std::string& file_name,
                                        Scene* scene) {
-  auto model_proxy = ResourceUtils::LoadResourceFromFile(file_name);
-  if (!model_proxy->IsOnline()) {
+  auto model = ResourceUtils::LoadResourceFromFile<Model>(file_name);
+  if (!model.GetProxy()->IsOnline()) {
     return false;
   }
 
-  auto model = model_proxy->GetAs<Model>();
-
-  for (auto mesh_proxy : model->GetMeshes()) {
+  for (auto mesh : model->GetMeshes()) {
     auto entity = scene->CreateEntity();
     entity->AddComponent<Transform>();
-    entity->AddComponent<MeshHandle>()->SetMeshProxy(mesh_proxy);
-    phx::ResourceProxy* material_proxy = model->GetMaterialForMesh(mesh_proxy);
-    if (material_proxy != nullptr) {
-      entity->AddComponent<MaterialHandle>()->SetMaterialProxy(material_proxy);
+    entity->AddComponent<MeshHandle>()->SetMesh(mesh);
+    ResourcePointer<Material> material = model->GetMaterialForMesh(mesh);
+    if (material != nullptr && material.GetProxy()->IsOnline()) {
+      entity->AddComponent<MaterialHandle>()->SetMaterial(material);
     }
   }
 
diff --git a/library/phx/setup.cpp b/library/phx/setup.cpp
index 28773ff4351a4bf94d37bc9ff23b667c470d208c..2b97bad44ba18b34ec81f4a458f3869c44af6318 100644
--- a/library/phx/setup.cpp
+++ b/library/phx/setup.cpp
@@ -24,15 +24,21 @@
 
 #include <cassert>
 #include <memory>
+#include <utility>
 
 #include "behavior_system.hpp"
-#include "display_system.hpp"
+#include "blit_pass.hpp"
+#include "clear_pass.hpp"
+#include "display_system_openvr.hpp"
+#include "display_system_window.hpp"
 #include "engine.hpp"
 #include "hmd.hpp"
 #include "input_system.hpp"
 #include "logger.hpp"
+#include "openvr_controller_system.hpp"
+#include "render_target.hpp"
 #include "rendering_system.hpp"
-#include "tracking_system.hpp"
+#include "tracking_system_openvr.hpp"
 
 #undef CreateWindow
 namespace phx {
@@ -42,21 +48,94 @@ std::unique_ptr<Engine> Setup::CreateDefaultEngine() {
   auto engine_ptr = engine.get();
   engine->SetScene(std::make_shared<Scene>());
 
-  engine->CreateSystem<BehaviorSystem>();
+  auto behavior_system = engine->CreateSystem<BehaviorSystem>();
   engine->CreateSystem<InputSystem>()->AddQuitCallback(
       [engine_ptr]() { engine_ptr->Stop(); });
 
-  auto displaysys = engine->CreateSystem<DisplaySystem>();
+  auto displaysys_window = engine->CreateSystem<DisplaySystemWindow>();
+  DisplaySystemOpenVR* displaysys_hmd = nullptr;
+  bool using_hmd = false;
   if (HMD::IsHMDPresent()) {
     info("An HMD is present so we use it");
-    displaysys->CreateHMD();
+    using_hmd = true;
+
+    displaysys_hmd = engine->CreateSystem<DisplaySystemOpenVR>();
+    displaysys_hmd->CreateHMD();
+    displaysys_window->CreateWindow(
+        "Phoenix HMD Companion", glm::uvec2(10, 10),
+        displaysys_hmd->GetHMD()->GetViewportSize());
+  } else {
+    displaysys_window->CreateWindow("Phoenix", glm::uvec2(100, 100));
+  }
+
+  auto rendering_system =
+      engine->CreateSystem<RenderingSystem>(engine->GetSystem<DisplaySystem>());
+
+  // fix update order
+  engine->GetUpdateOrder().MoveToBack(displaysys_window);
+  engine->GetUpdateOrder().MoveBefore(rendering_system, displaysys_window);
+
+  // setup rendering and frame graph
+  if (using_hmd) {
+    // we need the render targets of the DisplaySystemOpenVR, but the
+    // DisplaySystemWindow only exists for blitting the result of the left eye
+    // into the window and does not create a render target themselves
+    auto render_targets = displaysys_hmd->CreateRenderTargets();
+    rendering_system->SetRenderTargets(&render_targets);
+    SetupDefaultFrameGraphOpenVR(rendering_system);
+    auto tracking_system =
+        engine->CreateSystem<TrackingSystemOpenVR>(displaysys_hmd);
+    auto controller_system = engine->CreateSystem<OpenVRControllerSystem>(
+        engine->GetSystem<DisplaySystem>());
+    engine->GetUpdateOrder().MoveBefore(tracking_system, rendering_system);
+    engine->GetUpdateOrder().MoveAfter(behavior_system, tracking_system);
+    engine->GetUpdateOrder().MoveAfter(tracking_system, controller_system);
   } else {
-    displaysys->CreateWindow("Phoenix", glm::uvec2(100, 100));
+    auto render_targets = displaysys_window->CreateRenderTargets();
+    rendering_system->SetRenderTargets(&render_targets);
+    SetupDefaultFrameGraphWindow(rendering_system);
   }
-  engine->CreateSystem<RenderingSystem>(engine->GetSystem<DisplaySystem>());
-  engine->CreateSystem<TrackingSystem>(engine->GetSystem<DisplaySystem>());
 
   return engine;
 }
 
+void Setup::SetupDefaultFrameGraphWindow(RenderingSystem* rendering_system) {
+  auto frame_graph = std::make_unique<FrameGraph>();
+  auto render_targets = rendering_system->GetRenderTargets();
+  if (render_targets.empty()) {
+    error("Cannot setup default frame graph (window): no render targets.");
+    return;
+  }
+
+  frame_graph->AddRenderPass(std::make_unique<ClearPass>(render_targets[0]));
+  frame_graph->AddRenderPass(std::make_unique<GeometryPass>(render_targets[0]));
+  frame_graph->AddRenderPass(std::make_unique<BlitPass>(render_targets[0]));
+
+  frame_graph->Initialize();
+
+  rendering_system->SetFrameGraph(std::move(frame_graph));
+}
+
+void Setup::SetupDefaultFrameGraphOpenVR(RenderingSystem* rendering_system) {
+  auto frame_graph = std::make_unique<FrameGraph>();
+  auto render_targets = rendering_system->GetRenderTargets();
+  if (render_targets.size() < 2) {
+    error(
+        "Cannot setup default frame graph (OpenVR): not enough render "
+        "targets.");
+    return;
+  }
+
+  frame_graph->AddRenderPass(std::make_unique<ClearPass>(render_targets[0]));
+  frame_graph->AddRenderPass(std::make_unique<ClearPass>(render_targets[1]));
+  frame_graph->AddRenderPass(std::make_unique<GeometryPass>(render_targets[0]));
+  frame_graph->AddRenderPass(std::make_unique<GeometryPass>(render_targets[1]));
+
+  frame_graph->AddRenderPass(std::make_unique<BlitPass>(render_targets[0]));
+
+  frame_graph->Initialize();
+
+  rendering_system->SetFrameGraph(std::move(frame_graph));
+}
+
 }  // namespace phx
diff --git a/library/phx/setup.hpp b/library/phx/setup.hpp
index d96286b93bd00da09675b298b3c2c5508acfbeae..c5fb4a7496c2990dc871484eb020e0c22c0b437b 100644
--- a/library/phx/setup.hpp
+++ b/library/phx/setup.hpp
@@ -27,6 +27,8 @@
 
 #include "phx/engine.hpp"
 #include "phx/export.hpp"
+#include "phx/frame_graph.hpp"
+#include "phx/rendering_system.hpp"
 #include "phx/scene.hpp"
 #include "phx/window.hpp"
 
@@ -40,6 +42,9 @@ class PHOENIX_EXPORT Setup {
   // i.e.: RenderingSystem and an InputSystem
   // also creates an empty scene for the engine
   static std::unique_ptr<Engine> CreateDefaultEngine();
+
+  static void SetupDefaultFrameGraphWindow(RenderingSystem* rendering_system);
+  static void SetupDefaultFrameGraphOpenVR(RenderingSystem* rendering_system);
 };
 
 }  // namespace phx
diff --git a/library/phx/shader_program.cpp b/library/phx/shader_program.cpp
index 3532ffaa356cefa15e15be00daa3df13ce2b3e9d..445f001ef4171700c652313dc480c1e557673caa 100644
--- a/library/phx/shader_program.cpp
+++ b/library/phx/shader_program.cpp
@@ -33,14 +33,14 @@
 
 namespace phx {
 
-bool ShaderProgram::SetShaderProxy(ShaderChannel channel,
-                                   ResourceProxy* shader_source) {
+bool ShaderProgram::SetShader(
+    ShaderChannel channel, ResourcePointer<ShaderSource> shader_source) {
   auto& entry = shaders_[channel];
   entry.first = shader_source;
   entry.second =
       std::make_unique<gl::shader>(this->ConvertChannelToGL(channel));
   gl::shader* shader = entry.second.get();
-  shader->set_source(this->GetShaderSource(shader_source));
+  shader->set_source(shader_source->GetSource());
 
   return this->CompileAndAttachShader(shader);
 }
@@ -85,9 +85,4 @@ GLenum ShaderProgram::ConvertChannelToGL(ShaderChannel channel) const {
   }
 }
 
-std::string ShaderProgram::GetShaderSource(ResourceProxy* shader_proxy) const {
-  auto shader_source = shader_proxy->GetAs<phx::ShaderSource>();
-  return shader_source->GetSource();
-}
-
 }  // namespace phx
diff --git a/library/phx/shader_program.hpp b/library/phx/shader_program.hpp
index 2c6d92dc7b0be2d6c6d23a509257dd9d659a2e3b..3244f15ee0a6174b50ccfd3301026bdfca7178e4 100644
--- a/library/phx/shader_program.hpp
+++ b/library/phx/shader_program.hpp
@@ -38,7 +38,8 @@ SUPPRESS_WARNINGS_END
 #include "phx/export.hpp"
 #include "phx/mesh.hpp"
 #include "phx/render_pass.hpp"
-#include "phx/resource_proxy.hpp"
+#include "phx/resource_pointer.hpp"
+#include "phx/shader_source.hpp"
 #include "phx/transform.hpp"
 
 namespace phx {
@@ -67,7 +68,8 @@ class PHOENIX_EXPORT ShaderProgram : public gl::program {
   ShaderProgram& operator=(const ShaderProgram&) = delete;
   ShaderProgram& operator=(ShaderProgram&&) = default;
 
-  bool SetShaderProxy(ShaderChannel channel, ResourceProxy* shader_source);
+  bool SetShader(ShaderChannel channel,
+                      ResourcePointer<ShaderSource> shader_source);
 
   template <typename T>
   void SetUniform(const std::string& name, T value) {
@@ -82,9 +84,8 @@ class PHOENIX_EXPORT ShaderProgram : public gl::program {
 
   GLenum ConvertChannelToGL(ShaderChannel channel) const;
 
-  std::string GetShaderSource(ResourceProxy* shader_proxy) const;
-
-  using ShaderHandle = std::pair<ResourceProxy*, std::unique_ptr<gl::shader>>;
+  using ShaderHandle =
+      std::pair<ResourcePointer<ShaderSource>, std::unique_ptr<gl::shader>>;
   std::array<ShaderHandle, MAX_SHADER_CHANNEL> shaders_;
 };
 
diff --git a/library/phx/splash_screen.cpp b/library/phx/splash_screen.cpp
index fa0afd0b127671c40fa939a4dde90e82390d6c0c..3a36247ff754345f13c6ad1b564496a68e8f1b9a 100644
--- a/library/phx/splash_screen.cpp
+++ b/library/phx/splash_screen.cpp
@@ -36,8 +36,8 @@
 namespace phx {
 
 phx::SplashScreen::SplashScreen(Window* window) : window_(window) {
-  splash_image_proxy_ =
-      ResourceUtils::LoadResourceFromFile("textures/splash_progress.png");
+  splash_image_ = ResourceUtils::LoadResourceFromFile<Image>(
+      "textures/splash_progress.png");
 
   progressbar_image_ =
       std::make_unique<Image>(std::array<std::size_t, 2>{{1ull, 1ull}}, 32);
@@ -47,8 +47,7 @@ phx::SplashScreen::SplashScreen(Window* window) : window_(window) {
 }
 
 void SplashScreen::Draw() {
-  Image* splash_image = splash_image_proxy_->GetAs<Image>();
-  auto splash_dimensions = splash_image->GetDimensions();
+  auto splash_dimensions = splash_image_->GetDimensions();
   auto progress_dimensions = progressbar_image_->GetDimensions();
   gl::initialize();
   gl::framebuffer splash_buff;
@@ -62,7 +61,7 @@ void SplashScreen::Draw() {
                                             0);
   splash_tex.set_sub_image(0, 0, 0, static_cast<GLsizei>(splash_dimensions[0]),
                            static_cast<GLsizei>(splash_dimensions[1]), GL_RGBA,
-                           GL_UNSIGNED_BYTE, splash_image->GetPixels().first);
+                           GL_UNSIGNED_BYTE, splash_image_->GetPixels().first);
   gl::print_error("OpenGl Error creating Splash Screen texture: ");
   splash_buff.unbind();
   splash_tex.unbind();
diff --git a/library/phx/splash_screen.hpp b/library/phx/splash_screen.hpp
index d1fc1044df205acae2d36c28d8e23ed92a37f989..71492e57ab2e767359e97016fda3868c9d7e7d10 100644
--- a/library/phx/splash_screen.hpp
+++ b/library/phx/splash_screen.hpp
@@ -27,6 +27,7 @@
 
 #include "phx/export.hpp"
 #include "phx/image.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 #include "phx/window.hpp"
 
@@ -49,7 +50,7 @@ class PHOENIX_EXPORT SplashScreen {
 
  private:
   std::unique_ptr<gl::framebuffer> default_framebuffer_;
-  ResourceProxy* splash_image_proxy_;
+  ResourcePointer<Image> splash_image_;
   std::unique_ptr<Image> progressbar_image_;
   Window* window_;
 
diff --git a/library/phx/tracking_system.cpp b/library/phx/tracking_system_openvr.cpp
similarity index 55%
rename from library/phx/tracking_system.cpp
rename to library/phx/tracking_system_openvr.cpp
index ae836ae207255f3163e21681f2e0b1f9b5963a07..e78c6ebade0c9b4dec3453b79a37ac0bb8da64a1 100644
--- a/library/phx/tracking_system.cpp
+++ b/library/phx/tracking_system_openvr.cpp
@@ -20,11 +20,12 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
-#include "tracking_system.hpp"
+#include "tracking_system_openvr.hpp"
 
+#include <memory>
 #include <string>
 
-#include "display_system.hpp"
+#include "display_system_openvr.hpp"
 #include "hmd.hpp"
 #include "logger.hpp"
 #include "projection.hpp"
@@ -33,39 +34,60 @@
 
 namespace phx {
 
-TrackingSystem::TrackingSystem(Engine* engine, DisplaySystem* display_system)
+TrackingSystemOpenVR::TrackingSystemOpenVR(Engine* engine,
+                                           DisplaySystemOpenVR* display_system)
     : System(engine) {
-  if (!display_system) error("TrackingSystem needs a valid DisplaySystem.");
-  CreateRuntimeEntities();
+  if (!display_system)
+    error("TrackingSystemOpenVR needs a valid DisplaySystemOpenVR.");
+  if (display_system->GetHMD()) {
+    CreateRuntimeEntities(engine->GetScene().get());
+    scene_changed_connection_ = engine->AddSceneChangedCallback(
+        [this](std::shared_ptr<Scene> old_scene,
+               std::shared_ptr<Scene> new_scene) {
+          OnSceneChanged(old_scene, new_scene);
+        });
+  }
+}
+
+TrackingSystemOpenVR::~TrackingSystemOpenVR() {
+  scene_changed_connection_.disconnect();
 }
 
-void TrackingSystem::Update(const FrameTimer::TimeInfo&) {
-  const auto hmd = engine_->GetSystem<DisplaySystem>()->GetHMD();
-  if (hmd == nullptr) return;
+void TrackingSystemOpenVR::Update(const FrameTimer::TimeInfo&) {
+  const auto dispsys_openvr = engine_->GetSystem<DisplaySystemOpenVR>();
+  if (dispsys_openvr == nullptr) {
+    return;
+  }
+  const auto hmd = dispsys_openvr->GetHMD();
+  if (hmd == nullptr) {
+    return;
+  }
   hmd->UpdateTrackedDevices();
   const auto head_transformation = hmd->GetHeadTransformation();
-  hmd_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
-      head_transformation);
-  const auto left_eye_transformation = hmd->GetEyeToHeadMatrix(HMD::LEFT_EYE);
-  left_eye_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
-      left_eye_transformation);
-  const auto right_eye_transformation = hmd->GetEyeToHeadMatrix(HMD::RIGHT_EYE);
-  right_eye_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
-      right_eye_transformation);
-
-  left_controller_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
-      hmd->GetLeftControllerTransformation());
-
-  right_controller_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
-      hmd->GetRightControllerTransformation());
+  if (hmd_entity_ != nullptr) {
+    hmd_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
+        head_transformation);
+    const auto left_eye_transformation = hmd->GetEyeToHeadMatrix(HMD::LEFT_EYE);
+    left_eye_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
+        left_eye_transformation);
+    const auto right_eye_transformation =
+        hmd->GetEyeToHeadMatrix(HMD::RIGHT_EYE);
+    right_eye_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
+        right_eye_transformation);
+
+    left_controller_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
+        hmd->GetLeftControllerTransformation());
+
+    right_controller_entity_->GetFirstComponent<Transform>()->SetLocalMatrix(
+        hmd->GetRightControllerTransformation());
+  }
 }
 
-void TrackingSystem::CreateRuntimeEntities() {
-  const auto hmd = engine_->GetSystem<DisplaySystem>()->GetHMD();
+void TrackingSystemOpenVR::CreateRuntimeEntities(Scene* scene) {
+  const auto hmd = engine_->GetSystem<DisplaySystemOpenVR>()->GetHMD();
   if (hmd == nullptr) {
     return;
   }
-  auto scene = engine_->GetScene();
   if (scene == nullptr) {
     return;
   }
@@ -108,6 +130,20 @@ void TrackingSystem::CreateRuntimeEntities() {
   }
 }
 
-std::string TrackingSystem::ToString() const { return "Tracking System"; }
+void TrackingSystemOpenVR::RemoveRuntimeEntities(Scene* scene) {
+  scene->RemoveEntity(hmd_entity_);
+  scene->RemoveEntity(left_eye_entity_);
+  scene->RemoveEntity(right_eye_entity_);
+  scene->RemoveEntity(left_controller_entity_);
+  scene->RemoveEntity(right_controller_entity_);
+}
+
+void TrackingSystemOpenVR::OnSceneChanged(std::shared_ptr<Scene> old_scene,
+                                    std::shared_ptr<Scene> new_scene) {
+  RemoveRuntimeEntities(old_scene.get());
+  CreateRuntimeEntities(new_scene.get());
+}
+
+std::string TrackingSystemOpenVR::ToString() const { return "Tracking System"; }
 
 }  // namespace phx
diff --git a/library/phx/tracking_system_openvr.hpp b/library/phx/tracking_system_openvr.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c11f301c89d77052db966367b82834ac6c6e92b
--- /dev/null
+++ b/library/phx/tracking_system_openvr.hpp
@@ -0,0 +1,78 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#ifndef LIBRARY_PHX_TRACKING_SYSTEM_OPENVR_HPP_
+#define LIBRARY_PHX_TRACKING_SYSTEM_OPENVR_HPP_
+
+#include <memory>
+#include <string>
+
+#include "phx/display_system_openvr.hpp"
+#include "phx/engine.hpp"
+#include "phx/export.hpp"
+#include "phx/system.hpp"
+
+SUPPRESS_WARNINGS_BEGIN
+#define BOOST_BIND_NO_PLACEHOLDERS
+#include "boost/signals2/connection.hpp"
+SUPPRESS_WARNINGS_END
+
+namespace phx {
+
+class PHOENIX_EXPORT TrackingSystemOpenVR : public System {
+ public:
+  TrackingSystemOpenVR() = delete;
+  TrackingSystemOpenVR(const TrackingSystemOpenVR&) = delete;
+  TrackingSystemOpenVR(TrackingSystemOpenVR&&) = default;
+  ~TrackingSystemOpenVR();
+
+  TrackingSystemOpenVR& operator=(const TrackingSystemOpenVR&) = delete;
+  TrackingSystemOpenVR& operator=(TrackingSystemOpenVR&&) = default;
+
+  void Update(const FrameTimer::TimeInfo&) override;
+
+  std::string ToString() const override;
+
+ protected:
+  TrackingSystemOpenVR(Engine* engine, DisplaySystemOpenVR* display_system);
+
+ private:
+  template <typename SystemType, typename... SystemArguments>
+  friend SystemType* Engine::CreateSystem(SystemArguments&&... arguments);
+
+  void CreateRuntimeEntities(Scene* scene);
+  void RemoveRuntimeEntities(Scene* scene);
+  void OnSceneChanged(std::shared_ptr<Scene> old_scene,
+                      std::shared_ptr<Scene> new_scene);
+
+  Entity* hmd_entity_ = nullptr;
+  Entity* left_eye_entity_ = nullptr;
+  Entity* right_eye_entity_ = nullptr;
+  Entity* left_controller_entity_ = nullptr;
+  Entity* right_controller_entity_ = nullptr;
+
+  boost::signals2::connection scene_changed_connection_;
+};
+
+}  // namespace phx
+
+#endif  // LIBRARY_PHX_TRACKING_SYSTEM_OPENVR_HPP_
diff --git a/library/phx/transform.hpp b/library/phx/transform.hpp
index ed5e8d25b9e69908f07f53429aaf79ea2d07af62..787c9df69a1c1055b3021fd58bc658ce349c0431 100644
--- a/library/phx/transform.hpp
+++ b/library/phx/transform.hpp
@@ -42,18 +42,8 @@ namespace phx {
 class PHOENIX_EXPORT Transform : public Component,
                                  public Hierarchical<Transform> {
  public:
-  Transform(const glm::vec3& translation = glm::vec3(),
-            const glm::quat& rotation = glm::quat(),
-            const glm::vec3& scale = glm::vec3(1.0f));
-  Transform(const glm::vec3& translation, const glm::vec3& rotation_euler,
-            const glm::vec3& scale = glm::vec3(1.0f));
-  Transform(const Transform&) = default;
-  Transform(Transform&&) = default;
   virtual ~Transform() = default;
 
-  Transform& operator=(const Transform&) = default;
-  Transform& operator=(Transform&&) = default;
-
   // Getting/Setting Local transform
   const glm::vec3& GetLocalTranslation() const;
   Transform& SetLocalTranslation(const glm::vec3& translation);
@@ -104,6 +94,19 @@ class PHOENIX_EXPORT Transform : public Component,
 
   std::string ToString() const override;
 
+ protected:
+  friend Entity;
+  Transform(const glm::vec3& translation = glm::vec3(),
+            const glm::quat& rotation = glm::quat(),
+            const glm::vec3& scale = glm::vec3(1.0f));
+  Transform(const glm::vec3& translation, const glm::vec3& rotation_euler,
+            const glm::vec3& scale = glm::vec3(1.0f));
+  Transform(const Transform&) = delete;
+  Transform(Transform&&) = default;
+
+  Transform& operator=(const Transform&) = delete;
+  Transform& operator=(Transform&&) = default;
+
  private:
   bool CheckIfParentIsValid(Transform* parent);
   void UpdateLocalMatrix();
diff --git a/library/phx/window.cpp b/library/phx/window.cpp
index 2c61f93c5c80657361ccb00814be1c910bbc2425..edc41151a95ac2d2785ed975b657dbcdc8cdfedb 100644
--- a/library/phx/window.cpp
+++ b/library/phx/window.cpp
@@ -35,11 +35,12 @@ Window::Window(const std::string& title)
   Validate();
 }
 Window::Window(const std::string& title, const glm::uvec2& position,
-               const glm::uvec2& size)
+               const glm::uvec2& size, bool hidden)
     : native_(SDL_CreateWindow(
           title.c_str(), static_cast<int>(position.x),
           static_cast<int>(position.y), static_cast<int>(size.x),
-          static_cast<int>(size.y), SetupOpenGLContextFlags())),
+          static_cast<int>(size.y),
+          SetupOpenGLContextFlags() | (hidden ? SDL_WINDOW_HIDDEN : 0))),
       gl_context_(SDL_GL_CreateContext(native_)) {
   Validate();
 }
@@ -57,6 +58,14 @@ glm::uvec2 Window::GetSize() const {
   return glm::uvec2(static_cast<unsigned>(w), static_cast<unsigned>(h));
 }
 
+void Window::SetVisible(bool visible) {
+  if (visible) {
+    SDL_ShowWindow(native_);
+  } else {
+    SDL_HideWindow(native_);
+  }
+}
+
 std::uint32_t Window::SetupOpenGLContextFlags() const {
   SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
   SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
diff --git a/library/phx/window.hpp b/library/phx/window.hpp
index edd41bd4cf3715036775b30de75ba836b955c6f5..ea581f66159bc2051f4a0f5c04a3eefb46ea9dfd 100644
--- a/library/phx/window.hpp
+++ b/library/phx/window.hpp
@@ -34,7 +34,7 @@ SUPPRESS_WARNINGS_END
 
 namespace phx {
 
-class DisplaySystem;
+class DisplaySystemWindow;
 
 class PHOENIX_EXPORT Window {
  public:
@@ -49,12 +49,14 @@ class PHOENIX_EXPORT Window {
 
   glm::uvec2 GetSize() const;
 
+  void SetVisible(bool visible);
+
  protected:
-  friend DisplaySystem;
+  friend DisplaySystemWindow;
 
   explicit Window(const std::string& title);
   Window(const std::string& title, const glm::uvec2& position,
-         const glm::uvec2& size = glm::uvec2(1024, 768));
+         const glm::uvec2& size = glm::uvec2(1024, 768), bool hidden = false);
 
   std::uint32_t SetupOpenGLContextFlags() const;
   void Validate() const;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 0c516001fb8a2bb48d0353a54fac5d8469af3628..14e3a3d43d80b7ada144e5e8a3f81e07489abb90 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -226,6 +226,7 @@ add_mocked_test(test_shader MOCK_GLEW)
 add_mocked_test(test_display_system MOCK_SDL)
 add_mocked_test(test_engine MOCK_SDL MOCK_OPENVR MOCK_GLEW)
 add_mocked_test(test_tracking_system MOCK_SDL MOCK_OPENVR)
+add_mocked_test(test_openvr_controller_system MOCK_SDL MOCK_OPENVR MOCK_GLEW)
 
 add_mocked_test(integration_test_model_rendering MOCK_OPENVR)
 add_mocked_test(integration_test_opengl_buffer_data_download MOCK_OPENVR)
diff --git a/tests/src/integration_test_model_rendering.cpp b/tests/src/integration_test_model_rendering.cpp
index f4d4a601534826ecb357afdc8f5619d314b65221..dc107451e97160504b6886a2d518bf801e229bd5 100644
--- a/tests/src/integration_test_model_rendering.cpp
+++ b/tests/src/integration_test_model_rendering.cpp
@@ -25,7 +25,7 @@
 #include "catch/catch.hpp"
 
 #include "phx/assimp_model_loader.hpp"
-#include "phx/display_system.hpp"
+#include "phx/display_system_window.hpp"
 #include "phx/frame_timer.hpp"
 #include "phx/mesh.hpp"
 #include "phx/mesh_handle.hpp"
@@ -51,20 +51,20 @@ extern template struct trompeloeil::reporter<trompeloeil::specialized>;
 
 phx::Entity* LoadBunny(glm::vec3 pos, float angleDeg,
                        unsigned int material_index, phx::Scene* scene) {
-  auto bunny_proxy = phx::ResourceUtils::LoadResourceFromFile(
+  auto bunny_mesh = phx::ResourceUtils::LoadResourceFromFile<phx::Mesh>(
       "models/bunny.obj", {{"mesh_index", 0}});
 
   phx::Entity* bunny = scene->CreateEntity();
 
   phx::MeshHandle* bunny_handle = bunny->AddComponent<phx::MeshHandle>();
-  bunny_handle->SetMeshProxy(bunny_proxy);
+  bunny_handle->SetMesh(bunny_mesh);
 
   phx::MaterialHandle* bunny_material_handle =
       bunny->AddComponent<phx::MaterialHandle>();
 
-  auto bunny_material_proxy = phx::ResourceUtils::LoadResourceFromFile(
+  auto bunny_material = phx::ResourceUtils::LoadResourceFromFile<phx::Material>(
       "models/bunny.obj", {{"material_index", material_index}});
-  bunny_material_handle->SetMaterialProxy(bunny_material_proxy);
+  bunny_material_handle->SetMaterial(bunny_material);
 
   phx::Transform* bunny_transform = bunny->AddComponent<phx::Transform>();
   bunny_transform->SetLocalTranslation(pos);
@@ -111,7 +111,7 @@ SCENARIO(
         LoadBunny(glm::vec3(-0.15f, -0.1f, 0.0f), 180.0f, 2, scene.get());
 
     auto rendering_system = engine->GetSystem<phx::RenderingSystem>();
-    auto display_system = engine->GetSystem<phx::DisplaySystem>();
+    auto display_system = engine->GetSystem<phx::DisplaySystemWindow>();
 
     WHEN("We render the scene") {
       rendering_system->Update(phx::FrameTimer::TimeInfo());
@@ -140,7 +140,7 @@ SCENARIO(
         LoadBunny(glm::vec3(0.0f, -0.1f, -0.3f), 0.0f, 1, scene.get());
 
     auto rendering_system = engine->GetSystem<phx::RenderingSystem>();
-    auto display_system = engine->GetSystem<phx::DisplaySystem>();
+    auto display_system = engine->GetSystem<phx::DisplaySystemWindow>();
 
     WHEN("We render the scene") {
       rendering_system->Update(phx::FrameTimer::TimeInfo{});
diff --git a/tests/src/integration_test_opengl_buffer_data_download.cpp b/tests/src/integration_test_opengl_buffer_data_download.cpp
index cad6ca25a7335d3f9725011eece775800fd9a960..16ec61edecc70111a11ca1ce5e3ee78a2bccdb64 100644
--- a/tests/src/integration_test_opengl_buffer_data_download.cpp
+++ b/tests/src/integration_test_opengl_buffer_data_download.cpp
@@ -35,6 +35,7 @@
 #include "phx/rendering_system.hpp"
 #include "phx/resource_declaration.hpp"
 #include "phx/resource_manager.hpp"
+#include "phx/resource_pointer.hpp"
 #include "phx/resource_proxy.hpp"
 #include "phx/scene.hpp"
 #include "phx/setup.hpp"
@@ -99,7 +100,8 @@ class SceneSetupSimple {
 
     phx::MaterialHandle* material_handle =
         triangle->AddComponent<phx::MaterialHandle>();
-    material_handle->SetMaterialProxy(material_proxy);
+    material_handle->SetMaterial(
+        phx::ResourcePointer<phx::Material>(material_proxy));
 
     std::vector<glm::vec3> vertices = {
         {-1.0f, -1.0f, 0.5f}, {1.0f, -1.0f, 0.5f}, {1.0f, 1.0f, 0.5f}};
@@ -116,7 +118,7 @@ class SceneSetupSimple {
     mesh_proxy->Load();
 
     auto mesh_handle = triangle->AddComponent<phx::MeshHandle>();
-    mesh_handle->SetMeshProxy(mesh_proxy);
+    mesh_handle->SetMesh(phx::ResourcePointer<phx::Mesh>(mesh_proxy));
 
     phx::Entity* main_light = scene->CreateEntity();
     main_light->AddComponent<phx::Transform>();
diff --git a/tests/src/integration_test_rendering.cpp b/tests/src/integration_test_rendering.cpp
index a4f6257c7c158ce19978f7480c0aa13d0062f89d..4dc91836cd69184f7098628ee3c63fbc2e8ad285 100644
--- a/tests/src/integration_test_rendering.cpp
+++ b/tests/src/integration_test_rendering.cpp
@@ -26,7 +26,7 @@
 
 #include "catch/catch.hpp"
 
-#include "phx/display_system.hpp"
+#include "phx/display_system_window.hpp"
 #include "phx/frame_timer.hpp"
 #include "phx/mesh.hpp"
 #include "phx/mesh_handle.hpp"
@@ -87,7 +87,7 @@ void CreateTestTriangleComponent(phx::Entity* triangle) {
   mesh_proxy->Load();
 
   phx::MeshHandle* mesh_handle = triangle->AddComponent<phx::MeshHandle>();
-  mesh_handle->SetMeshProxy(mesh_proxy);
+  mesh_handle->SetMesh(phx::ResourcePointer<phx::Mesh>(mesh_proxy));
 }
 
 SCENARIO("We can render a simple triangle", "[phx][phx::Rendering]") {
@@ -95,7 +95,7 @@ SCENARIO("We can render a simple triangle", "[phx][phx::Rendering]") {
   GIVEN("A complete triangle") {
     std::unique_ptr<phx::Engine> engine = phx::Setup::CreateDefaultEngine();
     auto rendering_system = engine->GetSystem<phx::RenderingSystem>();
-    auto display_system = engine->GetSystem<phx::DisplaySystem>();
+    auto display_system = engine->GetSystem<phx::DisplaySystemWindow>();
     auto scene = engine->GetScene();
 
     SetupLightAndCamera(scene.get());
@@ -114,7 +114,8 @@ SCENARIO("We can render a simple triangle", "[phx][phx::Rendering]") {
     phx::Transform* transform = triangle->AddComponent<phx::Transform>();
     phx::MaterialHandle* material_handle =
         triangle->AddComponent<phx::MaterialHandle>();
-    material_handle->SetMaterialProxy(material_proxy);
+    material_handle->SetMaterial(
+        phx::ResourcePointer<phx::Material>(material_proxy));
 
     WHEN("We render the scene") {
       rendering_system->Update(phx::FrameTimer::TimeInfo{});
@@ -137,7 +138,7 @@ SCENARIO("If no material given a default red one is taken.",
   GIVEN("A triangle without material") {
     std::unique_ptr<phx::Engine> engine = phx::Setup::CreateDefaultEngine();
     auto rendering_system = engine->GetSystem<phx::RenderingSystem>();
-    auto display_system = engine->GetSystem<phx::DisplaySystem>();
+    auto display_system = engine->GetSystem<phx::DisplaySystemWindow>();
     auto scene = engine->GetScene();
 
     SetupLightAndCamera(scene.get());
diff --git a/tests/src/mocks/openvr_mock.hpp b/tests/src/mocks/openvr_mock.hpp
index 89ecec4ee202166ee92d3cf35ac315b825a7f496..77881d7054b6d4a82e1777140ec2b34724e70a8c 100644
--- a/tests/src/mocks/openvr_mock.hpp
+++ b/tests/src/mocks/openvr_mock.hpp
@@ -39,11 +39,11 @@ using trompeloeil::_;
 class OPENVR_MOCK_EXPORT OpenVRMockInternal {
  public:
   MAKE_MOCK0(VR_IsHmdPresent, bool());
-  MAKE_MOCK2(VR_GetGenericInterface, void*(const char*, vr::EVRInitError*));
-  MAKE_MOCK3(VR_InitInternal2,
-             uint32_t(vr::EVRInitError*, vr::EVRApplicationType, const char*));
+  MAKE_MOCK2(VR_GetGenericInterface, void *(const char *, vr::EVRInitError *));
+  MAKE_MOCK3(VR_InitInternal2, uint32_t(vr::EVRInitError *,
+                                        vr::EVRApplicationType, const char *));
   MAKE_MOCK0(VR_ShutdownInternal, void());
-  MAKE_MOCK1(VR_IsInterfaceVersionValid, bool(const char*));
+  MAKE_MOCK1(VR_IsInterfaceVersionValid, bool(const char *));
   MAKE_MOCK0(VR_GetInitToken, uint32_t());
 };
 
@@ -52,30 +52,31 @@ namespace vr {
 class OPENVR_MOCK_EXPORT IVRSystemMock : public IVRSystem {
  public:
   virtual ~IVRSystemMock() = default;
-  MAKE_MOCK2(GetRecommendedRenderTargetSize, void(uint32_t*, uint32_t*));
-  MAKE_MOCK5(GetProjectionRaw, void(EVREye, float*, float*, float*, float*));
+  MAKE_MOCK2(GetRecommendedRenderTargetSize, void(uint32_t *, uint32_t *));
+  MAKE_MOCK5(GetProjectionRaw,
+             void(EVREye, float *, float *, float *, float *));
   MAKE_MOCK4(ComputeDistortion,
-             bool(EVREye, float, float, DistortionCoordinates_t*));
-  MAKE_MOCK2(GetTimeSinceLastVsync, bool(float*, uint64_t*));
+             bool(EVREye, float, float, DistortionCoordinates_t *));
+  MAKE_MOCK2(GetTimeSinceLastVsync, bool(float *, uint64_t *));
   MAKE_MOCK0(GetD3D9AdapterIndex, int32_t());
-  MAKE_MOCK1(GetDXGIOutputInfo, void(int32_t*));
-  MAKE_MOCK3(GetOutputDevice, void(uint64_t*, ETextureType, VkInstance_T*));
+  MAKE_MOCK1(GetDXGIOutputInfo, void(int32_t *));
+  MAKE_MOCK3(GetOutputDevice, void(uint64_t *, ETextureType, VkInstance_T *));
   MAKE_MOCK0(IsDisplayOnDesktop, bool());
   MAKE_MOCK1(SetDisplayVisibility, bool(bool));
   MAKE_MOCK4(GetDeviceToAbsoluteTrackingPose,
-             void(ETrackingUniverseOrigin, float, TrackedDevicePose_t*,
+             void(ETrackingUniverseOrigin, float, TrackedDevicePose_t *,
                   uint32_t));
   MAKE_MOCK0(ResetSeatedZeroPose, void());
   MAKE_MOCK0(GetSeatedZeroPoseToStandingAbsoluteTrackingPose, HmdMatrix34_t());
   MAKE_MOCK0(GetRawZeroPoseToStandingAbsoluteTrackingPose, HmdMatrix34_t());
   MAKE_MOCK4(GetSortedTrackedDeviceIndicesOfClass,
-             uint32_t(ETrackedDeviceClass, TrackedDeviceIndex_t*, uint32_t,
+             uint32_t(ETrackedDeviceClass, TrackedDeviceIndex_t *, uint32_t,
                       TrackedDeviceIndex_t));
   MAKE_MOCK1(GetTrackedDeviceActivityLevel,
              EDeviceActivityLevel(TrackedDeviceIndex_t));
   MAKE_MOCK3(ApplyTransform,
-             void(TrackedDevicePose_t*, const TrackedDevicePose_t*,
-                  const HmdMatrix34_t*));
+             void(TrackedDevicePose_t *, const TrackedDevicePose_t *,
+                  const HmdMatrix34_t *));
   MAKE_MOCK1(GetTrackedDeviceIndexForControllerRole,
              TrackedDeviceIndex_t(vr::ETrackedControllerRole));
   MAKE_MOCK1(GetControllerRoleForTrackedDeviceIndex,
@@ -85,43 +86,43 @@ class OPENVR_MOCK_EXPORT IVRSystemMock : public IVRSystem {
   MAKE_MOCK1(IsTrackedDeviceConnected, bool(vr::TrackedDeviceIndex_t));
   MAKE_MOCK3(GetBoolTrackedDeviceProperty,
              bool(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
-                  ETrackedPropertyError*));
+                  ETrackedPropertyError *));
   MAKE_MOCK3(GetFloatTrackedDeviceProperty,
              float(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
-                   ETrackedPropertyError*));
+                   ETrackedPropertyError *));
   MAKE_MOCK3(GetInt32TrackedDeviceProperty,
              int32_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
-                     ETrackedPropertyError*));
+                     ETrackedPropertyError *));
   MAKE_MOCK3(GetUint64TrackedDeviceProperty,
              uint64_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
-                      ETrackedPropertyError*));
+                      ETrackedPropertyError *));
   MAKE_MOCK3(GetMatrix34TrackedDeviceProperty,
              HmdMatrix34_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
-                           ETrackedPropertyError*));
+                           ETrackedPropertyError *));
   MAKE_MOCK5(GetStringTrackedDeviceProperty,
-             uint32_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty, char*,
-                      uint32_t, ETrackedPropertyError*));
-  MAKE_MOCK1(GetPropErrorNameFromEnum, const char*(ETrackedPropertyError));
-  MAKE_MOCK2(PollNextEvent, bool(VREvent_t*, uint32_t));
-  MAKE_MOCK4(PollNextEventWithPose, bool(ETrackingUniverseOrigin, VREvent_t*,
-                                         uint32_t, vr::TrackedDevicePose_t*));
-  MAKE_MOCK1(GetEventTypeNameFromEnum, const char*(EVREventType));
+             uint32_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty, char *,
+                      uint32_t, ETrackedPropertyError *));
+  MAKE_MOCK1(GetPropErrorNameFromEnum, const char *(ETrackedPropertyError));
+  MAKE_MOCK2(PollNextEvent, bool(VREvent_t *, uint32_t));
+  MAKE_MOCK4(PollNextEventWithPose, bool(ETrackingUniverseOrigin, VREvent_t *,
+                                         uint32_t, vr::TrackedDevicePose_t *));
+  MAKE_MOCK1(GetEventTypeNameFromEnum, const char *(EVREventType));
   MAKE_MOCK2(GetHiddenAreaMesh, HiddenAreaMesh_t(EVREye, EHiddenAreaMeshType));
   MAKE_MOCK3(GetControllerState, bool(vr::TrackedDeviceIndex_t,
-                                      vr::VRControllerState_t*, uint32_t));
+                                      vr::VRControllerState_t *, uint32_t));
   MAKE_MOCK5(GetControllerStateWithPose,
              bool(ETrackingUniverseOrigin, vr::TrackedDeviceIndex_t,
-                  vr::VRControllerState_t*, uint32_t, TrackedDevicePose_t*));
+                  vr::VRControllerState_t *, uint32_t, TrackedDevicePose_t *));
   MAKE_MOCK3(TriggerHapticPulse,
              void(vr::TrackedDeviceIndex_t, uint32_t, unsigned short));
-  MAKE_MOCK1(GetButtonIdNameFromEnum, const char*(EVRButtonId));
+  MAKE_MOCK1(GetButtonIdNameFromEnum, const char *(EVRButtonId));
   MAKE_MOCK1(GetControllerAxisTypeNameFromEnum,
-             const char*(EVRControllerAxisType));
+             const char *(EVRControllerAxisType));
   MAKE_MOCK0(CaptureInputFocus, bool());
   MAKE_MOCK0(ReleaseInputFocus, void());
   MAKE_MOCK0(IsInputFocusCapturedByAnotherProcess, bool());
-  MAKE_MOCK4(DriverDebugRequest,
-             uint32_t(vr::TrackedDeviceIndex_t, const char*, char*, uint32_t));
+  MAKE_MOCK4(DriverDebugRequest, uint32_t(vr::TrackedDeviceIndex_t,
+                                          const char *, char *, uint32_t));
   MAKE_MOCK1(PerformFirmwareUpdate,
              vr::EVRFirmwareError(vr::TrackedDeviceIndex_t));
   MAKE_MOCK0(AcknowledgeQuit_Exiting, void());
@@ -130,9 +131,9 @@ class OPENVR_MOCK_EXPORT IVRSystemMock : public IVRSystem {
   // somehow returning structs is a problem, so this workaround
   // TODO(WJ): should be reworked once this is solved in trompeloeil
   // https://github.com/rollbear/trompeloeil/issues/69
-  MAKE_MOCK3(GetProjectionMatrixArray, float*(vr::EVREye, float, float));
+  MAKE_MOCK3(GetProjectionMatrixArray, float *(vr::EVREye, float, float));
   vr::HmdMatrix44_t GetProjectionMatrix(vr::EVREye, float, float);
-  MAKE_MOCK1(GetEyeToHeadTransformArray, float*(EVREye));
+  MAKE_MOCK1(GetEyeToHeadTransformArray, float *(EVREye));
   HmdMatrix34_t GetEyeToHeadTransform(EVREye);
 };
 
@@ -140,27 +141,28 @@ class OPENVR_MOCK_EXPORT IVRCompositorMock : public IVRCompositor {
  public:
   MAKE_MOCK1(SetTrackingSpace, void(ETrackingUniverseOrigin));
   MAKE_MOCK0(GetTrackingSpace, ETrackingUniverseOrigin());
-  MAKE_MOCK4(WaitGetPoses, EVRCompositorError(TrackedDevicePose_t*, uint32_t,
-                                              TrackedDevicePose_t*, uint32_t));
-  MAKE_MOCK4(GetLastPoses, EVRCompositorError(TrackedDevicePose_t*, uint32_t,
-                                              TrackedDevicePose_t*, uint32_t));
+  MAKE_MOCK4(WaitGetPoses, EVRCompositorError(TrackedDevicePose_t *, uint32_t,
+                                              TrackedDevicePose_t *, uint32_t));
+  MAKE_MOCK4(GetLastPoses, EVRCompositorError(TrackedDevicePose_t *, uint32_t,
+                                              TrackedDevicePose_t *, uint32_t));
   MAKE_MOCK3(GetLastPoseForTrackedDeviceIndex,
-             EVRCompositorError(TrackedDeviceIndex_t, TrackedDevicePose_t*,
-                                TrackedDevicePose_t*));
+             EVRCompositorError(TrackedDeviceIndex_t, TrackedDevicePose_t *,
+                                TrackedDevicePose_t *));
   MAKE_MOCK4(Submit,
-             EVRCompositorError(EVREye, const Texture_t*,
-                                const VRTextureBounds_t*, EVRSubmitFlags));
+             EVRCompositorError(EVREye, const Texture_t *,
+                                const VRTextureBounds_t *, EVRSubmitFlags));
   MAKE_MOCK0(ClearLastSubmittedFrame, void());
   MAKE_MOCK0(PostPresentHandoff, void());
-  MAKE_MOCK2(GetFrameTiming, bool(Compositor_FrameTiming*, uint32_t));
-  MAKE_MOCK2(GetFrameTimings, uint32_t(Compositor_FrameTiming*, uint32_t));
+  MAKE_MOCK2(GetFrameTiming, bool(Compositor_FrameTiming *, uint32_t));
+  MAKE_MOCK2(GetFrameTimings, uint32_t(Compositor_FrameTiming *, uint32_t));
   MAKE_MOCK0(GetFrameTimeRemaining, float());
-  MAKE_MOCK2(GetCumulativeStats, void(Compositor_CumulativeStats*, uint32_t));
+  MAKE_MOCK2(GetCumulativeStats, void(Compositor_CumulativeStats *, uint32_t));
   MAKE_MOCK6(FadeToColor, void(float, float, float, float, float, bool));
   MAKE_MOCK1(GetCurrentFadeColor, HmdColor_t(bool));
   MAKE_MOCK2(FadeGrid, void(float, bool));
   MAKE_MOCK0(GetCurrentGridAlpha, float());
-  MAKE_MOCK2(SetSkyboxOverride, EVRCompositorError(const Texture_t*, uint32_t));
+  MAKE_MOCK2(SetSkyboxOverride,
+             EVRCompositorError(const Texture_t *, uint32_t));
   MAKE_MOCK0(ClearSkyboxOverride, void());
   MAKE_MOCK0(CompositorBringToFront, void());
   MAKE_MOCK0(CompositorGoToBack, void());
@@ -178,22 +180,62 @@ class OPENVR_MOCK_EXPORT IVRCompositorMock : public IVRCompositor {
   MAKE_MOCK0(ForceReconnectProcess, void());
   MAKE_MOCK1(SuspendRendering, void(bool));
   MAKE_MOCK3(GetMirrorTextureD3D11,
-             EVRCompositorError(vr::EVREye, void*, void**));
-  MAKE_MOCK1(ReleaseMirrorTextureD3D11, void(void*));
+             EVRCompositorError(vr::EVREye, void *, void **));
+  MAKE_MOCK1(ReleaseMirrorTextureD3D11, void(void *));
   MAKE_MOCK3(GetMirrorTextureGL,
-             vr::EVRCompositorError(vr::EVREye, vr::glUInt_t*,
-                                    vr::glSharedTextureHandle_t*));
+             vr::EVRCompositorError(vr::EVREye, vr::glUInt_t *,
+                                    vr::glSharedTextureHandle_t *));
   MAKE_MOCK2(ReleaseSharedGLTexture,
              bool(vr::glUInt_t, vr::glSharedTextureHandle_t));
   MAKE_MOCK1(LockGLSharedTextureForAccess, void(vr::glSharedTextureHandle_t));
   MAKE_MOCK1(UnlockGLSharedTextureForAccess, void(vr::glSharedTextureHandle_t));
-  MAKE_MOCK2(GetVulkanInstanceExtensionsRequired, uint32_t(char*, uint32_t));
+  MAKE_MOCK2(GetVulkanInstanceExtensionsRequired, uint32_t(char *, uint32_t));
   MAKE_MOCK3(GetVulkanDeviceExtensionsRequired,
-             uint32_t(VkPhysicalDevice_T*, char*, uint32_t));
+             uint32_t(VkPhysicalDevice_T *, char *, uint32_t));
   MAKE_MOCK1(SetExplicitTimingMode, void(bool));
   MAKE_MOCK0(SubmitExplicitTimingData, EVRCompositorError());
 };
 
+class OPENVR_MOCK_EXPORT IVRRenderModelsMock : public IVRRenderModels {
+ public:
+  MAKE_MOCK2(LoadRenderModel_Async,
+             EVRRenderModelError(const char *, RenderModel_t **));
+  MAKE_MOCK1(FreeRenderModel, void(RenderModel_t *));
+  MAKE_MOCK2(LoadTexture_Async,
+             EVRRenderModelError(TextureID_t, RenderModel_TextureMap_t **));
+  MAKE_MOCK1(FreeTexture, void(RenderModel_TextureMap_t *));
+  MAKE_MOCK3(LoadTextureD3D11_Async,
+             EVRRenderModelError(TextureID_t, void *, void **));
+  MAKE_MOCK2(LoadIntoTextureD3D11_Async,
+             EVRRenderModelError(TextureID_t, void *));
+  MAKE_MOCK1(FreeTextureD3D11, void(void *));
+  MAKE_MOCK3(GetRenderModelName,
+             uint32_t(uint32_t, VR_OUT_STRING() char *, uint32_t));
+  MAKE_MOCK0(GetRenderModelCount, uint32_t());
+  MAKE_MOCK1(GetComponentCount, uint32_t(const char *));
+  MAKE_MOCK4(GetComponentName, uint32_t(const char *, uint32_t,
+                                        VR_OUT_STRING() char *, uint32_t));
+
+  MAKE_MOCK2(GetComponentButtonMask, uint64_t(const char *, const char *));
+  MAKE_MOCK4(GetComponentRenderModelName,
+             uint32_t(const char *, const char *, VR_OUT_STRING() char *,
+                      uint32_t));
+  MAKE_MOCK5(GetComponentState,
+             bool(const char *, const char *, const vr::VRControllerState_t *,
+                  const RenderModel_ControllerMode_State_t *,
+                  RenderModel_ComponentState_t *));
+
+  MAKE_MOCK2(RenderModelHasComponent, bool(const char *, const char *));
+  MAKE_MOCK4(GetRenderModelThumbnailURL,
+             uint32_t(const char *, VR_OUT_STRING() char *, uint32_t,
+                      vr::EVRRenderModelError *));
+  MAKE_MOCK4(GetRenderModelOriginalPath,
+             uint32_t(const char *, VR_OUT_STRING() char *, uint32_t,
+                      vr::EVRRenderModelError *));
+  MAKE_MOCK1(GetRenderModelErrorNameFromEnum,
+             const char *(vr::EVRRenderModelError));
+};
+
 }  // namespace vr
 
 class OPENVR_MOCK_EXPORT OpenVRMock {
@@ -201,7 +243,8 @@ class OPENVR_MOCK_EXPORT OpenVRMock {
   OpenVRMock()
       : mock_(new OpenVRMockInternal),
         ivr_system_mock_(new vr::IVRSystemMock),
-        ivr_compositor_mock_(new vr::IVRCompositorMock) {}
+        ivr_compositor_mock_(new vr::IVRCompositorMock),
+        ivr_render_models_mock_(new vr::IVRRenderModelsMock) {}
   ~OpenVRMock() {
     // We have to leak the mock_ pointer for the time being.
     // see
@@ -209,9 +252,35 @@ class OPENVR_MOCK_EXPORT OpenVRMock {
     // TODO(@tvierjahn) regularly check progress on this issue
   }
 
-  OpenVRMockInternal& Get() { return *mock_; }
-  vr::IVRSystemMock& GetSystem() const { return *ivr_system_mock_; }
-  vr::IVRCompositorMock& GetCompositor() { return *ivr_compositor_mock_; }
+  OpenVRMockInternal &Get() { return *mock_; }
+  vr::IVRSystemMock &GetSystem() const { return *ivr_system_mock_; }
+  vr::IVRCompositorMock &GetCompositor() { return *ivr_compositor_mock_; }
+  vr::IVRRenderModelsMock &GetRenderModels() {
+    return *ivr_render_models_mock_;
+  }
+
+  static vr::RenderModel_t *CreateDummyTriangleModel() {
+    vr::RenderModel_t *model = new vr::RenderModel_t();
+    model->rIndexData = new uint16_t[3]{0, 1, 2};
+    model->unVertexCount = 3;
+    model->unTriangleCount = 1;
+    model->diffuseTextureId = -1;
+
+    vr::RenderModel_Vertex_t vertex1;
+    vertex1.vPosition = {{-0.1f, -0.1f, 0.f}};
+    vertex1.vNormal = {{0.f, 0.f, 1.f}};
+    vertex1.rfTextureCoord[0] = 0.f;
+    vertex1.rfTextureCoord[1] = 0.f;
+    vr::RenderModel_Vertex_t vertex2 = vertex1;
+    vertex2.vPosition = {{+0.1f, -0.1f, 0.f}};
+    vr::RenderModel_Vertex_t vertex3 = vertex1;
+    vertex2.vPosition = {{0.f, +0.1f, 0.f}};
+
+    model->rVertexData =
+        new vr::RenderModel_Vertex_t[3]{vertex1, vertex2, vertex3};
+
+    return model;
+  }
 
   static vr::HmdMatrix44_t toHMDMatrix44_t(float mat[16]);
   static vr::HmdMatrix34_t toHMDMatrix34_t(float mat[12]);
@@ -229,9 +298,10 @@ class OPENVR_MOCK_EXPORT OpenVRMock {
                                     0.0f, 1.8f, 0.0f, 0.0f, 1.0f, 0.0f};
 
  private:
-  OpenVRMockInternal* mock_;
-  vr::IVRSystemMock* ivr_system_mock_;
-  vr::IVRCompositorMock* ivr_compositor_mock_;
+  OpenVRMockInternal *mock_;
+  vr::IVRSystemMock *ivr_system_mock_;
+  vr::IVRCompositorMock *ivr_compositor_mock_;
+  vr::IVRRenderModelsMock *ivr_render_models_mock_;
 };
 
 extern OPENVR_MOCK_EXPORT OpenVRMock openvr_mock;
@@ -251,12 +321,14 @@ extern OPENVR_MOCK_EXPORT OpenVRMock openvr_mock;
       .RETURN(openvr_mock.eye_to_head_right_);                               \
   ALLOW_CALL(openvr_mock.GetSystem(),                                        \
              GetSortedTrackedDeviceIndicesOfClass(_, _, _, _))               \
-      .RETURN(0u);                                                           \
+      .RETURN(2u)                                                            \
+      .SIDE_EFFECT(*_2 = 0u)                                                 \
+      .SIDE_EFFECT(*(_2 + sizeof(vr::TrackedDeviceIndex_t)) = 1u);           \
   ALLOW_CALL(openvr_mock.GetSystem(),                                        \
-             GetControllerRoleForTrackedDeviceIndex(_))                      \
+             GetControllerRoleForTrackedDeviceIndex(0u))                     \
       .RETURN(vr::TrackedControllerRole_LeftHand);                           \
   ALLOW_CALL(openvr_mock.GetSystem(),                                        \
-             GetControllerRoleForTrackedDeviceIndex(_))                      \
+             GetControllerRoleForTrackedDeviceIndex(1u))                     \
       .RETURN(vr::TrackedControllerRole_RightHand);                          \
   ALLOW_CALL(openvr_mock.GetCompositor(), WaitGetPoses(_, _, _, _))          \
       .RETURN(vr::EVRCompositorError::VRCompositorError_None)                \
@@ -268,16 +340,28 @@ extern OPENVR_MOCK_EXPORT OpenVRMock openvr_mock;
       .RETURN(vr::EVRCompositorError::VRCompositorError_None);               \
   ALLOW_CALL(openvr_mock.Get(), VR_GetGenericInterface(_, _))                \
       .WITH(std::string(vr::IVRSystem_Version) == std::string(_1))           \
-      .RETURN(static_cast<void*>(&openvr_mock.GetSystem()));                 \
+      .RETURN(static_cast<void *>(&openvr_mock.GetSystem()));                \
+  ALLOW_CALL(openvr_mock.Get(), VR_GetGenericInterface(_, _))                \
+      .WITH(std::string(vr::IVRRenderModels_Version) == std::string(_1))     \
+      .RETURN(static_cast<void *>(&openvr_mock.GetRenderModels()));          \
   ALLOW_CALL(openvr_mock.Get(), VR_GetGenericInterface(_, _))                \
       .WITH(std::string(vr::IVRCompositor_Version) == std::string(_1))       \
-      .RETURN(static_cast<void*>(&openvr_mock.GetCompositor()));             \
+      .RETURN(static_cast<void *>(&openvr_mock.GetCompositor()));            \
   ALLOW_CALL(openvr_mock.Get(),                                              \
              VR_InitInternal2(_, vr::VRApplication_Scene, _))                \
       .RETURN(static_cast<uint32_t>(1337))                                   \
       .SIDE_EFFECT(*_1 = vr::VRInitError_None);                              \
   ALLOW_CALL(openvr_mock.Get(), VR_ShutdownInternal());                      \
   ALLOW_CALL(openvr_mock.Get(), VR_IsInterfaceVersionValid(_)).RETURN(true); \
-  ALLOW_CALL(openvr_mock.Get(), VR_GetInitToken()).RETURN(1337);
+  ALLOW_CALL(openvr_mock.Get(), VR_GetInitToken()).RETURN(1337);             \
+  ALLOW_CALL(openvr_mock.GetRenderModels(), LoadRenderModel_Async(_, _))     \
+      .RETURN(vr::VRRenderModelError_None)                                   \
+      .SIDE_EFFECT(*_2 = openvr_mock.CreateDummyTriangleModel());            \
+  ALLOW_CALL(openvr_mock.GetSystem(),                                        \
+             GetStringTrackedDeviceProperty(_, _, _, _, _))                  \
+      .RETURN(0);                                                            \
+  ALLOW_CALL(openvr_mock.GetRenderModels(), LoadTexture_Async(_, _))         \
+      .RETURN(vr::VRRenderModelError_None)                                   \
+      .SIDE_EFFECT(*_2 = nullptr);
 
 #endif  // TESTS_SRC_MOCKS_OPENVR_MOCK_HPP_
diff --git a/tests/src/mocks/sdl_mock.cpp b/tests/src/mocks/sdl_mock.cpp
index 702b3d6bd8eadbc6d6510b3905a0df1e749db600..919ae46a7ece937b40f6c97ad5ccd936b21b35cb 100644
--- a/tests/src/mocks/sdl_mock.cpp
+++ b/tests/src/mocks/sdl_mock.cpp
@@ -76,4 +76,10 @@ void SDL_GetWindowSize(SDL_Window* window, int* w, int* h) {
 int SDL_GL_SetSwapInterval(int interval) {
   return sdl_mock.Get().SDL_GL_SetSwapInterval(interval);
 }
+void SDL_ShowWindow(SDL_Window* window) {
+  sdl_mock.Get().SDL_ShowWindow(window);
+}
+void SDL_HideWindow(SDL_Window* window) {
+  sdl_mock.Get().SDL_HideWindow(window);
+}
 }
diff --git a/tests/src/mocks/sdl_mock.hpp b/tests/src/mocks/sdl_mock.hpp
index ee35b1f2ac01a8832277899f4b23a88fffca6d71..3faddfd628ae9facd6a4096e641a865ff89dd94d 100644
--- a/tests/src/mocks/sdl_mock.hpp
+++ b/tests/src/mocks/sdl_mock.hpp
@@ -49,6 +49,8 @@ class SdlMockInternal {
   MAKE_MOCK1(SDL_PollEvent, int(SDL_Event*));  // NOLINT(readability/casting)
   MAKE_MOCK3(SDL_GetWindowSize, void(SDL_Window*, int*, int*));
   MAKE_MOCK1(SDL_GL_SetSwapInterval, int(int));
+  MAKE_MOCK1(SDL_ShowWindow, void(SDL_Window*));
+  MAKE_MOCK1(SDL_HideWindow, void(SDL_Window*));
 };
 
 class SdlMock {
@@ -88,6 +90,8 @@ extern SdlMock sdl_mock;
   ALLOW_CALL(sdl_mock.Get(), SDL_GL_SwapWindow(ne(nullptr)));                \
   ALLOW_CALL(sdl_mock.Get(), SDL_GetWindowSize(ne(nullptr), _, _));          \
   ALLOW_CALL(sdl_mock.Get(), SDL_GL_SetSwapInterval(_)).RETURN(0);           \
-  ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)).RETURN(0);
+  ALLOW_CALL(sdl_mock.Get(), SDL_PollEvent(_)).RETURN(0);                    \
+  ALLOW_CALL(sdl_mock.Get(), SDL_ShowWindow(_));                             \
+  ALLOW_CALL(sdl_mock.Get(), SDL_HideWindow(_));
 
 #endif  // TESTS_SRC_MOCKS_SDL_MOCK_HPP_
diff --git a/tests/src/test-transform.cpp b/tests/src/test-transform.cpp
index 24d01a7eb2b411d5956267f2415e8275ef4ac2af..f9cc4cd768ca728876390516071144d790209032 100644
--- a/tests/src/test-transform.cpp
+++ b/tests/src/test-transform.cpp
@@ -554,27 +554,5 @@ SCENARIO("The transform component checks if its parent is in the same scene.",
         }
       }
     }
-
-    GIVEN("A transform t4 without a scene.") {
-      phx::Transform t4;
-
-      WHEN("We set t4 to be the parent of t1.") {
-        auto log_capture = std::make_shared<test_utilities::LogCapture>();
-        phx::logger =
-            std::make_shared<spdlog::logger>("logcapture", log_capture);
-        phx::logger->set_pattern("%v");
-
-        t1->SetParent(&t4);
-        THEN("An error is logged.") {
-          REQUIRE(*log_capture ==
-                  "The transform to be set as parent is not within the same "
-                  "scene.");
-        }
-        THEN("t4 is not the parent of t1.") {
-          REQUIRE(t1->GetParent() != &t4);
-          REQUIRE(t4.GetChildCount() == 0);
-        }
-      }
-    }
   }
 }
diff --git a/tests/src/test_assimp_loader.cpp b/tests/src/test_assimp_loader.cpp
index e143adb324cb38808c92fa9d68f35eabac6d5173..1855a8b7361992e9c8e559e232e8e263b12960b7 100644
--- a/tests/src/test_assimp_loader.cpp
+++ b/tests/src/test_assimp_loader.cpp
@@ -54,7 +54,7 @@ SCENARIO("The assimp loader loads models using the Assimp library.",
     TestLogger test_logger;
 
     WHEN("We load an invalid file") {
-      phx::ResourceUtils::LoadResourceFromFile("invalid.obj");
+      phx::ResourceUtils::LoadResourceFromFile<phx::Mesh>("invalid.obj");
 
       THEN("We get an error message printed to the console.") {
         std::string captured_message = test_logger.GetCapture()->ToString();
@@ -65,9 +65,9 @@ SCENARIO("The assimp loader loads models using the Assimp library.",
       }
     }
     WHEN("We load the stanford bunny.") {
-      auto resource_proxy = phx::ResourceUtils::LoadResourceFromFile(
+      auto resource = phx::ResourceUtils::LoadResourceFromFile<phx::Mesh>(
           "models/bunny.obj", {{"mesh_index", 0}});
-      auto mesh = dynamic_cast<phx::Mesh*>(resource_proxy->GetAs<phx::Mesh>());
+      auto mesh = resource.Get();
 
       THEN("there is a mesh") {
         REQUIRE(mesh != nullptr);
diff --git a/tests/src/test_display_system.cpp b/tests/src/test_display_system.cpp
index 5c7e6b07219fc8858c4c319cd2e456f06c833d2a..97135366aa074c6ed2dcc0d869125bbe2e3eb3b4 100644
--- a/tests/src/test_display_system.cpp
+++ b/tests/src/test_display_system.cpp
@@ -29,7 +29,7 @@
 
 #include "mocks/sdl_mock.hpp"
 
-#include "phx/display_system.hpp"
+#include "phx/display_system_window.hpp"
 #include "phx/logger.hpp"
 #include "phx/window.hpp"
 
@@ -53,8 +53,8 @@ SCENARIO(
       REQUIRE_CALL(sdl_mock.Get(), SDL_VideoInit(nullptr)).RETURN(0);
       REQUIRE_CALL(sdl_mock.Get(), SDL_VideoQuit());
       phx::Engine engine;
-      phx::DisplaySystem* displaySystem =
-          engine.CreateSystem<phx::DisplaySystem>();
+      phx::DisplaySystemWindow* displaySystem =
+          engine.CreateSystem<phx::DisplaySystemWindow>();
 
       WHEN("We create a window.") {
         THEN("The window is created.") {
diff --git a/tests/src/test_engine.cpp b/tests/src/test_engine.cpp
index 3256e671385c5be1d8f79da1df7c43b876786ea3..f8a7baf5c5e313fd405ed9ca22895433af8bfaad 100644
--- a/tests/src/test_engine.cpp
+++ b/tests/src/test_engine.cpp
@@ -22,12 +22,14 @@
 
 #include <chrono>
 #include <memory>
+#include <string>
 #include <thread>
+#include <vector>
 
 #include "catch/catch.hpp"
 
 #include "phx/behavior.hpp"
-#include "phx/display_system.hpp"
+#include "phx/display_system_window.hpp"
 #include "phx/engine.hpp"
 #include "phx/input_system.hpp"
 #include "phx/logger.hpp"
@@ -39,11 +41,9 @@
 
 #include "trompeloeil.hpp"
 
-SUPPRESS_WARNINGS_BEGIN
 #include "mocks/openvr_mock.hpp"
-SUPPRESS_WARNINGS_END
-#include "mocks/sdl_mock.hpp"
 #include "mocks/opengl_mock.hpp"
+#include "mocks/sdl_mock.hpp"
 
 using trompeloeil::_;
 using trompeloeil::ne;
@@ -52,7 +52,7 @@ extern template struct trompeloeil::reporter<trompeloeil::specialized>;
 
 class TimeTrackerSystem : public phx::System {
  public:
-  explicit TimeTrackerSystem(phx::Engine* engine) : System(engine) {}
+  explicit TimeTrackerSystem(phx::Engine* engine) : phx::System(engine) {}
 
   void Update(const phx::FrameTimer::TimeInfo& time_info) override {
     time_info_ = &time_info;
@@ -64,7 +64,7 @@ class TimeTrackerSystem : public phx::System {
 class EngineStopTestSystem : public phx::System {
  public:
   explicit EngineStopTestSystem(phx::Engine* engine, int stop_in_frame = 1)
-      : System(engine), stop_on_update_(stop_in_frame) {}
+      : phx::System(engine), stop_on_update_(stop_in_frame) {}
 
   void Update(const phx::FrameTimer::TimeInfo& time_info) override {
     update_counter_++;
@@ -83,13 +83,31 @@ class EngineStopTestSystem : public phx::System {
 
 class WaitSystem : public phx::System {
  public:
-  explicit WaitSystem(phx::Engine* engine) : System(engine) {}
+  explicit WaitSystem(phx::Engine* engine) : phx::System(engine) {}
   void Update(const phx::FrameTimer::TimeInfo&) override {
     std::this_thread::sleep_for(std::chrono::milliseconds(5));
   }
 };
 
-class AnyBehavior : public phx::Behavior {};
+template <typename T>
+class TestOrderSystem : public phx::System {
+ public:
+  explicit TestOrderSystem(phx::Engine* engine) : phx::System(engine) {}
+  void Update(const phx::FrameTimer::TimeInfo&) override {
+    if (call_on_update_ != nullptr) call_on_update_();
+  }
+
+  void SetCallbackOnUpdate(const std::function<void(void)>& callback) {
+    call_on_update_ = callback;
+  }
+
+ private:
+  std::function<void(void)> call_on_update_;
+};
+
+class AnyBehavior : public phx::Behavior {
+  void OnUpdate() override{};
+};
 
 SCENARIO("Only one engine should be created", "[phx][phx::Engine]") {
   auto log_capture = std::make_shared<test_utilities::LogCapture>();
@@ -131,6 +149,15 @@ SCENARIO("An engine is a container of systems.", "[phx][phx::Engine]") {
             REQUIRE(engine.GetSystem<EngineStopTestSystem>() == nullptr);
           }
         }
+
+        WHEN("We add another test system") {
+          engine.CreateSystem<EngineStopTestSystem>();
+          THEN("It contains two test systems") {
+            std::vector<EngineStopTestSystem*> systems =
+                engine.GetSystems<EngineStopTestSystem>();
+            REQUIRE(systems.size() == 2);
+          }
+        }
       }
     }
 
@@ -158,11 +185,26 @@ SCENARIO("The active scene in an engine can be switched",
   GIVEN("An engine") {
     phx::Engine engine;
     auto first_scene = std::make_shared<phx::Scene>();
+
+    // setup a way to test the scene changed signal
+    phx::Scene* s1;
+    phx::Scene* s2;
+    engine.AddSceneChangedCallback(
+        [&s1, &s2](std::shared_ptr<phx::Scene> param_s1,
+                   std::shared_ptr<phx::Scene> param_s2) {
+          s1 = param_s1.get();
+          s2 = param_s2.get();
+        });
+
     engine.SetScene(first_scene);
     THEN("It has a scene") {
       REQUIRE(engine.GetScene() != nullptr);
       REQUIRE(engine.GetScene()->GetEngine() == &engine);
     }
+    THEN("The old scene is nullptr.") { REQUIRE(s1 == nullptr); }
+    THEN("The new scene is the one we just set.") {
+      REQUIRE(s2 == first_scene.get());
+    }
     WHEN("The scene is exchanged for a new scene") {
       auto new_scene = std::make_shared<phx::Scene>();
       engine.SetScene(new_scene);
@@ -175,6 +217,10 @@ SCENARIO("The active scene in an engine can be switched",
 
         REQUIRE(first_scene->GetEngine() == nullptr);
       }
+      THEN("The signal is triggered with the appropriate values.") {
+        REQUIRE(s1 == first_scene.get());
+        REQUIRE(s2 == new_scene.get());
+      }
     }
   }
 }
@@ -288,7 +334,8 @@ SCENARIO("An engine can be setup by the default setup", "[phx][phx::Engine]") {
       THEN("It is not null") {
         REQUIRE(engine != nullptr);
         THEN("It has a window") {
-          auto window = engine->GetSystem<phx::DisplaySystem>()->GetWindow();
+          auto window =
+              engine->GetSystem<phx::DisplaySystemWindow>()->GetWindow();
           REQUIRE(window != nullptr);
         }
         THEN("It has a RenderingSystem") {
@@ -310,3 +357,67 @@ SCENARIO("An engine can be setup by the default setup", "[phx][phx::Engine]") {
     }
   }
 }
+
+SCENARIO("The order in which systems are updated by the engine can be changed",
+         "[phx][phx::Engine]") {
+  SDL_MOCK_ALLOW_ANY_CALL
+  OPENGL_MOCK_ALLOW_ANY_CALL
+  GIVEN("An engine set up with a number of test systems") {
+    auto engine = std::make_unique<phx::Engine>();
+    auto system1 = engine->CreateSystem<TestOrderSystem<int>>();
+    auto system2 = engine->CreateSystem<TestOrderSystem<float>>();
+    auto system3 = engine->CreateSystem<TestOrderSystem<unsigned int>>();
+    auto system4 = engine->CreateSystem<TestOrderSystem<double>>();
+    engine->CreateSystem<EngineStopTestSystem>();
+    std::string test_string;
+    auto callback1 = [&test_string]() { test_string.push_back('A'); };
+    auto callback2 = [&test_string]() { test_string.push_back('B'); };
+    auto callback3 = [&test_string]() { test_string.push_back('C'); };
+    auto callback4 = [&test_string]() { test_string.push_back('D'); };
+    system1->SetCallbackOnUpdate(callback1);
+    system2->SetCallbackOnUpdate(callback2);
+    system3->SetCallbackOnUpdate(callback3);
+    system4->SetCallbackOnUpdate(callback4);
+
+    WHEN("We run the engine") {
+      engine->Run();
+      THEN(
+          "The test systems have been updated in the same order in which they "
+          "were added") {
+        REQUIRE(test_string == "ABCD");
+      }
+    }
+
+    WHEN("We change the second system to update first") {
+      engine->GetUpdateOrder().MoveToFront(system2);
+      engine->Run();
+      THEN("The systems are updated in the order 2-1-3-4") {
+        REQUIRE(test_string == "BACD");
+      }
+    }
+
+    WHEN("We change the second system to update last") {
+      engine->GetUpdateOrder().MoveToBack(system2);
+      engine->Run();
+      THEN("The systems are updated in the order 1-3-4-2") {
+        REQUIRE(test_string == "ACDB");
+      }
+    }
+
+    WHEN("We change the update order to update system 2 after system 3") {
+      engine->GetUpdateOrder().MoveAfter(system2, system3);
+      engine->Run();
+      THEN("The systems are updated in the order 1-3-2-4") {
+        REQUIRE(test_string == "ACBD");
+      }
+    }
+
+    WHEN("We change the update order to update system 4 before system 1") {
+      engine->GetUpdateOrder().MoveBefore(system4, system1);
+      engine->Run();
+      THEN("The systems are updated in the order 4-1-2-3") {
+        REQUIRE(test_string == "DABC");
+      }
+    }
+  }
+}
diff --git a/tests/src/test_frame_graph.cpp b/tests/src/test_frame_graph.cpp
index cd98e045f714f0e7015a8ca5f574279275a40138..2008be84053496297c680dac6f2bc875e2dd2fec 100644
--- a/tests/src/test_frame_graph.cpp
+++ b/tests/src/test_frame_graph.cpp
@@ -48,25 +48,31 @@ SCENARIO("A frame graph manages render passes.", "[phx][phx::FrameGraph]") {
 
     WHEN("We add a mock render pass") {
       std::unique_ptr<MockRenderPass> pass = std::make_unique<MockRenderPass>();
-      MockRenderPass* pass_ref = static_cast<MockRenderPass*>(
+      MockRenderPass* pass_ptr = static_cast<MockRenderPass*>(
           frame_graph.AddRenderPass(std::move(pass)));
 
       THEN("the frame graph has 1 render pass.") {
         REQUIRE(frame_graph.GetNumberOfPasses() == 1);
       }
 
+      THEN("we can get the mock render pass out again") {
+        auto mockrenderpasses = frame_graph.GetRenderPasses<MockRenderPass>();
+        REQUIRE(mockrenderpasses.size() == 1);
+        REQUIRE(mockrenderpasses.front() == pass_ptr);
+      }
+
       WHEN("we call create") {
         THEN("the mock render pass was initialized but not executed") {
-          REQUIRE_CALL(*pass_ref, Initialize()).TIMES(1);
-          FORBID_CALL(*pass_ref, Execute());
+          REQUIRE_CALL(*pass_ptr, Initialize()).TIMES(1);
+          FORBID_CALL(*pass_ptr, Execute());
           frame_graph.Initialize();
         }
       }
 
       WHEN("we traverse the graph") {
         THEN("the mock render pass was executed") {
-          REQUIRE_CALL(*pass_ref, Execute()).TIMES(1);
-          FORBID_CALL(*pass_ref, Initialize());
+          REQUIRE_CALL(*pass_ptr, Execute()).TIMES(1);
+          FORBID_CALL(*pass_ptr, Initialize());
           frame_graph.Execute();
         }
       }
diff --git a/tests/src/test_geometry_pass.cpp b/tests/src/test_geometry_pass.cpp
index 0111f5a71f2c0c2789d535a427d7857223ad4352..a111eeee252dcab4e8f899ebd40ea4f86b35d9bb 100644
--- a/tests/src/test_geometry_pass.cpp
+++ b/tests/src/test_geometry_pass.cpp
@@ -35,6 +35,7 @@ SUPPRESS_WARNINGS_BEGIN
 #include "trompeloeil.hpp"
 SUPPRESS_WARNINGS_END
 
+#include "phx/entity.hpp"
 #include "phx/geometry_pass.hpp"
 #include "phx/render_target.hpp"
 
@@ -87,13 +88,14 @@ SCENARIO(
       }
 
       WHEN("We add data for a mesh with 3 indices.") {
+        phx::Entity entity;
+        phx::Transform* transform = entity.AddComponent<phx::Transform>();
         phx::Mesh mesh;
-        mesh.SetIndices({0u, 1u, 2u});
-        phx::Transform transform;
         phx::Material material;
+        mesh.SetIndices({0u, 1u, 2u});
 
         std::vector<phx::GeometryPass::RenderingInstance> geometry_pass_data;
-        geometry_pass_data.push_back({&mesh, &material, &transform});
+        geometry_pass_data.push_back({&mesh, &material, transform});
         geometry_pass.SetData(geometry_pass_data);
 
         THEN("Then one triangle is drawn") {
@@ -105,18 +107,19 @@ SCENARIO(
       }
 
       WHEN("We add data for a mesh with 3 vertices, normals, indices.") {
+        phx::Entity entity;
+        phx::Transform* transform = entity.AddComponent<phx::Transform>();
         phx::Mesh mesh;
+        phx::Material material;
         mesh.SetVertices(
             {{0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 0.0f}});
         mesh.SetNormals(
             {{0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}});
         mesh.SetTextureCoords({{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}});
         mesh.SetIndices({0u, 1u, 2u});
-        phx::Transform transform;
-        phx::Material material;
 
         std::vector<phx::GeometryPass::RenderingInstance> geometry_pass_data;
-        geometry_pass_data.push_back({&mesh, &material, &transform});
+        geometry_pass_data.push_back({&mesh, &material, transform});
 
         THEN(
             "3 vertices, 3 normals, 3 texCoords, 3 indices are uploaded and "
@@ -222,25 +225,31 @@ SCENARIO(
     phx::GeometryPass geometry_pass(&renderTarget);
     geometry_pass.Initialize();
 
-    WHEN("We add two meshes with different transformations") {
+    WHEN("We add a meshes with two different transformations") {
+      phx::Entity entity1;
+      phx::Transform* transform1 = entity1.AddComponent<phx::Transform>();
+      phx::Entity entity2;
+      phx::Transform* transform2 = entity2.AddComponent<phx::Transform>();
+
       phx::Mesh mesh;
+      phx::Material material;
+
       mesh.SetVertices(
           {{0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 0.0f}});
       mesh.SetNormals(
           {{0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}});
       mesh.SetTextureCoords({{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}});
       mesh.SetIndices({0u, 1u, 2u});
-      phx::Material material;
 
-      phx::Transform transform1(glm::vec3(-1, 0, 0));
-      const glm::mat4 global_matrix1{transform1.GetGlobalMatrix()};
-      phx::Transform transform2(glm::vec3(1, 0, 0));
-      const glm::mat4 local_matrix2{transform2.GetLocalMatrix()};
+      transform1->SetGlobalTranslation(glm::vec3(-1, 0, 0));
+      const glm::mat4 global_matrix1{transform1->GetGlobalMatrix()};
+      transform2->SetGlobalTranslation(glm::vec3(1, 0, 0));
+      const glm::mat4 local_matrix2{transform2->GetLocalMatrix()};
 
       phx::GeometryPass::RenderingInstance instance1{&mesh, &material,
-                                                     &transform1};
+                                                     transform1};
       phx::GeometryPass::RenderingInstance instance2{&mesh, &material,
-                                                     &transform2};
+                                                     transform2};
 
       geometry_pass.SetData({instance1, instance2}, {});
       THEN(
diff --git a/tests/src/test_light.cpp b/tests/src/test_light.cpp
index 409151931f5c6cc0436438731486864007b8beff..c8a4fadf4720565da8848fc67326acb5c2f4ac43 100644
--- a/tests/src/test_light.cpp
+++ b/tests/src/test_light.cpp
@@ -20,8 +20,11 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
+#include <memory>
+
 #include "catch/catch.hpp"
 
+#include "phx/entity.hpp"
 #include "phx/light.hpp"
 
 #include "glm/glm.hpp"
@@ -29,38 +32,39 @@
 SCENARIO("The light component describes a light source in space.",
          "[phx][phx::Light]") {
   GIVEN("A new light component.") {
-    phx::Light light;
+    phx::Entity entity;
+    phx::Light* light = entity.AddComponent<phx::Light>();
 
     WHEN("We set the type to spotlight.") {
-      light.SetType(phx::Light::Type::kSpot);
+      light->SetType(phx::Light::Type::kSpot);
       THEN("The type is set to spotlight.") {
-        REQUIRE(light.GetType() == phx::Light::Type::kSpot);
+        REQUIRE(light->GetType() == phx::Light::Type::kSpot);
       }
     }
 
     WHEN("We set the color to [1.0, 0.0, 0.0].") {
-      light.SetColor(glm::vec3(1.0, 0.0, 0.0));
+      light->SetColor(glm::vec3(1.0, 0.0, 0.0));
       THEN("The color is set to [1.0, 0.0, 0.0].") {
-        REQUIRE(light.GetColor() == glm::vec3(1.0, 0.0, 0.0));
+        REQUIRE(light->GetColor() == glm::vec3(1.0, 0.0, 0.0));
       }
     }
 
     WHEN("We set the intensity to 10.") {
-      light.SetIntensity(10.0f);
+      light->SetIntensity(10.0f);
       THEN("The intensity is set to 10.") {
-        REQUIRE(light.GetIntensity() == 10.0f);
+        REQUIRE(light->GetIntensity() == 10.0f);
       }
     }
 
     WHEN("We set the range to 100.") {
-      light.SetRange(100.0f);
-      THEN("The range is set to 100.") { REQUIRE(light.GetRange() == 100.0f); }
+      light->SetRange(100.0f);
+      THEN("The range is set to 100.") { REQUIRE(light->GetRange() == 100.0f); }
     }
 
     WHEN("We set the spot angle to 60.") {
-      light.SetSpotAngle(60.0f);
+      light->SetSpotAngle(60.0f);
       THEN("The spot angle is set to 60.") {
-        REQUIRE(light.GetSpotAngle() == 60.0f);
+        REQUIRE(light->GetSpotAngle() == 60.0f);
       }
     }
   }
diff --git a/tests/src/test_model.cpp b/tests/src/test_model.cpp
index e12c98e706b069845518997d1ce74d15cee0b88b..2d6b927ea4056039e4f4414a15b1c55671abfc9a 100644
--- a/tests/src/test_model.cpp
+++ b/tests/src/test_model.cpp
@@ -35,9 +35,8 @@ SCENARIO("A Model can be loaded that contains multiple meshes",
     GIVEN("A file name of an .obj file...") {
       std::string model_file_name{"models/2MeshTest/2meshTest.obj"};
       WHEN("A model resource is declared and loaded") {
-        auto model_proxy =
-            phx::ResourceUtils::LoadResourceFromFile(model_file_name);
-        phx::Model* model = model_proxy->GetAs<phx::Model>();
+        auto model = phx::ResourceUtils::LoadResourceFromFile<phx::Model>(
+            model_file_name);
         THEN("the returned model contains 2 meshes") {
           REQUIRE(model->GetMeshes().size() == 2u);
         }
diff --git a/tests/src/test_openvr_controller_system.cpp b/tests/src/test_openvr_controller_system.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..225ea9b498109211629d506451deb94b6834fde4
--- /dev/null
+++ b/tests/src/test_openvr_controller_system.cpp
@@ -0,0 +1,118 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include <memory>
+
+#include "catch/catch.hpp"
+
+SUPPRESS_WARNINGS_BEGIN
+#include "GL/glew.h"
+SUPPRESS_WARNINGS_END
+
+#include "trompeloeil.hpp"
+
+#include "phx/display_system_openvr.hpp"
+#include "phx/entity.hpp"
+#include "phx/material_handle.hpp"
+#include "phx/mesh_handle.hpp"
+#include "phx/openvr_controller_behavior.hpp"
+#include "phx/openvr_controller_system.hpp"
+#include "phx/rendering_system.hpp"
+#include "phx/scene.hpp"
+
+#include "mocks/opengl_mock.hpp"
+#include "mocks/openvr_mock.hpp"
+#include "mocks/sdl_mock.hpp"
+
+using trompeloeil::_;
+using trompeloeil::ne;
+
+extern template struct trompeloeil::reporter<trompeloeil::specialized>;
+
+class EngineStopTestSystem : public phx::System {
+ public:
+  explicit EngineStopTestSystem(phx::Engine* engine, int stop_in_frame = 1)
+      : System(engine), stop_on_update_(stop_in_frame) {}
+
+  void Update(const phx::FrameTimer::TimeInfo& time_info) override {
+    update_counter_++;
+    if (update_counter_ >= stop_on_update_) {
+      GetEngine()->Stop();
+    }
+    time_info_ = &time_info;
+  }
+
+  const phx::FrameTimer::TimeInfo* time_info_ = nullptr;
+
+ private:
+  int update_counter_ = 0;
+  int stop_on_update_ = 1;
+};
+
+SCENARIO(
+    "The OpenVRControllerSystem automatically inserts controller entities into "
+    "a scene if controllers are connected",
+    "[phx][phx::OpenVRControllerSystem]") {
+  OPENGL_MOCK_ALLOW_ANY_CALL;
+  OPENVR_MOCK_ALLOW_ANY_CALL;
+  SDL_MOCK_ALLOW_ANY_CALL;
+
+  phx::Engine engine;
+  auto display_system = engine.CreateSystem<phx::DisplaySystemOpenVR>();
+
+  GIVEN(
+      "The display system has an HMD and the engine has a scene. Also, there's "
+      "an OpenVRControllerSystem.") {
+    display_system->CreateHMD();
+    auto scene = std::make_shared<phx::Scene>();
+    engine.SetScene(scene);
+    engine.CreateSystem<phx::OpenVRControllerSystem>(display_system);
+    engine.CreateSystem<EngineStopTestSystem>();
+    engine.CreateSystem<phx::RenderingSystem>(display_system);
+
+    WHEN("We run the engine for once frame (updating each system once)") {
+      engine.Run();
+
+      THEN(
+          "There are controller entities in the scene with controller "
+          "behaviors attached to them, as well as mesh and material handles, "
+          "and the controllers are left and right") {
+        auto controller_entities =
+            scene->GetEntitiesWithComponents<phx::OpenVRControllerBehavior>();
+        REQUIRE(controller_entities.size() == 2);
+
+        for (auto entity : controller_entities) {
+          REQUIRE(entity->GetFirstComponent<phx::MeshHandle>() != nullptr);
+          REQUIRE(entity->GetFirstComponent<phx::MaterialHandle>() != nullptr);
+        }
+
+        auto side0 = controller_entities[0]
+                         ->GetFirstComponent<phx::OpenVRControllerBehavior>()
+                         ->GetSide();
+        auto side1 = controller_entities[1]
+                         ->GetFirstComponent<phx::OpenVRControllerBehavior>()
+                         ->GetSide();
+        REQUIRE(side0 != side1);
+      }
+    }
+  }
+}
diff --git a/tests/src/test_projection.cpp b/tests/src/test_projection.cpp
index 896bdab742f7f778d9c2db50e8e70a93dc75ebdf..b1b4c963d59c733777bbe52adcb26cfcd378843b 100644
--- a/tests/src/test_projection.cpp
+++ b/tests/src/test_projection.cpp
@@ -26,6 +26,7 @@ SUPPRESS_WARNINGS_BEGIN
 #include "glm/glm.hpp"
 SUPPRESS_WARNINGS_END
 
+#include "phx/entity.hpp"
 #include "phx/projection.hpp"
 
 #include "test_utilities/glm_mat4.hpp"
@@ -33,9 +34,10 @@ SUPPRESS_WARNINGS_END
 SCENARIO("The projection component stores data for projections.",
          "[phx][phx::Projection]") {
   GIVEN("A new projection component.") {
-    phx::Projection projection;
+    phx::Entity entity;
+    phx::Projection* projection = entity.AddComponent<phx::Projection>();
     WHEN("we query the matrix.") {
-      auto matrix = projection.GetMatrix();
+      auto matrix = projection->GetMatrix();
       THEN("It should yield an orthogonal projection to the xz-plane.") {
         const glm::mat4 ortho(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                               0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
@@ -46,9 +48,9 @@ SCENARIO("The projection component stores data for projections.",
     WHEN(
         "We set some projection parameters for a perspective projection and "
         "query the matrix.") {
-      projection.SetPerspective(glm::radians(68.0f), 4.0f / 3.0f, 0.01f,
-                                1000.0f);
-      auto matrix = projection.GetMatrix();
+      projection->SetPerspective(glm::radians(68.0f), 4.0f / 3.0f, 0.01f,
+                                 1000.0f);
+      auto matrix = projection->GetMatrix();
       THEN("It should yield the appropriate projection matrix.") {
         const glm::mat4 ground_truth(1.11192f, 0.0f, 0.0f, 0.0f, 0.0f, 1.48256f,
                                      0.0f, 0.0f, 0.0f, 0.0f, -1.00002f, -1.0f,
@@ -61,9 +63,9 @@ SCENARIO("The projection component stores data for projections.",
     WHEN(
         "We set some projection parameters for an orthogonal projection and "
         "query the matrix.") {
-      projection.SetOrthogonal(-100.0f, 100.0f, -100.0f, 100.0f, 0.01f,
-                               1000.0f);
-      auto matrix = projection.GetMatrix();
+      projection->SetOrthogonal(-100.0f, 100.0f, -100.0f, 100.0f, 0.01f,
+                                1000.0f);
+      auto matrix = projection->GetMatrix();
       THEN("It should yield the appropriate projection matrix.") {
         const glm::mat4 ground_truth(0.01, 0.0f, 0.0f, 0.0f, 0.0f, 0.01f, 0.0f,
                                      0.0f, 0.0f, 0.0f, -0.002f, 0.0f, 0.0f,
diff --git a/tests/src/test_rendering_system.cpp b/tests/src/test_rendering_system.cpp
index 4c83660c7f36a14b96d0264636bdf7294d8c2cbd..cd925e872804a65417c00adf684761e9f8741404 100644
--- a/tests/src/test_rendering_system.cpp
+++ b/tests/src/test_rendering_system.cpp
@@ -24,6 +24,7 @@
 
 #include "catch/catch.hpp"
 
+#include "phx/display_system_window.hpp"
 #include "phx/engine.hpp"
 #include "phx/entity.hpp"
 #include "phx/geometry_pass.hpp"
@@ -48,7 +49,7 @@ SCENARIO(
   phx::Engine engine;
 
   GIVEN("A rendering system.") {
-    auto diplay_system = engine.CreateSystem<phx::DisplaySystem>();
+    auto diplay_system = engine.CreateSystem<phx::DisplaySystemWindow>();
     phx::RenderingSystem* rendering_system =
         engine.CreateSystem<phx::RenderingSystem>(diplay_system);
 
diff --git a/tests/src/test_resource_pointer.cpp b/tests/src/test_resource_pointer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a95e89a53565bbedb982e9c6468f2d3a4d1e49bb
--- /dev/null
+++ b/tests/src/test_resource_pointer.cpp
@@ -0,0 +1,96 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include "catch/catch.hpp"
+
+#include "phx/image.hpp"
+#include "phx/resource_manager.hpp"
+#include "phx/resource_pointer.hpp"
+#include "phx/resource_proxy.hpp"
+#include "phx/resource_utils.hpp"
+
+SCENARIO(
+    "The resource pointer holds a raw pointer to a resource proxy and makes "
+    "the underlying resource available through the -> operator.",
+    "[phx][phx::ResourcePointer]") {
+  GIVEN("A proxy to an arbitrarily chosen image resource.") {
+    phx::ResourceProxy* proxy =
+        phx::ResourceManager::instance().DeclareResource(
+            phx::ResourceUtils::DeclarationFromFile(
+                "textures/splash_progress.png"));
+    WHEN("We initialize a resource pointer with that proxy.") {
+      phx::ResourcePointer<phx::Image> resource_pointer =
+          phx::ResourcePointer<phx::Image>(proxy);
+      THEN("We can access the image through the -> operator.") {
+        REQUIRE(resource_pointer.operator->() == proxy->GetAs<phx::Image>());
+      }
+      THEN("We can access the proxy through the GetProxy() method.") {
+        REQUIRE(resource_pointer.GetProxy() == proxy);
+      }
+      THEN(
+          "We can can compare the pointer to nullptr using the != operator and "
+          "they are the same, because the resource is not loaded.") {
+        REQUIRE(resource_pointer == nullptr);
+        REQUIRE(!resource_pointer);
+      }
+      WHEN("We load the resource.") {
+        proxy->Load();
+        THEN(
+            "We can compare the pointer to nullptr and they are not the "
+            "same.") {
+          REQUIRE(resource_pointer != nullptr);
+          REQUIRE(resource_pointer);
+        }
+      }
+      WHEN("We initialize a new pointer with the same proxy.") {
+        phx::ResourcePointer<phx::Image> resource_pointer2 =
+            phx::ResourcePointer<phx::Image>(proxy);
+        THEN(
+            "We can can compare the two pointers using the == operator and "
+            "they are the same") {
+          REQUIRE(resource_pointer == resource_pointer2);
+        }
+      }
+      WHEN("We initialize a new pointer with a different proxy.") {
+        phx::ResourceProxy* proxy2 =
+            phx::ResourceManager::instance().DeclareResource(
+                phx::ResourceUtils::DeclarationFromFile("textures/splash.png"));
+        phx::ResourcePointer<phx::Image> resource_pointer2 =
+            phx::ResourcePointer<phx::Image>(proxy2);
+        THEN(
+            "We can can compare the two pointers using the != operator and "
+            "they are not the same") {
+          REQUIRE(resource_pointer != resource_pointer2);
+        }
+      }
+      WHEN("We initialize a new pointer with nullptr.") {
+        phx::ResourcePointer<phx::Image> resource_pointer2 =
+            phx::ResourcePointer<phx::Image>(nullptr);
+        THEN(
+            "We can can compare the two pointers using the != operator and "
+            "they are not the same") {
+          REQUIRE(resource_pointer != resource_pointer2);
+        }
+      }
+    }
+  }
+}
diff --git a/tests/src/test_resource_utils.cpp b/tests/src/test_resource_utils.cpp
index a59ff75f4ed472611e9d7906ceec1cd0cecb9870..45d092956465a30c8583ac65a7fae6a441df33aa 100644
--- a/tests/src/test_resource_utils.cpp
+++ b/tests/src/test_resource_utils.cpp
@@ -24,6 +24,7 @@
 
 #include "catch/catch.hpp"
 
+#include "phx/image.hpp"
 #include "phx/resource_declaration.hpp"
 #include "phx/resource_proxy.hpp"
 #include "phx/resource_utils.hpp"
@@ -93,9 +94,9 @@ SCENARIO("Resource utils can load a file resource.",
     std::string file_name{"textures/splash_progress.png"};
 
     THEN("It can load it") {
-      phx::ResourceProxy* proxy =
-          phx::ResourceUtils::LoadResourceFromFile(file_name);
-      REQUIRE(proxy->IsOnline());
+      phx::ResourcePointer<phx::Image> image =
+          phx::ResourceUtils::LoadResourceFromFile<phx::Image>(file_name);
+      REQUIRE(image != nullptr);
     }
   }
 }
diff --git a/tests/src/test_shader.cpp b/tests/src/test_shader.cpp
index e7f87ff0af3852cefe14bb4baf9159f19767f295..b433156e3078559d9ae89dc3f3bc06059fa6f024 100644
--- a/tests/src/test_shader.cpp
+++ b/tests/src/test_shader.cpp
@@ -59,11 +59,12 @@ SCENARIO("We can load shaders.", "[phx][phx::Shader]") {
         REQUIRE_CALL(open_gl_mock, glCompileShader(1u));
         REQUIRE_CALL(open_gl_mock, glAttachShader(1u, 1u));
 
-        auto fragment_proxy =
-            phx::ResourceUtils::LoadResourceFromFile("shader/test.frag");
+        auto fragment =
+            phx::ResourceUtils::LoadResourceFromFile<phx::ShaderSource>(
+                "shader/test.frag");
 
-        bool success = shader_program.SetShaderProxy(
-            phx::ShaderProgram::FRAGMENT, fragment_proxy);
+        bool success =
+            shader_program.SetShader(phx::ShaderProgram::FRAGMENT, fragment);
 
         REQUIRE(success);
         REQUIRE(shader_program.is_valid());
@@ -83,15 +84,17 @@ SCENARIO("We can load shaders.", "[phx][phx::Shader]") {
             .SIDE_EFFECT(*_3 = 1);
         ALLOW_CALL(open_gl_mock, glCreateShader(_)).RETURN(1u);
 
-        auto vertex_proxy =
-            phx::ResourceUtils::LoadResourceFromFile("shader/phong.vert");
-        auto fragment_proxy =
-            phx::ResourceUtils::LoadResourceFromFile("shader/phong.frag");
+        auto vertex =
+            phx::ResourceUtils::LoadResourceFromFile<phx::ShaderSource>(
+                "shader/phong.vert");
+        auto fragment =
+            phx::ResourceUtils::LoadResourceFromFile<phx::ShaderSource>(
+                "shader/phong.frag");
 
-        bool success = shader_program.SetShaderProxy(phx::ShaderProgram::VERTEX,
-                                                     vertex_proxy);
-        success &= shader_program.SetShaderProxy(phx::ShaderProgram::FRAGMENT,
-                                                 fragment_proxy);
+        bool success =
+            shader_program.SetShader(phx::ShaderProgram::VERTEX, vertex);
+        success &=
+            shader_program.SetShader(phx::ShaderProgram::FRAGMENT, fragment);
 
         REQUIRE(success);
         REQUIRE(shader_program.is_valid());
@@ -107,15 +110,13 @@ SCENARIO("Shader Programs link themselves if they should be binded.",
     REQUIRE_CALL(open_gl_mock, glCreateProgram()).TIMES(1).RETURN(1u);
     phx::ShaderProgram shader_program;
 
-    auto vertex_proxy =
-        phx::ResourceUtils::LoadResourceFromFile("shader/phong.vert");
-    auto fragment_proxy =
-        phx::ResourceUtils::LoadResourceFromFile("shader/phong.frag");
+    auto vertex = phx::ResourceUtils::LoadResourceFromFile<phx::ShaderSource>(
+        "shader/phong.vert");
+    auto fragment = phx::ResourceUtils::LoadResourceFromFile<phx::ShaderSource>(
+        "shader/phong.frag");
 
-    bool success =
-        shader_program.SetShaderProxy(phx::ShaderProgram::VERTEX, vertex_proxy);
-    success &= shader_program.SetShaderProxy(phx::ShaderProgram::FRAGMENT,
-                                             fragment_proxy);
+    bool success = shader_program.SetShader(phx::ShaderProgram::VERTEX, vertex);
+    success &= shader_program.SetShader(phx::ShaderProgram::FRAGMENT, fragment);
 
     WHEN("we use this for the first time") {
       THEN(" it is also LinkShaderProgram links it") {
diff --git a/tests/src/test_tracking_system.cpp b/tests/src/test_tracking_system.cpp
index ea6f58a16e8e944ec443a99d475d82d88192aeff..467bf0b4ae7463e2e96ac722de572710e9f82466 100644
--- a/tests/src/test_tracking_system.cpp
+++ b/tests/src/test_tracking_system.cpp
@@ -31,12 +31,12 @@ SUPPRESS_WARNINGS_BEGIN
 SUPPRESS_WARNINGS_END
 #include "mocks/sdl_mock.hpp"
 
-#include "phx/display_system.hpp"
+#include "phx/display_system_openvr.hpp"
 #include "phx/entity.hpp"
 #include "phx/projection.hpp"
 #include "phx/runtime_component.hpp"
 #include "phx/scene.hpp"
-#include "phx/tracking_system.hpp"
+#include "phx/tracking_system_openvr.hpp"
 #include "phx/transform.hpp"
 
 #include "test_utilities/glm_mat4.hpp"
@@ -46,8 +46,8 @@ using trompeloeil::ne;
 
 extern template struct trompeloeil::reporter<trompeloeil::specialized>;
 
-void SetGlmToArrayMatrix_3_4(glm::mat4 m, float* array);
-void SetGlmToArrayMatrix_3_4(glm::mat4 m, float* array) {
+void SetGlmToArrayMatrix_3_4(glm::mat4 m, float *array);
+void SetGlmToArrayMatrix_3_4(glm::mat4 m, float *array) {
   std::size_t index = 0;
   for (int x = 0; x < 3; x++) {
     for (int y = 0; y < 4; y++) {
@@ -56,266 +56,412 @@ void SetGlmToArrayMatrix_3_4(glm::mat4 m, float* array) {
   }
 }
 
+template <typename ComponentType>
+bool HasComponent(phx::Entity *entity) {
+  return entity->GetFirstComponent<ComponentType>() != nullptr;
+}
+
+bool HasUserPlatform(phx::Entity *entity) {
+  return HasComponent<phx::RuntimeComponent<phx::USER_PLATFORM>>(entity);
+}
+
+bool HasHMD(phx::Entity *entity) {
+  return HasComponent<phx::RuntimeComponent<phx::HEAD>>(entity);
+}
+
+bool HasTransform(phx::Entity *entity) {
+  return HasComponent<phx::Transform>(entity);
+}
+
+bool HasLeftEye(phx::Entity *entity) {
+  return HasComponent<phx::RuntimeComponent<phx::LEFT_EYE>>(entity);
+}
+
+bool HasRightEye(phx::Entity *entity) {
+  return HasComponent<phx::RuntimeComponent<phx::RIGHT_EYE>>(entity);
+}
+
+bool HasProjection(phx::Entity *entity) {
+  return HasComponent<phx::Projection>(entity);
+}
+
+bool HasLeftController(phx::Entity *entity) {
+  return HasComponent<phx::RuntimeComponent<phx::LEFT_CONTROLLER>>(entity);
+}
+
+bool HasRightController(phx::Entity *entity) {
+  return HasComponent<phx::RuntimeComponent<phx::RIGHT_CONTROLLER>>(entity);
+}
+
+bool ValidateUserPlatform(phx::Entity *entity, bool platform_present) {
+  if (HasUserPlatform(entity)) {
+    THEN("There is only one virtual platform.") {
+      REQUIRE(platform_present == false);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateHMD(phx::Entity *entity, bool hmd_present) {
+  if (HasHMD(entity)) {
+    THEN("There is only one HMD.") { REQUIRE(hmd_present == false); }
+    THEN("The HMD has a transform component.") {
+      REQUIRE(HasTransform(entity));
+    }
+    THEN(
+        "The parent of the HMD's transform is the platform's "
+        "transform.") {
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()->GetParent() !=
+              nullptr);
+      REQUIRE(
+          entity->GetFirstComponent<phx::Transform>()
+              ->GetParent()
+              ->GetEntity()
+              ->GetFirstComponent<phx::RuntimeComponent<phx::USER_PLATFORM>>());
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateLeftEye(phx::Entity *entity, bool left_eye_present) {
+  if (HasLeftEye(entity)) {
+    THEN("There is only one left eye.") { REQUIRE(left_eye_present == false); }
+    THEN("The left eye has a transform component.") {
+      REQUIRE(HasTransform(entity));
+    }
+    THEN("The left eye has a projection component.") {
+      REQUIRE(HasProjection(entity));
+    }
+    THEN(
+        "The parent of the left eye's transform is the HMD's "
+        "transform.") {
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()->GetParent() !=
+              nullptr);
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()
+                  ->GetParent()
+                  ->GetEntity()
+                  ->GetFirstComponent<phx::RuntimeComponent<phx::HEAD>>());
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateRightEye(phx::Entity *entity, bool right_eye_present) {
+  if (HasRightEye(entity)) {
+    THEN("There is only one right eye.") {
+      REQUIRE(right_eye_present == false);
+    }
+    THEN("The right eye has a transform component.") {
+      REQUIRE(HasTransform(entity));
+    }
+    THEN("The right eye has a projection component.") {
+      REQUIRE(HasProjection(entity));
+    }
+    THEN(
+        "The parent of the right eye's transform is the HMD's "
+        "transform.") {
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()->GetParent() !=
+              nullptr);
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()
+                  ->GetParent()
+                  ->GetEntity()
+                  ->GetFirstComponent<phx::RuntimeComponent<phx::HEAD>>());
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateLeftController(phx::Entity *entity, bool left_controller_present) {
+  if (HasLeftController(entity)) {
+    THEN("There is only one left controller.") {
+      REQUIRE(left_controller_present == false);
+    }
+    THEN("The left controller has a transform component.") {
+      REQUIRE(HasTransform(entity));
+    }
+    THEN(
+        "The parent of the left controller's transform is the "
+        "platform's transform.") {
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()->GetParent() !=
+              nullptr);
+      REQUIRE(
+          entity->GetFirstComponent<phx::Transform>()
+              ->GetParent()
+              ->GetEntity()
+              ->GetFirstComponent<phx::RuntimeComponent<phx::USER_PLATFORM>>());
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateRightController(phx::Entity *entity,
+                             bool right_controller_present) {
+  if (HasRightController(entity)) {
+    THEN("There is only one right controller.") {
+      REQUIRE(right_controller_present == false);
+    }
+    THEN("The right controller has a transform component.") {
+      REQUIRE(HasTransform(entity));
+    }
+    THEN(
+        "The parent of the right controller's transform is the "
+        "platform's transform.") {
+      REQUIRE(entity->GetFirstComponent<phx::Transform>()->GetParent() !=
+              nullptr);
+      REQUIRE(
+          entity->GetFirstComponent<phx::Transform>()
+              ->GetParent()
+              ->GetEntity()
+              ->GetFirstComponent<phx::RuntimeComponent<phx::USER_PLATFORM>>());
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidatePlatformTransform(phx::Entity *entity,
+                               glm::mat4 platform_trans_mat) {
+  if (HasUserPlatform(entity)) {
+    THEN("The platform transformation did not change.") {
+      REQUIRE(
+          test_utilities::Approx<glm::mat4>(
+              entity->GetFirstComponent<phx::Transform>()->GetLocalMatrix()) ==
+          platform_trans_mat);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateHMDTransform(phx::Entity *entity, glm::mat4 hmd_trans_mat) {
+  if (HasHMD(entity)) {
+    THEN(
+        "The hmd transformation changes to the one provided by "
+        "OpenVR.") {
+      REQUIRE(
+          test_utilities::Approx<glm::mat4>(
+              entity->GetFirstComponent<phx::Transform>()->GetLocalMatrix()) ==
+          hmd_trans_mat);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateLeftEyeTransform(phx::Entity *entity,
+                              glm::mat4 left_eye_trans_mat) {
+  if (HasLeftEye(entity)) {
+    THEN(
+        "The left eye transformation changes to the one provided "
+        "by OpenVR.") {
+      REQUIRE(
+          test_utilities::Approx<glm::mat4>(
+              entity->GetFirstComponent<phx::Transform>()->GetLocalMatrix()) ==
+          left_eye_trans_mat);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool ValidateRightEyeTransform(phx::Entity *entity,
+                               glm::mat4 right_eye_trans_mat) {
+  if (HasRightEye(entity)) {
+    THEN(
+        "The right eye transformation changes to the one provided "
+        "by OpenVR.") {
+      REQUIRE(
+          test_utilities::Approx<glm::mat4>(
+              entity->GetFirstComponent<phx::Transform>()->GetLocalMatrix()) ==
+          right_eye_trans_mat);
+    }
+    return true;
+  }
+  return false;
+}
+
+void TestRuntimeEntityStructure(std::shared_ptr<phx::Scene> scene) {
+  THEN("The HMD and the user's eyes are represented in the scene.") {
+    auto entities = scene->GetEntitiesWithComponents<phx::Transform>();
+    bool platform_present = false;
+    bool hmd_present = false;
+    bool left_eye_present = false;
+    bool right_eye_present = false;
+    bool left_controller_present = false;
+    bool right_controller_present = false;
+
+    for (auto entity : entities) {
+      platform_present |= ValidateUserPlatform(entity, platform_present);
+
+      hmd_present |= ValidateHMD(entity, hmd_present);
+
+      left_eye_present |= ValidateLeftEye(entity, left_eye_present);
+      right_eye_present |= ValidateRightEye(entity, right_eye_present);
+
+      left_controller_present |=
+          ValidateLeftController(entity, left_controller_present);
+      right_controller_present |=
+          ValidateLeftController(entity, right_controller_present);
+    }
+
+    THEN(
+        "There are six entities: The platform, the HMD, the left and "
+        "the right eyes, the left and right controllers.") {
+      REQUIRE(entities.size() == 6);
+      REQUIRE(platform_present);
+      REQUIRE(hmd_present);
+      REQUIRE(left_eye_present);
+      REQUIRE(right_eye_present);
+      REQUIRE(left_controller_present);
+      REQUIRE(right_controller_present);
+    }
+  }
+}
+
+void InitMatrices(glm::mat4 *platform_trans_mat, glm::mat4 *hmd_trans_mat,
+                  glm::mat4 *left_eye_trans_mat,
+                  glm::mat4 *right_eye_trans_mat) {
+  *platform_trans_mat =
+      glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                1.0f, 0.0f, 1.0f, -1.0f, 0.5f, 1.0f);
+  *hmd_trans_mat = glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+                            0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.8f, 0.2f, 1.0f);
+  *left_eye_trans_mat =
+      glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                1.0f, 0.0f, -0.04f, 0.0f, 0.0f, 1.0f);
+  *right_eye_trans_mat =
+      glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                1.0f, 0.0f, 0.04f, 0.0f, 0.0f, 1.0f);
+  SetGlmToArrayMatrix_3_4(*hmd_trans_mat, openvr_mock.head_transformation_);
+  SetGlmToArrayMatrix_3_4(*left_eye_trans_mat, openvr_mock.eye_to_head_left_);
+  SetGlmToArrayMatrix_3_4(*right_eye_trans_mat, openvr_mock.eye_to_head_right_);
+}
+
+void TestRuntimeEntityUpdate(std::shared_ptr<phx::Scene> scene,
+                             phx::TrackingSystemOpenVR *tracking_system) {
+  glm::mat4 platform_trans_mat, hmd_trans_mat, left_eye_trans_mat,
+      right_eye_trans_mat;
+  InitMatrices(&platform_trans_mat, &hmd_trans_mat, &left_eye_trans_mat,
+               &right_eye_trans_mat);
+
+  WHEN("The tracking system is updated.") {
+    tracking_system->Update(phx::FrameTimer::TimeInfo());
+    THEN(
+        "It sets the transforms of all the runtime entities to the "
+        "correct values.") {
+      auto entities = scene->GetEntitiesWithComponents<phx::Transform>();
+      bool platform_present = false;
+      bool hmd_present = false;
+      bool left_eye_present = false;
+      bool right_eye_present = false;
+      bool left_controller_present = false;
+      bool right_controller_present = false;
+
+      for (auto entity : entities) {
+        platform_present |=
+            ValidatePlatformTransform(entity, platform_trans_mat);
+
+        hmd_present |= ValidateHMDTransform(entity, hmd_trans_mat);
+
+        left_eye_present |=
+            ValidateLeftEyeTransform(entity, left_eye_trans_mat);
+        right_eye_present |=
+            ValidateRightEyeTransform(entity, right_eye_trans_mat);
+
+        left_controller_present |= HasLeftController(entity);
+        right_controller_present |= HasRightController(entity);
+      }
+      THEN(
+          "There are still six entities: The platform, the HMD, the "
+          "left and the right eyes, the left and the right controllers.") {
+        REQUIRE(entities.size() == 6);
+        REQUIRE(platform_present);
+        REQUIRE(hmd_present);
+        REQUIRE(left_eye_present);
+        REQUIRE(right_eye_present);
+        REQUIRE(left_controller_present);
+        REQUIRE(right_controller_present);
+      }
+    }
+  }
+}
+
 SCENARIO(
     "The tracking system tracks hardware and updates their software "
     "counterparts.",
-    "[phx][phx::TrackingSystem]") {
+    "[phx][phx::TrackingSystemOpenVR]") {
   OPENVR_MOCK_ALLOW_ANY_CALL;
   SDL_MOCK_ALLOW_ANY_CALL;
 
   phx::Engine engine;
-  auto display_system = engine.CreateSystem<phx::DisplaySystem>();
+  auto display_system = engine.CreateSystem<phx::DisplaySystemOpenVR>();
 
   GIVEN(
       "The display system has an HMD and the engine has a scene with a "
       "user platform.") {
     display_system->CreateHMD();
-    auto scene = std::make_shared<phx::Scene>();
-    engine.SetScene(scene);
+    auto first_scene = std::make_shared<phx::Scene>();
+    engine.SetScene(first_scene);
     auto platform_trans_mat =
         glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
                   1.0f, 0.0f, 1.0f, -1.0f, 0.5f, 1.0f);
-    scene
+    first_scene
         ->GetEntitiesWithComponents<
             phx::RuntimeComponent<phx::USER_PLATFORM>>()[0]
         ->GetFirstComponent<phx::Transform>()
         ->SetLocalMatrix(platform_trans_mat);
     WHEN("A tracking system is created and initialized.") {
       auto tracking_system =
-          engine.CreateSystem<phx::TrackingSystem>(display_system);
-      THEN("The HMD and the user's eyes are represented in the scene.") {
-        auto entities = scene->GetEntitiesWithComponents<phx::Transform>();
-        bool platform_present = false;
-        bool hmd_present = false;
-        bool left_eye_present = false;
-        bool right_eye_present = false;
-        bool left_controller_present = false;
-        bool right_controller_present = false;
-        for (auto entity : entities) {
-          if (entity->GetFirstComponent<
-                  phx::RuntimeComponent<phx::USER_PLATFORM>>()) {
-            THEN("There is only one virtual platform.") {
-              REQUIRE(platform_present == false);
-            }
-            platform_present = true;
-          }
-          if (entity->GetFirstComponent<phx::RuntimeComponent<phx::HEAD>>()) {
-            THEN("There is only one HMD.") { REQUIRE(hmd_present == false); }
-            THEN("The HMD has a transform component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Transform>());
-            }
-            THEN(
-                "The parent of the HMD's transform is the platform's "
-                "transform.") {
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()->GetParent() !=
-                  nullptr);
-              REQUIRE(entity->GetFirstComponent<phx::Transform>()
-                          ->GetParent()
-                          ->GetEntity()
-                          ->GetFirstComponent<
-                              phx::RuntimeComponent<phx::USER_PLATFORM>>());
-            }
-            hmd_present = true;
-          }
-          if (entity
-                  ->GetFirstComponent<phx::RuntimeComponent<phx::LEFT_EYE>>()) {
-            THEN("There is only one left eye.") {
-              REQUIRE(left_eye_present == false);
-            }
-            THEN("The left eye has a transform component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Transform>());
-            }
-            THEN("The left eye has a projection component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Projection>());
-            }
-            THEN(
-                "The parent of the left eye's transform is the HMD's "
-                "transform.") {
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()->GetParent() !=
-                  nullptr);
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()
-                      ->GetParent()
-                      ->GetEntity()
-                      ->GetFirstComponent<phx::RuntimeComponent<phx::HEAD>>());
-            }
-            left_eye_present = true;
-          }
-          if (entity->GetFirstComponent<
-                  phx::RuntimeComponent<phx::RIGHT_EYE>>()) {
-            THEN("There is only one right eye.") {
-              REQUIRE(right_eye_present == false);
-            }
-            THEN("The right eye has a transform component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Transform>());
-            }
-            THEN("The right eye has a projection component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Projection>());
-            }
-            THEN(
-                "The parent of the right eye's transform is the HMD's "
-                "transform.") {
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()->GetParent() !=
-                  nullptr);
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()
-                      ->GetParent()
-                      ->GetEntity()
-                      ->GetFirstComponent<phx::RuntimeComponent<phx::HEAD>>());
-            }
-            right_eye_present = true;
-          }
-
-          if (entity->GetFirstComponent<
-                  phx::RuntimeComponent<phx::LEFT_CONTROLLER>>()) {
-            THEN("There is only one left controller.") {
-              REQUIRE(left_controller_present == false);
-            }
-            THEN("The left controller has a transform component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Transform>());
-            }
-            THEN(
-                "The parent of the left controller's transform is the "
-                "platform's transform.") {
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()->GetParent() !=
-                  nullptr);
-              REQUIRE(entity->GetFirstComponent<phx::Transform>()
-                          ->GetParent()
-                          ->GetEntity()
-                          ->GetFirstComponent<
-                              phx::RuntimeComponent<phx::USER_PLATFORM>>());
-            }
-            left_controller_present = true;
-          }
-          if (entity->GetFirstComponent<
-                  phx::RuntimeComponent<phx::RIGHT_CONTROLLER>>()) {
-            THEN("There is only one right controller.") {
-              REQUIRE(right_controller_present == false);
-            }
-            THEN("The right controller has a transform component.") {
-              REQUIRE(entity->GetFirstComponent<phx::Transform>());
-            }
-            THEN(
-                "The parent of the right controller's transform is the "
-                "platform's transform.") {
-              REQUIRE(
-                  entity->GetFirstComponent<phx::Transform>()->GetParent() !=
-                  nullptr);
-              REQUIRE(entity->GetFirstComponent<phx::Transform>()
-                          ->GetParent()
-                          ->GetEntity()
-                          ->GetFirstComponent<
-                              phx::RuntimeComponent<phx::USER_PLATFORM>>());
-            }
-            right_controller_present = true;
-          }
-        }
-        THEN(
-            "There are six entities: The platform, the HMD, the left and "
-            "the right eyes, the left and right controllers.") {
-          REQUIRE(entities.size() == 6);
-          REQUIRE(platform_present);
-          REQUIRE(hmd_present);
-          REQUIRE(left_eye_present);
-          REQUIRE(right_eye_present);
-          REQUIRE(left_controller_present);
-          REQUIRE(right_controller_present);
-        }
-      }
-      WHEN("The tracking system is then updated.") {
-        auto hmd_trans_mat =
-            glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-                      0.0f, 1.0f, 0.0f, 0.5f, 1.8f, 0.2f, 1.0f);
-        auto left_eye_trans_mat =
-            glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-                      0.0f, 1.0f, 0.0f, -0.04f, 0.0f, 0.0f, 1.0f);
-        auto right_eye_trans_mat =
-            glm::mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-                      0.0f, 1.0f, 0.0f, 0.04f, 0.0f, 0.0f, 1.0f);
-        SetGlmToArrayMatrix_3_4(hmd_trans_mat,
-                                openvr_mock.head_transformation_);
-        SetGlmToArrayMatrix_3_4(left_eye_trans_mat,
-                                openvr_mock.eye_to_head_left_);
-        SetGlmToArrayMatrix_3_4(right_eye_trans_mat,
-                                openvr_mock.eye_to_head_right_);
-        tracking_system->Update(phx::FrameTimer::TimeInfo());
+          engine.CreateSystem<phx::TrackingSystemOpenVR>(display_system);
+
+      TestRuntimeEntityStructure(first_scene);
+      TestRuntimeEntityUpdate(first_scene, tracking_system);
+
+      WHEN("The scene is then changed.") {
+        auto new_scene = std::make_shared<phx::Scene>();
+        new_scene
+            ->GetEntitiesWithComponents<
+                phx::RuntimeComponent<phx::USER_PLATFORM>>()[0]
+            ->GetFirstComponent<phx::Transform>()
+            ->SetLocalMatrix(platform_trans_mat);
+        engine.SetScene(new_scene);
+
         THEN(
-            "It sets the transforms of all the runtime entities to the "
-            "correct values.") {
-          auto entities = scene->GetEntitiesWithComponents<phx::Transform>();
-          bool platform_present = false;
-          bool hmd_present = false;
-          bool left_eye_present = false;
-          bool right_eye_present = false;
-          bool left_controller_present = false;
-          bool right_controller_present = false;
-          for (auto entity : entities) {
-            if (entity->GetFirstComponent<
-                    phx::RuntimeComponent<phx::USER_PLATFORM>>()) {
-              THEN("The platform transformation did not change.") {
-                REQUIRE(test_utilities::Approx<glm::mat4>(
-                            entity->GetFirstComponent<phx::Transform>()
-                                ->GetLocalMatrix()) == platform_trans_mat);
-              }
-              platform_present = true;
-            }
-            if (entity->GetFirstComponent<phx::RuntimeComponent<phx::HEAD>>()) {
-              THEN(
-                  "The hmd transformation changes to the one provided by "
-                  "OpenVR.") {
-                REQUIRE(test_utilities::Approx<glm::mat4>(
-                            entity->GetFirstComponent<phx::Transform>()
-                                ->GetLocalMatrix()) == hmd_trans_mat);
-              }
-              hmd_present = true;
-            }
-            if (entity->GetFirstComponent<
-                    phx::RuntimeComponent<phx::LEFT_EYE>>()) {
-              THEN(
-                  "The left eye transformation changes to the one provided "
-                  "by OpenVR.") {
-                REQUIRE(test_utilities::Approx<glm::mat4>(
-                            entity->GetFirstComponent<phx::Transform>()
-                                ->GetLocalMatrix()) == left_eye_trans_mat);
-              }
-              left_eye_present = true;
-            }
-            if (entity->GetFirstComponent<
-                    phx::RuntimeComponent<phx::RIGHT_EYE>>()) {
-              THEN(
-                  "The right eye transformation changes to the one provided "
-                  "by OpenVR.") {
-                REQUIRE(test_utilities::Approx<glm::mat4>(
-                            entity->GetFirstComponent<phx::Transform>()
-                                ->GetLocalMatrix()) == right_eye_trans_mat);
-              }
-              right_eye_present = true;
-            }
-            if (entity->GetFirstComponent<
-                    phx::RuntimeComponent<phx::LEFT_CONTROLLER>>()) {
-              left_controller_present = true;
-            }
-            if (entity->GetFirstComponent<
-                    phx::RuntimeComponent<phx::RIGHT_CONTROLLER>>()) {
-              right_controller_present = true;
-            }
-          }
-          THEN(
-              "There are still six entities: The platform, the HMD, the "
-              "left and the right eyes, the left and the right controllers.") {
-            REQUIRE(entities.size() == 6);
-            REQUIRE(platform_present);
-            REQUIRE(hmd_present);
-            REQUIRE(left_eye_present);
-            REQUIRE(right_eye_present);
-            REQUIRE(left_controller_present);
-            REQUIRE(right_controller_present);
-          }
+            "The first scene does not contain runtime entities except for "
+            "exactly one user platform.") {
+          REQUIRE(first_scene
+                      ->GetEntitiesWithComponents<
+                          phx::RuntimeComponent<phx::USER_PLATFORM>>()
+                      .size() == 1);
+          REQUIRE(first_scene
+                      ->GetEntitiesWithComponents<
+                          phx::RuntimeComponent<phx::HEAD>>()
+                      .size() == 0);
+          REQUIRE(first_scene
+                      ->GetEntitiesWithComponents<
+                          phx::RuntimeComponent<phx::LEFT_EYE>>()
+                      .size() == 0);
+          REQUIRE(first_scene
+                      ->GetEntitiesWithComponents<
+                          phx::RuntimeComponent<phx::RIGHT_EYE>>()
+                      .size() == 0);
+          REQUIRE(first_scene
+                      ->GetEntitiesWithComponents<
+                          phx::RuntimeComponent<phx::LEFT_CONTROLLER>>()
+                      .size() == 0);
+          REQUIRE(first_scene
+                      ->GetEntitiesWithComponents<
+                          phx::RuntimeComponent<phx::RIGHT_CONTROLLER>>()
+                      .size() == 0);
         }
+
+        TestRuntimeEntityStructure(new_scene);
+        TestRuntimeEntityUpdate(new_scene, tracking_system);
       }
     }
   }
diff --git a/tests/test_utilities/tests/src/test_reference_images.cpp b/tests/test_utilities/tests/src/test_reference_images.cpp
index c6b3a2236bfb8e9db0127989c611fe13d981d975..f2005d2cc4c4a91fd7f15de4cdee2bd3cfd5510a 100644
--- a/tests/test_utilities/tests/src/test_reference_images.cpp
+++ b/tests/test_utilities/tests/src/test_reference_images.cpp
@@ -114,14 +114,12 @@ SCENARIO(
         THEN(
             "If they accept, the reference image now exists and is identical "
             "to the buffer") {
-          auto img_proxy = phx::ResourceUtils::LoadResourceFromFile(
+          auto img = phx::ResourceUtils::LoadResourceFromFile<phx::Image>(
               filename_with_path, {}, true);
-          auto test_ref_image = img_proxy->GetAs<phx::Image>();
 
-          REQUIRE(test_ref_image != nullptr);
-          auto test_ref_image_buffer =
-              phx::OpenGLImageBufferData<phx::OpenGLImageBufferDataType_RGB>::
-                  CreateFromImage(test_ref_image);
+          REQUIRE(img != nullptr);
+          auto test_ref_image_buffer = phx::OpenGLImageBufferData<
+              phx::OpenGLImageBufferDataType_RGB>::CreateFromImage(img.Get());
           test_utilities::OpenGLBufferComparison::REQUIRE_SIMILARITY(
               buffer, *test_ref_image_buffer.get(), 1.0);
 
@@ -156,13 +154,11 @@ SCENARIO(
         THEN(
             "If they accept, the reference image now exists and is identical "
             "to the buffer") {
-          auto img_proxy = phx::ResourceUtils::LoadResourceFromFile(
+          auto img = phx::ResourceUtils::LoadResourceFromFile<phx::Image>(
               filename_with_path, {}, true);
-          auto test_ref_image = img_proxy->GetAs<phx::Image>();
-          REQUIRE(test_ref_image != nullptr);
-          auto test_ref_image_buffer =
-              phx::OpenGLImageBufferData<phx::OpenGLImageBufferDataType_RGB>::
-                  CreateFromImage(test_ref_image);
+          REQUIRE(img != nullptr);
+          auto test_ref_image_buffer = phx::OpenGLImageBufferData<
+              phx::OpenGLImageBufferDataType_RGB>::CreateFromImage(img.Get());
           test_utilities::OpenGLBufferComparison::REQUIRE_SIMILARITY(
               buffer, *test_ref_image_buffer.get(), 1.0);