diff --git a/Content/BP_VirtualRealityPawn.uasset b/Content/BP_VirtualRealityPawn.uasset
index d3ab67b1d5e35aa30a09884d6070777d908d76db..d712f953c0b6b7115269a19395b8ec42c8998aed 100644
Binary files a/Content/BP_VirtualRealityPawn.uasset and b/Content/BP_VirtualRealityPawn.uasset differ
diff --git a/Content/RWTHVRGameMode.uasset b/Content/RWTHVRGameMode.uasset
index 6e3b11f843990e7dd4f9418596c8987874829aa1..bbe367b340d7b98310000099bb7ffa8e3e088b0f 100644
Binary files a/Content/RWTHVRGameMode.uasset and b/Content/RWTHVRGameMode.uasset differ
diff --git a/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp
index af46f80934f02d316a5680f35a1a0a684c809cd3..cf8213737de30479629cc84aeb80dca1cae7a04e 100644
--- a/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp
+++ b/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp
@@ -1,6 +1,5 @@
 // Fill out your copyright notice in the Description page of Project Settings.
 
-
 #include "Pawn/ContinuousMovementComponent.h"
 
 #include "EnhancedInputComponent.h"
@@ -9,6 +8,7 @@
 #include "GameFramework/PlayerController.h"
 #include "Pawn/VRPawnInputConfig.h"
 #include "Utility/VirtualRealityUtilities.h"
+#include "MotionControllerComponent.h"
 
 void UContinuousMovementComponent::BeginPlay()
 {
@@ -71,16 +71,6 @@ void UContinuousMovementComponent::SetupInputActions()
 	// bind additional functions for desktop rotations
 	if (UVirtualRealityUtilities::IsDesktopMode())
 	{
-		APlayerController* PC = Cast<APlayerController>(VRPawn->GetController());
-		if (PC)
-		{
-			PC->bShowMouseCursor = true; 
-			PC->bEnableClickEvents = true; 
-			PC->bEnableMouseOverEvents = true;
-		} else
-		{
-			UE_LOG(LogTemp,Error,TEXT("PC Player Controller is invalid"));
-		}
 		EI->BindAction(DesktopRotation, ETriggerEvent::Started, this, &UContinuousMovementComponent::StartDesktopRotation);
 		EI->BindAction(DesktopRotation, ETriggerEvent::Completed, this, &UContinuousMovementComponent::EndDesktopRotation);
 		EI->BindAction(MoveUp, ETriggerEvent::Triggered,this,&UContinuousMovementComponent::OnBeginUp);
@@ -102,8 +92,8 @@ void UContinuousMovementComponent::OnBeginMove(const FInputActionValue& Value)
 	
 	const bool bGazeDirected = UVirtualRealityUtilities::IsDesktopMode() || SteeringMode == EVRSteeringModes::STEER_GAZE_DIRECTED;
 	
-	const FVector ForwardDir = bGazeDirected ? VRPawn->Head->GetForwardVector() : MovementHand->GetForwardVector();
-	const FVector RightDir = bGazeDirected ? VRPawn->Head->GetRightVector() : MovementHand->GetRightVector();
+	const FVector ForwardDir = bGazeDirected ? VRPawn->HeadCameraComponent->GetForwardVector() : MovementHand->GetForwardVector();
+	const FVector RightDir = bGazeDirected ? VRPawn->HeadCameraComponent->GetRightVector() : MovementHand->GetRightVector();
 	
 	if (VRPawn->Controller != nullptr)
 	{
@@ -133,10 +123,6 @@ void UContinuousMovementComponent::OnBeginTurn(const FInputActionValue& Value)
 		if (TurnValue.X != 0.f)
 		{
 			VRPawn->AddControllerYawInput(TurnRateFactor * TurnValue.X);
-			if (UVirtualRealityUtilities::IsDesktopMode())
-			{
-				UpdateRightHandForDesktopInteraction();
-			}
 		}
  
 		if (TurnValue.Y != 0.f)
@@ -144,7 +130,6 @@ void UContinuousMovementComponent::OnBeginTurn(const FInputActionValue& Value)
 			if (UVirtualRealityUtilities::IsDesktopMode() && bApplyDesktopRotation)
 			{
 				VRPawn->AddControllerPitchInput(TurnRateFactor * -TurnValue.Y);
-				SetCameraOffset();
 			}
 		}
 	}
@@ -162,28 +147,6 @@ void UContinuousMovementComponent::OnBeginSnapTurn(const FInputActionValue& Valu
 	}
 }
 
-void UContinuousMovementComponent::SetCameraOffset() const
-{
-	// this also incorporates the BaseEyeHeight, if set as static offset,
-	// rotations are still around the center of the pawn (on the floor), so pitch rotations look weird
-	FVector Location;
-	FRotator Rotation;
-	VRPawn->GetActorEyesViewPoint(Location, Rotation);
-	VRPawn->CameraComponent->SetWorldLocationAndRotation(Location, Rotation);
-}
-
-void UContinuousMovementComponent::UpdateRightHandForDesktopInteraction()
-{
-	APlayerController* PC = Cast<APlayerController>(VRPawn->GetController());
-	if (PC)
-	{
-		FVector MouseLocation, MouseDirection;
-		PC->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);
-		FRotator HandOrientation = MouseDirection.ToOrientationRotator();
-		VRPawn->RightHand->SetWorldRotation(HandOrientation);
-	}
-}
-
 void UContinuousMovementComponent::OnBeginUp(const FInputActionValue& Value)
 {
 	const float MoveValue =  Value.Get<FVector2D>().X;
diff --git a/Source/RWTHVRToolkit/Private/Pawn/TeleportationComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/TeleportationComponent.cpp
index b775efcac63506828c7112e3675cad196a652ce5..0fd9bd5a3e170d723b28c39fd047d575c1780542 100644
--- a/Source/RWTHVRToolkit/Private/Pawn/TeleportationComponent.cpp
+++ b/Source/RWTHVRToolkit/Private/Pawn/TeleportationComponent.cpp
@@ -13,6 +13,7 @@
 #include "Kismet/GameplayStatics.h"
 #include "NiagaraDataInterfaceArrayFunctionLibrary.h"
 #include "Utility/VirtualRealityUtilities.h"
+#include "MotionControllerComponent.h"
 
 // Sets default values for this component's properties
 UTeleportationComponent::UTeleportationComponent()
@@ -273,7 +274,7 @@ void UTeleportationComponent::SetCameraOffset() const
 	FVector Location;
 	FRotator Rotation;
 	VRPawn->GetActorEyesViewPoint(Location, Rotation);
-	VRPawn->CameraComponent->SetWorldLocationAndRotation(Location, Rotation);
+	VRPawn->HeadCameraComponent->SetWorldLocationAndRotation(Location, Rotation);
 }
 
 void UTeleportationComponent::UpdateRightHandForDesktopInteraction()
diff --git a/Source/RWTHVRToolkit/Private/Pawn/UniversalTrackedComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/UniversalTrackedComponent.cpp
deleted file mode 100644
index 18320ca4b9a3a1378918f7df114507550102d0f5..0000000000000000000000000000000000000000
--- a/Source/RWTHVRToolkit/Private/Pawn/UniversalTrackedComponent.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-
-#include "Pawn/UniversalTrackedComponent.h"
-
-#include "Camera/CameraComponent.h"
-#include "Utility/VirtualRealityUtilities.h"
-#include "Roles/LiveLinkTransformTypes.h"
-#include "ILiveLinkClient.h"
-
-DEFINE_LOG_CATEGORY(LogUniversalTrackedComponent);
-
-// Sets default values for this component's properties
-UUniversalTrackedComponent::UUniversalTrackedComponent()
-{
-	PrimaryComponentTick.bCanEverTick = true;
-	PrimaryComponentTick.TickGroup = ETickingGroup::TG_PrePhysics;
-	bAlwaysUseLiveLinkTracking = false;
-}
-
-void UUniversalTrackedComponent::SetShowDeviceModel(const bool bShowControllerModel)
-{
-	if (!UVirtualRealityUtilities::IsHeadMountedMode() || TrackedComponent == nullptr) return;
-
-	bShowDeviceModelInHMD = bShowControllerModel;
-	Cast<UMotionControllerComponent>(TrackedComponent)->SetShowDeviceModel(bShowDeviceModelInHMD);
-}
-
-void UUniversalTrackedComponent::BeginPlay()
-{
-	Super::BeginPlay();
-
-	if (UVirtualRealityUtilities::IsHeadMountedMode())
-	{
-		if (ProxyType == ETrackedComponentType::TCT_HEAD)
-		{
-			TrackedComponent = GetOwner()->FindComponentByClass<UCameraComponent>();
-		}
-		else
-		{
-			/* Spawn Motion Controller Components in HMD Mode*/
-			UMotionControllerComponent* MotionController = Cast<UMotionControllerComponent>(GetOwner()->AddComponentByClass(UMotionControllerComponent::StaticClass(), false, FTransform::Identity, false));
-			GetOwner()->AddInstanceComponent(MotionController); // makes it show correctly in the hierarchy
-
-			// Todo: If bAlwaysUseLiveLinkTracking is true, those should be sourced by LiveLink
-			switch(ProxyType)
-			{
-				case ETrackedComponentType::TCT_TRACKER_1:
-					MotionController->SetTrackingMotionSource(FName("Special_1"));
-					break;
-				case ETrackedComponentType::TCT_TRACKER_2:
-					MotionController->SetTrackingMotionSource(FName("Special_2"));
-					break;
-				case ETrackedComponentType::TCT_RIGHT_HAND:
-					MotionController->SetTrackingMotionSource(FName("Right"));
-					break;
-				case ETrackedComponentType::TCT_LEFT_HAND:
-					MotionController->SetTrackingMotionSource(FName("Left"));
-					break;
-				default: break;
-			}
-			MotionController->SetShowDeviceModel(bShowDeviceModelInHMD);
-
-			TrackedComponent = MotionController;
-		}
-		if (TrackedComponent)
-			AttachToComponent(Cast<USceneComponent>(TrackedComponent), FAttachmentTransformRules::SnapToTargetIncludingScale);
-
-	}
-	// Check for bAlwaysUseLiveLinkTracking here too in case we want to use LiveLink in Editor/Desktop mode.
-	else if (UVirtualRealityUtilities::IsDesktopMode() && !bAlwaysUseLiveLinkTracking)
-	{
-		switch(ProxyType)
-		{
-			case ETrackedComponentType::TCT_RIGHT_HAND:
-			case ETrackedComponentType::TCT_LEFT_HAND:
-			case ETrackedComponentType::TCT_HEAD:
-				TrackedComponent = GetOwner()->FindComponentByClass<UCameraComponent>(); //All are attached to camera
-				break;
-			case ETrackedComponentType::TCT_TRACKER_1:
-			case ETrackedComponentType::TCT_TRACKER_2:
-				TrackedComponent = GetOwner()->GetRootComponent();
-				break;
-		}
-		if (TrackedComponent) AttachToComponent(Cast<USceneComponent>(TrackedComponent), FAttachmentTransformRules::SnapToTargetIncludingScale);
-
-	}
-	// If we're either in the cave or using LiveLink, set it up here. Might want to differentiate between the two cases later on,
-	// for now both should be equivalent. Maybe set up some additional stuff automatically like presets etc.
-	else if (UVirtualRealityUtilities::IsRoomMountedMode() || bAlwaysUseLiveLinkTracking)
-	{
-		// Instead of using the clumsy LiveLinkComponentController, we just directly check the LiveLink Data in Tick later on.
-		// Set up this Component to Tick, and check whether Subject and Role is set.
-
-		// TODO: Check for AttachmentType and automatically get the respective Subject/Role. Need to investigate how those are called by DTrack.
-		TrackedComponent = this;
-		bUseLiveLinkTracking = true; // override this in case someone forgot to set it.
-		if (SubjectRepresentation.Subject.IsNone() || SubjectRepresentation.Role == nullptr)
-		{
-			UE_LOG(LogUniversalTrackedComponent, Error, TEXT("UUniversalTrackedComponent::BeginPlay(): No LiveLink Subject or Role is set! Tracking will not work"));
-		}
-		SetComponentTickEnabled(true);
-	}
-}
-
-void UUniversalTrackedComponent::PostLoad()
-{
-	Super::PostLoad();
-
-	// This is required in PostLoad (and theoretically in OnComponentCreated too) because just setting this in
-	// the constructor or PostInitializeProperties will load the CDO's property values.
-	// Just calling it in BeginPlay() won't let us see the LiveLink preview in the editor. 
-	bTickInEditor = bAlwaysUseLiveLinkTracking;	
-	PrimaryComponentTick.bStartWithTickEnabled =  bAlwaysUseLiveLinkTracking;	
-}
-
-#if WITH_EDITOR
-void UUniversalTrackedComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
-{
-	// Catch the change to bAlwaysUseLiveLinkTracking, and disable/enable tick respectively for in-editor tracking.
-	const FName PropertyName(PropertyChangedEvent.GetPropertyName());
-	if(PropertyName == GET_MEMBER_NAME_CHECKED(UUniversalTrackedComponent, bAlwaysUseLiveLinkTracking))
-	{
-		bTickInEditor = bAlwaysUseLiveLinkTracking;
-		SetComponentTickEnabled(bAlwaysUseLiveLinkTracking);
-	}
-	Super::PostEditChangeProperty(PropertyChangedEvent);
-}
-#endif
-
-
-void UUniversalTrackedComponent::TickComponent(const float DeltaTime, const ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
-{
-	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
-
-	// Check whether we need to update the component with new LiveLink data. This is either the case if
-	// nDisplay uses bUseLiveLinkTracking (Play Mode), or if bAlwaysUseLiveLinkTracking is true, then we tick both in Play Mode and Editor.
-	const bool bEvaluateLiveLink = bUseLiveLinkTracking || bAlwaysUseLiveLinkTracking;
-
-	if(!bEvaluateLiveLink || SubjectRepresentation.Subject.IsNone() || SubjectRepresentation.Role == nullptr)
-	{
-		return;
-	}
-
-	// Get the LiveLink interface and evaluate the current existing frame data for the given Subject and Role.
-	ILiveLinkClient& LiveLinkClient = IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(ILiveLinkClient::ModularFeatureName);
-	FLiveLinkSubjectFrameData SubjectData;
-	const bool bHasValidData = LiveLinkClient.EvaluateFrame_AnyThread(SubjectRepresentation.Subject, SubjectRepresentation.Role, SubjectData);
-
-	if(!bHasValidData)
-		return;
-
-	// Assume we are using a Transform Role to track the components! This is a slightly dangerous assumption, and could be further improved.
-	const FLiveLinkTransformStaticData* StaticData = SubjectData.StaticData.Cast<FLiveLinkTransformStaticData>();
-	const FLiveLinkTransformFrameData* FrameData = SubjectData.FrameData.Cast<FLiveLinkTransformFrameData>();
-
-	if (StaticData && FrameData)
-	{
-		// Finally, apply the transform to this component according to the static data.
-		ApplyLiveLinkTransform(FrameData->Transform, *StaticData);
-	}	
-}
-
-UMotionControllerComponent* UUniversalTrackedComponent::GetMotionControllerComponentByMotionSource(EControllerHand MotionSource) const
-{
-	TArray<UActorComponent*> Components;
-	GetOwner()->GetComponents(UMotionControllerComponent::StaticClass(),Components);
-	return Cast<UMotionControllerComponent>(
-		Components.FindByPredicate([&MotionSource](UActorComponent* Current)
-		{
-			switch(MotionSource)
-			{
-				case EControllerHand::Right:
-					return Cast<UMotionControllerComponent>(Current)->MotionSource == FName("Right");
-				case EControllerHand::Left:
-					return Cast<UMotionControllerComponent>(Current)->MotionSource == FName("Left");
-				default: return true;
-			}
-		})[0]
-	);
-}
-
-void UUniversalTrackedComponent::ApplyLiveLinkTransform(const FTransform& Transform, const FLiveLinkTransformStaticData& StaticData)
-{
-	if (bUseLocation && StaticData.bIsLocationSupported)
-	{
-		if (bWorldTransform)
-		{
-			this->SetWorldLocation(Transform.GetLocation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
-		}
-		else
-		{
-			this->SetRelativeLocation(Transform.GetLocation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
-		}
-	}
-
-	if (bUseRotation && StaticData.bIsRotationSupported)
-	{
-		if (bWorldTransform)
-		{
-			this->SetWorldRotation(Transform.GetRotation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
-		}
-		else
-		{
-			this->SetRelativeRotation(Transform.GetRotation(), bSweep, nullptr, bTeleport ? ETeleportType::TeleportPhysics : ETeleportType::ResetPhysics);
-		}
-	}
-
-	if (bUseScale && StaticData.bIsScaleSupported)
-	{
-		if (bWorldTransform)
-		{
-			this->SetWorldScale3D(Transform.GetScale3D());
-		}
-		else
-		{
-			this->SetRelativeScale3D(Transform.GetScale3D());
-		}
-	}	
-}
diff --git a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp
index 40b293ecdbc5da4bbf250bb32bafd97986000a4a..1d6ac46295f055d38c206a6757c0e0771d8fe103 100644
--- a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp
+++ b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp
@@ -85,7 +85,7 @@ void UVRPawnMovement::SetHeadComponent(USceneComponent* NewHeadComponent)
 	CapsuleColliderComponent->SetupAttachment(HeadComponent);
 	const float HalfHeight = 80.0f; //this is just an initial value to look good in editor
 	CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, HalfHeight);
-	CapsuleColliderComponent->SetWorldLocation(FVector(0.0f, 0.0f,HalfHeight));
+	CapsuleColliderComponent->SetWorldLocation(FVector(0.0f, 0.0f,-HalfHeight));
 }
 
 void UVRPawnMovement::SetCapsuleColliderToUserSize()
diff --git a/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp
index 324da1efed37f74ea74239577279b479bc192854..8cd1fd2992101b33b8f872833c8ecad8134798d8 100644
--- a/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp
+++ b/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp
@@ -4,9 +4,9 @@
 
 #include "Engine/LocalPlayer.h"
 #include "GameFramework/PlayerController.h"
-#include "Pawn/UniversalTrackedComponent.h"
 #include "EnhancedInputComponent.h"
 #include "EnhancedInputSubsystems.h"
+#include "MotionControllerComponent.h"
 #include "Camera/CameraComponent.h"
 #include "Pawn/VRPawnInputConfig.h"
 #include "Pawn/VRPawnMovement.h"
@@ -23,45 +23,54 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial
 
 	SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("Origin")));
 	
-	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
-	CameraComponent->SetupAttachment(RootComponent);
-	CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, BaseEyeHeight)); //so it is rendered correctly in editor
+	HeadCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
+	HeadCameraComponent->SetupAttachment(RootComponent);
+	HeadCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, BaseEyeHeight)); //so it is rendered correctly in editor
 	
-	Head = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Head"));
-	Head->ProxyType = ETrackedComponentType::TCT_HEAD;
-	Head->SetupAttachment(RootComponent);
-
-	CapsuleRotationFix = CreateDefaultSubobject<USceneComponent>(TEXT("CapsuleRotationFix"));
-	CapsuleRotationFix->SetUsingAbsoluteRotation(true);
-	CapsuleRotationFix->SetupAttachment(Head);
-
 	PawnMovement = CreateDefaultSubobject<UVRPawnMovement>(TEXT("Pawn Movement"));
 	PawnMovement->SetUpdatedComponent(RootComponent);
-	PawnMovement->SetHeadComponent(CapsuleRotationFix);
+	PawnMovement->SetHeadComponent(HeadCameraComponent);
 	
-	RightHand = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Right Hand"));
-	RightHand->ProxyType = ETrackedComponentType::TCT_RIGHT_HAND;
-	RightHand->AttachementType = EAttachementType::AT_FLYSTICK;
+	RightHand = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Right Hand MCC"));
 	RightHand->SetupAttachment(RootComponent);
 	
-	LeftHand = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Left Hand"));
-	LeftHand->ProxyType = ETrackedComponentType::TCT_LEFT_HAND;
-	LeftHand->AttachementType = EAttachementType::AT_HANDTARGET;
+	LeftHand = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("Left Hand MCC"));
 	LeftHand->SetupAttachment(RootComponent);
 
 	BasicVRInteraction = CreateDefaultSubobject<UBasicVRInteractionComponent>(TEXT("Basic VR Interaction"));
 	BasicVRInteraction->Initialize(RightHand);
-	
+}
+
+void AVirtualRealityPawn::Tick(float DeltaSeconds)
+{
+	Super::Tick(DeltaSeconds);
+
+	if (UVirtualRealityUtilities::IsDesktopMode())
+	{
+		SetCameraOffset();
+		UpdateRightHandForDesktopInteraction();
+	}
 }
 
 void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
 {
-	const APlayerController* PlayerController = Cast<APlayerController>(GetController());
+	APlayerController* PlayerController = Cast<APlayerController>(GetController());
+	if (!PlayerController) {
+		UE_LOG(LogTemp, Error, TEXT("PC Player Controller is invalid"));
+		return;
+	}
 	UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
 	if(!InputSubsystem)
 	{
 		UE_LOG(Toolkit,Error,TEXT("[VirtualRealiytPawn.cpp] InputSubsystem IS NOT VALID"));
 	}
+
+	if(UVirtualRealityUtilities::IsDesktopMode())
+	{
+		PlayerController->bShowMouseCursor = true;
+		PlayerController->bEnableClickEvents = true;
+		PlayerController->bEnableMouseOverEvents = true;
+	}
 	
 	InputSubsystem->ClearAllMappings();
 
@@ -74,8 +83,30 @@ void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInput
 	EI->BindAction(Fire, ETriggerEvent::Started, this, &AVirtualRealityPawn::OnBeginFire);
 	EI->BindAction(Fire, ETriggerEvent::Completed, this, &AVirtualRealityPawn::OnEndFire);
 
-	EI->BindAction(ToggleNavigationMode,ETriggerEvent::Started,this,&AVirtualRealityPawn::OnToggleNavigationMode);
-	
+	EI->BindAction(ToggleNavigationMode,ETriggerEvent::Started,this,&AVirtualRealityPawn::OnToggleNavigationMode);	
+}
+
+void AVirtualRealityPawn::UpdateRightHandForDesktopInteraction()
+{
+	APlayerController* PC = Cast<APlayerController>(GetController());
+	if (PC)
+	{
+		FVector MouseLocation, MouseDirection;
+		PC->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);
+		FRotator HandOrientation = MouseDirection.ToOrientationRotator();
+		RightHand->SetWorldRotation(HandOrientation);
+		RightHand->SetRelativeLocation(HeadCameraComponent->GetRelativeLocation());
+	}
+}
+
+void AVirtualRealityPawn::SetCameraOffset() const
+{
+	// this also incorporates the BaseEyeHeight, if set as static offset,
+	// rotations are still around the center of the pawn (on the floor), so pitch rotations look weird
+	FVector Location;
+	FRotator Rotation;
+	GetActorEyesViewPoint(Location, Rotation);
+	HeadCameraComponent->SetWorldLocationAndRotation(Location, Rotation);
 }
 
 // legacy grabbing
diff --git a/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp b/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp
index 2cfd23435ddcd3ae6a0f31c66e3a0b07d1f9b0d4..c335e156518151ccef60a186e8a4bc67b0c55903 100644
--- a/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp
+++ b/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp
@@ -4,12 +4,24 @@
 
 void FRWTHVRToolkitModule::StartupModule ()
 {
+
+	IModularFeatures& ModularFeatures = IModularFeatures::Get();
+	if (ModularFeatures.IsModularFeatureAvailable(ILiveLinkClient::ModularFeatureName))
+	{
+		FLiveLinkClient* LiveLinkClient = static_cast<FLiveLinkClient*>(&IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(
+			ILiveLinkClient::ModularFeatureName));
+		LiveLinkMotionController = MakeUnique<FLiveLinkMotionControllerFix>(*LiveLinkClient);
+		LiveLinkMotionController->RegisterController();
+	}
+	
 	ConsoleActivation.Register();
 }
 
 void FRWTHVRToolkitModule::ShutdownModule()
 {
-	ConsoleActivation.Unregister();	
+	ConsoleActivation.Unregister();
+	if (LiveLinkMotionController)
+		LiveLinkMotionController->UnregisterController();
 }
 
 
diff --git a/Source/RWTHVRToolkit/Public/Fixes/LiveLinkMotionControllerFix.h b/Source/RWTHVRToolkit/Public/Fixes/LiveLinkMotionControllerFix.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e8bb02b97f5c333281fd3b23df5109f9370b1ce
--- /dev/null
+++ b/Source/RWTHVRToolkit/Public/Fixes/LiveLinkMotionControllerFix.h
@@ -0,0 +1,221 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "Features/IModularFeatures.h"
+#include "IMotionController.h"
+#include "LiveLinkClient.h"
+
+#include "Roles/LiveLinkTransformRole.h"
+#include "Roles/LiveLinkTransformTypes.h"
+
+
+#define LOCTEXT_NAMESPACE "LiveLinkMotionController"
+
+
+class FLiveLinkMotionControllerFix : public IMotionController
+{
+	// Internal structure for caching enumerated data
+	struct FLiveLinkMotionControllerEnumeratedSource
+	{
+		// Subject key for talking to live link
+		FLiveLinkSubjectKey SubjectKey;
+
+		// MotionSource name for interacting with Motion Controller system
+		FName MotionSource;
+
+		FLiveLinkMotionControllerEnumeratedSource(const FLiveLinkSubjectKey& Key, FName MotionSourceName) : SubjectKey(Key), MotionSource(MotionSourceName) {}
+	};
+
+	// Built array of Live Link Sources to give to Motion Controller system
+	TArray<FLiveLinkMotionControllerEnumeratedSource> EnumeratedSources;
+
+public:
+	FLiveLinkMotionControllerFix(FLiveLinkClient& InClient) : Client(InClient)
+	{ 
+		BuildSourceData();
+		OnSubjectsChangedHandle = Client.OnLiveLinkSubjectsChanged().AddRaw(this, &FLiveLinkMotionControllerFix::OnSubjectsChangedHandler);
+		WildcardSource = FGuid::NewGuid();
+	}
+
+	~FLiveLinkMotionControllerFix()
+	{
+		Client.OnLiveLinkSubjectsChanged().Remove(OnSubjectsChangedHandle);
+		OnSubjectsChangedHandle.Reset();
+	}
+
+	void RegisterController()
+	{
+		IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
+	}
+
+	void UnregisterController()
+	{
+		IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
+	}
+
+	virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float) const override
+	{
+		FLiveLinkSubjectKey SubjectKey = GetSubjectKeyFromMotionSource(MotionSource);
+
+		FLiveLinkSubjectFrameData FrameData;
+		if (Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, ULiveLinkTransformRole::StaticClass(), FrameData))
+		{
+			if (FLiveLinkTransformFrameData* TransformFrameData = FrameData.FrameData.Cast<FLiveLinkTransformFrameData>())
+			{
+				OutPosition = TransformFrameData->Transform.GetLocation();
+				OutOrientation = TransformFrameData->Transform.GetRotation().Rotator();
+				return true;
+			}
+		}
+		return false;
+	}
+
+	virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, bool& OutbProvidedLinearVelocity, FVector& OutLinearVelocity, bool& OutbProvidedAngularVelocity, FVector& OutAngularVelocityAsAxisAndLength, bool& OutbProvidedLinearAcceleration, FVector& OutLinearAcceleration, float WorldToMetersScale) const override
+	{
+		OutbProvidedLinearVelocity = false;
+		OutbProvidedAngularVelocity = false;
+		OutbProvidedLinearAcceleration = false;
+		return GetControllerOrientationAndPosition(ControllerIndex, MotionSource, OutOrientation, OutPosition, WorldToMetersScale);
+	}
+	
+	virtual bool GetControllerOrientationAndPositionForTime(const int32 ControllerIndex, const FName MotionSource, FTimespan Time, bool& OutTimeWasUsed, FRotator& OutOrientation, FVector& OutPosition, bool& OutbProvidedLinearVelocity, FVector& OutLinearVelocity, bool& OutbProvidedAngularVelocity, FVector& OutAngularVelocityAsAxisAndLength, bool& OutbProvidedLinearAcceleration, FVector& OutLinearAcceleration, float WorldToMetersScale) const override
+	{
+		OutTimeWasUsed = false;
+		OutbProvidedLinearVelocity = false;
+		OutbProvidedAngularVelocity = false;
+		OutbProvidedLinearAcceleration = false;
+		return GetControllerOrientationAndPosition(ControllerIndex, MotionSource, OutOrientation, OutPosition, WorldToMetersScale);
+	}
+
+	float GetCustomParameterValue(const FName MotionSource, FName ParameterName, bool& bValueFound) const override
+	{
+		FLiveLinkSubjectKey SubjectKey = GetSubjectKeyFromMotionSource(MotionSource);
+
+		FLiveLinkSubjectFrameData EvaluatedData;
+		if (Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, ULiveLinkBasicRole::StaticClass(), EvaluatedData))
+		{
+			if (EvaluatedData.FrameData.GetBaseData())
+			{
+				FLiveLinkBaseFrameData& BaseFrameData = *EvaluatedData.FrameData.GetBaseData();
+
+				float FoundValue = 0.f;
+				if (EvaluatedData.StaticData.GetBaseData()->FindPropertyValue(BaseFrameData, ParameterName, FoundValue))
+				{
+					bValueFound = true;
+					return FoundValue;
+				}
+			}
+		}
+
+		bValueFound = false;
+		return 0.f;
+	}
+
+	virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const override
+	{
+		FLiveLinkSubjectKey SubjectKey = GetSubjectKeyFromMotionSource(MotionSource);
+
+		FLiveLinkSubjectFrameData EvaluatedData;
+		if (Client.EvaluateFrame_AnyThread(SubjectKey.SubjectName, ULiveLinkBasicRole::StaticClass(), EvaluatedData))
+		{
+			return ETrackingStatus::Tracked;
+		}
+		return ETrackingStatus::NotTracked;
+	}
+
+
+	virtual FName GetMotionControllerDeviceTypeName() const override
+	{
+		static FName LiveLinkMotionControllerName(TEXT("LiveLinkMotionController"));
+		return LiveLinkMotionControllerName;
+	}
+
+	// Builds cached source data for passing to motion controller system
+	void BuildSourceData()
+	{
+		TArray<FLiveLinkSubjectKey> SubjectKeys = Client.GetSubjects(true, true);
+
+		TMap<FGuid, TArray<FName>> LiveLinkSubjects;
+		LiveLinkSubjects.Add(WildcardSource);
+
+		for (const FLiveLinkSubjectKey& Subject : SubjectKeys)
+		{
+			LiveLinkSubjects.FindOrAdd(Subject.Source).Add(Subject.SubjectName);
+			LiveLinkSubjects.FindChecked(WildcardSource).Add(Subject.SubjectName);
+		}
+
+		TArray<FGuid> SourceGuids;
+		LiveLinkSubjects.GenerateKeyArray(SourceGuids);
+
+		typedef TPair<FGuid, FText> FHeaderEntry;
+		TArray<FHeaderEntry> Headers;
+		Headers.Reserve(SourceGuids.Num());
+
+		for (const FGuid& Source : SourceGuids)
+		{
+			FText SourceName = (Source == WildcardSource) ? LOCTEXT("LiveLinkAnySource", "Any") : Client.GetSourceType(Source);
+			Headers.Emplace(Source, SourceName);
+		}
+
+		{
+			FGuid& CaptureWildcardSource = WildcardSource;
+			Headers.Sort([CaptureWildcardSource](const FHeaderEntry& A, const FHeaderEntry& B) { return A.Key == CaptureWildcardSource || A.Value.CompareToCaseIgnored(B.Value) <= 0; });
+		}
+
+		//Build EnumeratedSources data
+		EnumeratedSources.Reset();
+		EnumeratedSources.Reserve(SubjectKeys.Num());
+
+		for (const FHeaderEntry& Header : Headers)
+		{
+			TArray<FName> Subjects = LiveLinkSubjects.FindChecked(Header.Key);
+			Subjects.Sort(FNameLexicalLess());
+			for (FName Subject : Subjects)
+			{
+				FName FullName = *FString::Format(TEXT("{0} ({1})"), { Subject.ToString(), Header.Value.ToString() });
+				EnumeratedSources.Emplace(FLiveLinkSubjectKey(Header.Key, Subject), FullName);
+			}
+		}
+	}
+
+	virtual void EnumerateSources(TArray<FMotionControllerSource>& Sources) const override
+	{
+		for (const FLiveLinkMotionControllerEnumeratedSource& Source : EnumeratedSources)
+		{
+			FMotionControllerSource SourceDesc(Source.MotionSource);
+#if WITH_EDITOR
+			static const FName LiveLinkCategoryName(TEXT("LiveLink"));
+			SourceDesc.EditorCategory = LiveLinkCategoryName;
+#endif
+			Sources.Add(SourceDesc);
+		}
+	}
+
+	virtual bool GetHandJointPosition(const FName MotionSource, int jointIndex, FVector& OutPosition) const override { return false; }
+
+private:
+	FLiveLinkSubjectKey GetSubjectKeyFromMotionSource(FName MotionSource) const
+	{
+		const FLiveLinkMotionControllerEnumeratedSource* EnumeratedSource = EnumeratedSources.FindByPredicate([&](const FLiveLinkMotionControllerEnumeratedSource& Item) { return Item.MotionSource == MotionSource; });
+		if (EnumeratedSource)
+		{
+			return EnumeratedSource->SubjectKey;
+		}
+		return FLiveLinkSubjectKey(FGuid(), MotionSource);
+	}
+
+	// Registered with the client and called when client's subjects change
+	void OnSubjectsChangedHandler() { BuildSourceData(); }
+
+	// Reference to the live link client
+	FLiveLinkClient& Client;
+
+	// Handle to delegate registered with client so we can update when subject state changes
+	FDelegateHandle OnSubjectsChangedHandle;
+
+	// Wildcard source, we don't care about the source itself, just the subject name
+	FGuid WildcardSource;
+};
+
+#undef LOCTEXT_NAMESPACE
diff --git a/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h b/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h
index 38bada0c11d392d7e011b4d9d2830c3399197bf2..7ef4d501d729ad9fb800bba06571bb7ee57add3f 100644
--- a/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h
+++ b/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h
@@ -89,10 +89,10 @@ public:
 private:
 	
 	UPROPERTY()
-	UUniversalTrackedComponent* MovementHand;
+	UMotionControllerComponent* MovementHand;
 	
 	UPROPERTY()
-	UUniversalTrackedComponent* RotationHand;
+	UMotionControllerComponent* RotationHand;
 
 	UPROPERTY()
 	class UInputMappingContext* IMCMovement;
@@ -101,11 +101,5 @@ private:
 
 	UPROPERTY()
 	AVirtualRealityPawn* VRPawn;
-
-	/**
-	* Fixes camera rotation in desktop mode.
-	*/
-	void SetCameraOffset() const;
-	void UpdateRightHandForDesktopInteraction();
 	
 };
diff --git a/Source/RWTHVRToolkit/Public/Pawn/TeleportationComponent.h b/Source/RWTHVRToolkit/Public/Pawn/TeleportationComponent.h
index 4521fdd7322e5880f533d674b73ee992ffbf926e..003f6a96f01ca828e2da9f1cde509a01a913d194 100644
--- a/Source/RWTHVRToolkit/Public/Pawn/TeleportationComponent.h
+++ b/Source/RWTHVRToolkit/Public/Pawn/TeleportationComponent.h
@@ -117,10 +117,10 @@ public:
 	
 private:
 	UPROPERTY()
-	UUniversalTrackedComponent* TeleportationHand;
+	UMotionControllerComponent* TeleportationHand;
 
 	UPROPERTY()
-	UUniversalTrackedComponent* RotationHand;
+	UMotionControllerComponent* RotationHand;
 
 	UPROPERTY()
 	class UInputMappingContext* IMCMovement;
diff --git a/Source/RWTHVRToolkit/Public/Pawn/UniversalTrackedComponent.h b/Source/RWTHVRToolkit/Public/Pawn/UniversalTrackedComponent.h
deleted file mode 100644
index 254863d0dec9643ccae920fbc3e6a6b0453d9d0e..0000000000000000000000000000000000000000
--- a/Source/RWTHVRToolkit/Public/Pawn/UniversalTrackedComponent.h
+++ /dev/null
@@ -1,128 +0,0 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "LiveLinkRole.h"
-#include "Components/SceneComponent.h"
-#include "MotionControllerComponent.h"
-#include "UniversalTrackedComponent.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(LogUniversalTrackedComponent, Log, All);
-
-struct FLiveLinkTransformStaticData;
-
-UENUM(BlueprintType)
-enum class ETrackedComponentType : uint8
-{
-	TCT_TRACKER_1 UMETA(DisplayName = "VIVE Tracker 1"),
-	TCT_TRACKER_2 UMETA(DisplayName = "VIVE Tracker 2"),
-	TCT_RIGHT_HAND UMETA(DisplayName = "Right Hand"),
-	TCT_LEFT_HAND UMETA(DisplayName = "Left Hand"),
-	TCT_HEAD UMETA(DisplayName = "Head")
-};
-
-UENUM(BlueprintType)
-enum class EAttachementType : uint8
-{
-	AT_NONE UMETA(DisplayName = "Not attached"),
-	AT_HANDTARGET UMETA(DisplayName = "To the right/left hand target"),
-	AT_FLYSTICK UMETA(DisplayName = "To the Flystick"),
-	AT_CUSTOM_SUBJECT UMETA(DisplayName = "Custom LiveLink Subject|Role")
-};
-
-/*
- * Acts as an intelligent proxy object, when attached to a Pawn class
- * Attaches itself to the specified controller (Camera, MotionController, TrackedDevice) once they are available
- * Behaves according to the ETrackedComponentType which has to be set before starting
- */
-
-UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
-class RWTHVRTOOLKIT_API UUniversalTrackedComponent : public USceneComponent
-{
-	GENERATED_BODY()
-
-public:	
-	// Sets default values for this component's properties
-	UUniversalTrackedComponent();
-
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking")
-	ETrackedComponentType ProxyType = ETrackedComponentType::TCT_HEAD;
-
-	/** Set whether LiveLink should always be enabled, even in the editor or desktop mode. Overrides bUseLiveLinkTracking.*/
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking", meta = (DisplayName = "Override all tracking with LiveLink"))
-	bool bAlwaysUseLiveLinkTracking;
-
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking|nDisplay")
-	EAttachementType AttachementType = EAttachementType::AT_NONE;
-
-	/** Set whether nDisplay should use LiveLink tracking. Requires a valid Subject Representation!*/
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking|nDisplay")
-	bool bUseLiveLinkTracking = true;
-
-	/** Set the LiveLink Subject Representation to be used by this component. */
-	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	FLiveLinkSubjectRepresentation SubjectRepresentation;
-
-	/** Set the transform of the component in world space of in its local reference frame. */
-	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	bool bWorldTransform = false;
-
-	/** Whether we should set the owning actor's location with the value coming from live link. */
-	UPROPERTY(EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	bool bUseLocation = true;
-
-	/** Whether we should set the owning actor's rotation with the value coming from live link. */
-	UPROPERTY(EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	bool bUseRotation = true;
-	
-	/** Whether we should set the owning actor's scale with the value coming from live link. */
-	UPROPERTY(EditAnywhere, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	bool bUseScale = true;
-
-	/**
-	 * Whether we sweep to the destination location, triggering overlaps along the way and stopping short of the target if blocked by something.
-	 * Only the root component is swept and checked for blocking collision, child components move without sweeping. If collision is off, this has no effect.
-	 */
-	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	bool bSweep = false;
-
-	/**
-	 * Whether we teleport the physics state (if physics collision is enabled for this object).
-	 * If true, physics velocity for this object is unchanged (so ragdoll parts are not affected by change in location).
-	 * If false, physics velocity is updated based on the change in position (affecting ragdoll parts).
-	 * If CCD is on and not teleporting, this will affect objects along the entire sweep volume.
-	 */
-	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tracking|nDisplay|LiveLink", meta = (EditCondition = "AttachementType==EAttachementType::AT_CUSTOM_SUBJECT"))
-	bool bTeleport = true;
-	
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking|HMD", BlueprintSetter=SetShowDeviceModel)
-	bool bShowDeviceModelInHMD = true;
-
-	UFUNCTION(BlueprintSetter)
-	void SetShowDeviceModel(const bool bShowControllerModel);
-
-	//~ Begin SceneComponent Interface	
-	virtual void BeginPlay() override;
-	virtual void PostLoad() override;
-	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
-
-#if WITH_EDITOR
-	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
-#endif
-	//~ End SceneComponent Interface
-
-private:
-
-	/**
-	 * @brief Helper function that applies the LiveLink data to this component. Taken from the LiveLink Transform Controller.
-	 * @param Transform Transform read from the LiveLink Client.
-	 * @param StaticData Static data from the LiveLink Subject, defines what is and isn't supported.
-	 * @return void
-	 */
-	void ApplyLiveLinkTransform(const FTransform& Transform, const FLiveLinkTransformStaticData& StaticData);
-	
-	USceneComponent* TrackedComponent = nullptr;
-	UMotionControllerComponent* GetMotionControllerComponentByMotionSource(EControllerHand MotionSource) const;	
-	
-};
diff --git a/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h b/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h
index 21ba56b809f3c642243650ce6df4774f12cf19c0..36bd4233955a8fdbb0f3eb13d4d6e5a56bed92c1 100644
--- a/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h
+++ b/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h
@@ -4,13 +4,12 @@
 
 #include "BasicVRInteractionComponent.h"
 #include "CoreMinimal.h"
-#include "UniversalTrackedComponent.h"
 #include "Pawn/VRPawnMovement.h"
 #include "VirtualRealityPawn.generated.h"
 
 class UCameraComponent;
 class ULiveLinkComponentController;
-
+class UMotionControllerComponent;
 
 /**
  * 
@@ -21,32 +20,26 @@ class RWTHVRTOOLKIT_API AVirtualRealityPawn : public APawn
 	GENERATED_BODY()
 public:
 	AVirtualRealityPawn(const FObjectInitializer& ObjectInitializer);
+
+	virtual void Tick(float DeltaSeconds) override;
 	
-	/* Proxy */
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Proxy Objects")
-	UUniversalTrackedComponent* Head;
-	
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Proxy Objects")
-	UUniversalTrackedComponent* RightHand;
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|MotionControllers")
+	UMotionControllerComponent* RightHand;
 	
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Proxy Objects")
-	UUniversalTrackedComponent* LeftHand;
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|MotionControllers")
+	UMotionControllerComponent* LeftHand;
 
 	/* Interaction */
 	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Interaction")
 	UBasicVRInteractionComponent* BasicVRInteraction;
 	
 	/* Movement */
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement")
-	UVRPawnMovement* PawnMovement;
-
-	
 	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Movement")
-	USceneComponent* CapsuleRotationFix;
+	UVRPawnMovement* PawnMovement;
 	
 	/* CameraComponent */
 	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera")
-	UCameraComponent* CameraComponent;
+	UCameraComponent* HeadCameraComponent;
 
 
 protected:
@@ -72,4 +65,10 @@ protected:
 	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pawn|Input")
 	class UInputAction* ToggleNavigationMode;
 
+	/**
+	* Fixes camera rotation in desktop mode.
+	*/
+	void SetCameraOffset() const;
+	void UpdateRightHandForDesktopInteraction();
+
 };
diff --git a/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h b/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h
index fa1843ded226c6fcd438ea1e22f1acdc83632906..c1d682b4edf75806bf8d48debc8eb4bafbb0b06c 100644
--- a/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h
+++ b/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h
@@ -2,6 +2,7 @@
 
 #include "CoreMinimal.h"
 #include "Fixes/ActivateConsoleInShipping.h"
+#include "Fixes/LiveLinkMotionControllerFix.h"
 
 
 class FRWTHVRToolkitModule : public IModuleInterface
@@ -11,5 +12,6 @@ public:
 	virtual void ShutdownModule() override;
 	
 private:
-	FActivateConsoleInShipping ConsoleActivation;	
+	FActivateConsoleInShipping ConsoleActivation;
+	TUniquePtr<FLiveLinkMotionControllerFix> LiveLinkMotionController;
 };