diff --git a/Content/Calibratio/CalibratioHud.uasset b/Content/Calibratio/CalibratioHud.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..f72b8fb6c7505876dc1fcc035d1ed07048865527
Binary files /dev/null and b/Content/Calibratio/CalibratioHud.uasset differ
diff --git a/Content/Calibratio/CalibratioMaterial.uasset b/Content/Calibratio/CalibratioMaterial.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..c1ff5f0bd9e92786b74edd76e5ca51ee81db1413
Binary files /dev/null and b/Content/Calibratio/CalibratioMaterial.uasset differ
diff --git a/Content/Calibratio/Cylinder.uasset b/Content/Calibratio/Cylinder.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..23a1be42460bdae72d9bd601de338681336e6e4f
Binary files /dev/null and b/Content/Calibratio/Cylinder.uasset differ
diff --git a/RWTHVRToolkit.uplugin b/RWTHVRToolkit.uplugin
index a0891804774aa9a6dc48313dedd275af7cd477fa..690ed43563cb6a18ecc61882b4f323688117263a 100644
--- a/RWTHVRToolkit.uplugin
+++ b/RWTHVRToolkit.uplugin
@@ -15,6 +15,11 @@
   "Installed": false,
   "EnabledByDefault": true,
   "Modules": [
+	{
+      "Name": "Calibratio",
+      "Type": "Runtime",
+      "LoadingPhase": "Default"
+    },
     {
       "Name": "RWTHVRToolkit",
       "Type": "Runtime",
diff --git a/Source/Calibratio/Calibratio.Build.cs b/Source/Calibratio/Calibratio.Build.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ed66e1ac1b86072a467f014f24569661d284f5c5
--- /dev/null
+++ b/Source/Calibratio/Calibratio.Build.cs
@@ -0,0 +1,32 @@
+using UnrealBuildTool;
+
+public class Calibratio : ModuleRules
+{
+	public Calibratio(ReadOnlyTargetRules Target) : base(Target)
+	{
+		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
+
+		PublicIncludePaths.AddRange(
+			new string[]{}
+		);
+
+		PrivateIncludePaths.AddRange(
+			new string[]{}
+		);
+
+		PublicDependencyModuleNames.AddRange(
+			new string[]
+			{
+				"Core", "CoreUObject", "Engine", "UMG", "SlateCore", "DisplayCluster", "RWTHVRToolkit"
+            }
+		);
+
+		PrivateDependencyModuleNames.AddRange(
+			new string[]{}
+		);
+
+		DynamicallyLoadedModuleNames.AddRange(
+			new string[]{}
+		);
+	}
+}
diff --git a/Source/Calibratio/Private/Calibratio.cpp b/Source/Calibratio/Private/Calibratio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3a085b211c93c002c619d4e1264a8945deea291
--- /dev/null
+++ b/Source/Calibratio/Private/Calibratio.cpp
@@ -0,0 +1,55 @@
+#include "Calibratio.h"
+#include "Kismet/GameplayStatics.h"
+#include "IDisplayCluster.h"
+#include "Cluster/DisplayClusterClusterEvent.h"
+#include "Utility/VirtualRealityUtilities.h"
+
+#define LOCTEXT_NAMESPACE "FCalibratioModule"
+
+void FCalibratioModule::StartupModule ()
+{
+	/* Registering console command */
+	CalibratioConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand(TEXT("Calibratio"), TEXT("Spawn an instance of calibratio"),
+		FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray< FString >&)
+	{
+		if(UVirtualRealityUtilities::IsRoomMountedMode()){
+			/* Emitting cluster event to spawn on all nodes in sync*/
+			FDisplayClusterClusterEventJson ClusterEvent;
+			ClusterEvent.Name = "CalibratioSpawn";
+			ClusterEvent.Category = "CalibratioSpawner";
+			IDisplayCluster::Get().GetClusterMgr()->EmitClusterEventJson(ClusterEvent, false);
+		} else {
+			SpawnCalibratio();
+		}
+	}));
+
+	
+	/* Register cluster event listening */
+	IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
+	if (ClusterManager && !ClusterEventListenerDelegate.IsBound())
+	{
+		ClusterEventListenerDelegate = FOnClusterEventJsonListener::CreateLambda([](const FDisplayClusterClusterEventJson& Event)
+		{
+			if (Event.Category.Equals("CalibratioSpawner") && Event.Name.Equals("CalibratioSpawn"))
+			{
+				SpawnCalibratio();
+			}
+		});
+		ClusterManager->AddClusterEventJsonListener(ClusterEventListenerDelegate);
+	}
+}
+void FCalibratioModule::ShutdownModule()
+{
+	IConsoleManager::Get().UnregisterConsoleObject(CalibratioConsoleCommand);
+	IDisplayCluster::Get().GetClusterMgr()->RemoveClusterEventJsonListener(ClusterEventListenerDelegate);
+}
+
+void FCalibratioModule::SpawnCalibratio()
+{ 
+	if (UGameplayStatics::GetActorOfClass(GEngine->GetCurrentPlayWorld(), ACalibratioActor::StaticClass()) != nullptr) return;
+	GEngine->GetCurrentPlayWorld()->SpawnActor<ACalibratioActor>();
+}
+
+#undef LOCTEXT_NAMESPACE
+
+IMPLEMENT_MODULE(FCalibratioModule, Calibratio)
\ No newline at end of file
diff --git a/Source/Calibratio/Private/CalibratioActor.cpp b/Source/Calibratio/Private/CalibratioActor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ebf58ec63d04156f5ce3b6d031285c58fd054899
--- /dev/null
+++ b/Source/Calibratio/Private/CalibratioActor.cpp
@@ -0,0 +1,323 @@
+#include "CalibratioActor.h"
+
+#include "Components/StaticMeshComponent.h"
+#include "Cluster/DisplayClusterClusterEvent.h"
+#include "IDisplayCluster.h"
+#include "TimerManager.h"
+#include "CalibratioOverlay.h"
+#include "GameFramework/InputSettings.h"
+#include "Utility/VirtualRealityUtilities.h"
+
+ACalibratioActor::ACalibratioActor()
+{
+	PrimaryActorTick.bCanEverTick = true;
+	AutoReceiveInput = EAutoReceiveInput::Player0;
+
+	/* Loads needed Assets */
+	UStaticMesh* CylinderMesh = nullptr;
+	UVirtualRealityUtilities::LoadClass("WidgetBlueprint'/RWTHVRToolkit/Calibratio/CalibratioHud'", Overlay_Class);
+	UVirtualRealityUtilities::LoadAsset("StaticMesh'/RWTHVRToolkit/Calibratio/Cylinder'", CylinderMesh);
+	UVirtualRealityUtilities::LoadAsset("Material'/RWTHVRToolkit/Calibratio/CalibratioMaterial'", BaseMaterial);
+
+	/* Create Mesh component and initialize */
+	Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
+	Mesh->SetupAttachment(RootComponent);
+	Mesh->SetStaticMesh(CylinderMesh);
+	Mesh->SetRelativeScale3D(FVector(1,1,0.1f)); //Make it a Disk
+	RootComponent = Mesh;
+}
+
+// Called when the game starts or when spawned
+void ACalibratioActor::BeginPlay()
+{
+	Super::BeginPlay();
+
+	/* Register cluster event listener */
+	IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
+	if (ClusterManager && !ClusterEventListenerDelegate.IsBound())
+	{
+		ClusterEventListenerDelegate = FOnClusterEventJsonListener::CreateUObject(this, &ACalibratioActor::HandleClusterEvent);
+		ClusterManager->AddClusterEventJsonListener(ClusterEventListenerDelegate);
+	}
+
+	/* Create Overlay */
+	Overlay = CreateWidget<UCalibratioOverlay>(GetWorld()->GetFirstPlayerController(), Overlay_Class);
+	Overlay->AddToViewport(0);
+	Overlay->SetThresholds(MinRotation, MaxRotation, Threshold);
+	Overlay->SetOwner(this);
+
+	/* Bind Buttons */
+	Overlay->ResettingButton->OnClicked.AddDynamic(this, &ACalibratioActor::ClusterReset);
+	Overlay->IncreaseThresholdButton->OnClicked.AddDynamic(this, &ACalibratioActor::ClusterIncreaseThreshold);
+	Overlay->DecreaseThresholdButton->OnClicked.AddDynamic(this, &ACalibratioActor::ClusterDecreaseThreshold);
+
+	/* Hide this overlay on all clients */
+	if (UVirtualRealityUtilities::IsSlave())
+	{
+		Overlay->SetVisibility(ESlateVisibility::Hidden);
+	}
+}
+
+void ACalibratioActor::PostInitializeComponents()
+{
+	Super::PostInitializeComponents();
+
+	/* Create dynamic materials at runtime (Not constructor) */
+	DynamicMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, RootComponent);
+	DynamicMaterial->SetVectorParameterValue("Color", FColor::Red);
+	Mesh->SetMaterial(0, DynamicMaterial);
+}
+
+void ACalibratioActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	/* Remove from Cluster events */
+	IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
+	if (ClusterManager && ClusterEventListenerDelegate.IsBound())
+	{
+		ClusterManager->RemoveClusterEventJsonListener(ClusterEventListenerDelegate);
+	}
+
+	Super::EndPlay(EndPlayReason);
+
+	/* Remove components */
+	GetWorld()->GetTimerManager().ClearTimer(ResetTimerHandle);
+	if(Overlay->IsInViewport()) Overlay->RemoveFromViewport();
+}
+
+void ACalibratioActor::HandleClusterEvent(const FDisplayClusterClusterEventJson& Event)
+{
+	if(!Event.Category.Equals("Calibratio")) return; //Not our Business
+	
+	if (Event.Name == "CalibratioReset")
+	{
+		LocalReset();
+	}
+	else if (Event.Name == "CalibratioSetThreshold" && Event.Parameters.Contains("NewThreshold"))
+	{
+		LocalSetThreshold(FCString::Atof(*Event.Parameters["NewThreshold"]));
+	}
+	else if (Event.Name == "CalibratioArmAndSetCalibration" && Event.Parameters.Contains("NewMin") && Event.Parameters.Contains("NewMax"))
+	{
+		LocalArmAndSetCalibration(FCString::Atof(*Event.Parameters["NewMin"]), FCString::Atof(*Event.Parameters["NewMax"]));
+	}
+	else if (Event.Name == "CalibratioDespawn")
+	{
+		LocalDespawn();
+	}
+}
+
+void ACalibratioActor::ClusterReset()
+{
+	if(UVirtualRealityUtilities::IsRoomMountedMode())
+	{
+		IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr();
+		if (!Manager) return;
+
+		FDisplayClusterClusterEventJson ClusterEvent;
+		ClusterEvent.Name = "CalibratioReset";
+		ClusterEvent.Category = "Calibratio";
+		Manager->EmitClusterEventJson(ClusterEvent, true);
+	}
+	else if(UVirtualRealityUtilities::IsDesktopMode())
+	{
+		LocalReset();
+	}
+}
+
+void ACalibratioActor::LocalReset()
+{
+	DynamicMaterial->SetVectorParameterValue("Color", FColor::Red);
+	CurrentCalibrationRuns = 0;
+	MaxRotation = -FLT_MAX;
+	MinRotation = FLT_MAX;
+	LastRotations.Empty();
+	LastRotations.Reserve(MaxCalibrationRuns);
+}
+
+void ACalibratioActor::ClusterIncreaseThreshold()
+{
+	ClusterChangeThreshold(FMath::DegreesToRadians(0.1f));
+}
+
+void ACalibratioActor::ClusterDecreaseThreshold()
+{
+	ClusterChangeThreshold(-FMath::DegreesToRadians(0.1f));
+}
+
+void ACalibratioActor::ClusterChangeThreshold(float Value)
+{
+	const float NewThreshold = Threshold + Value;
+
+	if(UVirtualRealityUtilities::IsRoomMountedMode())
+	{
+		IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr();
+		if (!Manager) return;
+
+		FDisplayClusterClusterEventJson ClusterEvent;
+		ClusterEvent.Name = "CalibratioSetThreshold";
+		ClusterEvent.Category = "Calibratio";
+		ClusterEvent.Parameters.Add("NewThreshold",FString::SanitizeFloat(NewThreshold));
+		Manager->EmitClusterEventJson(ClusterEvent, true);
+	}
+	else if(UVirtualRealityUtilities::IsDesktopMode())
+	{
+		LocalSetThreshold(NewThreshold);		
+	}
+}
+
+void ACalibratioActor::LocalSetThreshold(float NewValue)
+{
+	Threshold = NewValue;
+	Overlay->SetThresholds(MinRotation, MaxRotation, Threshold);
+}
+
+void ACalibratioActor::ClusterArmAndSetCalibration(float MinAngle, float MaxAngle)
+{
+	if(UVirtualRealityUtilities::IsRoomMountedMode())
+	{
+		IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr();
+		if (!Manager) return;
+
+		FDisplayClusterClusterEventJson ClusterEvent;
+		ClusterEvent.Name = "CalibratioArmAndSetCalibration";
+		ClusterEvent.Category = "Calibratio";
+		ClusterEvent.Parameters.Add("NewMin",FString::SanitizeFloat(MinAngle));
+		ClusterEvent.Parameters.Add("NewMax",FString::SanitizeFloat(MaxAngle));
+		Manager->EmitClusterEventJson(ClusterEvent, true);
+	}
+	else if(UVirtualRealityUtilities::IsDesktopMode())
+	{
+		LocalArmAndSetCalibration(MinAngle, MaxAngle);
+	}
+}
+
+void ACalibratioActor::LocalArmAndSetCalibration(float NewMin, float NewMax)
+{
+	MinRotation = NewMin;
+	MaxRotation = NewMax;
+	Overlay->SetStatus(Waiting);
+	DynamicMaterial->SetVectorParameterValue("Color", FColor::Black);
+	CurrentCalibrationRuns = MaxCalibrationRuns + 1; //Arm
+}
+
+void ACalibratioActor::ClusterDespawn()
+{
+	if (UVirtualRealityUtilities::IsRoomMountedMode())
+	{
+		IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr();
+		if (!Manager) return;
+
+		FDisplayClusterClusterEventJson ClusterEvent;
+		ClusterEvent.Name = "CalibratioDespawn";
+		ClusterEvent.Category = "Calibratio";
+		Manager->EmitClusterEventJson(ClusterEvent, true);
+	}
+	else if (UVirtualRealityUtilities::IsDesktopMode())
+	{
+		LocalDespawn();
+	}
+}
+void ACalibratioActor::LocalDespawn()
+{
+	GetWorld()->DestroyActor(this); // Destroy ourself
+}
+
+void ACalibratioActor::Tick(const float DeltaSeconds)
+{
+	Super::Tick(DeltaSeconds);
+
+	/* Search for tracker */
+	if(!TrackedClusterComponent)
+	{
+		TrackedClusterComponent = UVirtualRealityUtilities::GetNamedClusterComponent(ENamedClusterComponent::NCC_CALIBRATIO);
+	} else
+	{
+		const FVector NewPos = TrackedClusterComponent->GetComponentLocation();
+		if(NewPos != LastVisiblePosition)
+		{
+			if(FirstPositionSet) LastTimeVisible = FDateTime::Now();
+
+			LastVisiblePosition = NewPos;
+			FirstPositionSet = true;
+		} 
+	}
+
+	if (!IsTrackerCurrentlyVisible() || !TrackedClusterComponent)
+	{
+		Overlay->SetPhysicalStatus(NotFound);
+		Overlay->SetStatus(Waiting);
+		return;
+	}
+
+	/* Tracker is visible */
+	const float Rotation = TrackedClusterComponent->GetRelativeRotation().Yaw;
+
+	/* First run, place mesh */
+	if (CurrentCalibrationRuns == 0)
+	{
+		Mesh->SetRelativeLocation(TrackedClusterComponent->GetRelativeLocation());
+	}
+	/* More calibration runs to go */
+	if (CurrentCalibrationRuns < MaxCalibrationRuns)
+	{
+		Overlay->SetStatus(Calibrating);
+		if (IsDeviceMoving(Rotation))
+		{
+			Overlay->SetPhysicalStatus(Moving);
+			LocalReset();
+		}
+		else
+		{
+			Overlay->SetPhysicalStatus(Found);
+			CalibrationRun(Rotation);
+		}
+	}
+	/* Calibration finished */
+	else if (CurrentCalibrationRuns == MaxCalibrationRuns)
+	{
+		ClusterArmAndSetCalibration(MinRotation, MaxRotation); /* Sync to other nodes */
+	}
+	/* Actual Measuring */
+	else if (Rotation < MinRotation - Threshold || Rotation > MaxRotation + Threshold)
+	{
+		if (!GetWorld()->GetTimerManager().IsTimerActive(ResetTimerHandle))
+		{
+			DynamicMaterial->SetVectorParameterValue("Color", FColor::White);
+			Overlay->SetStatus(Triggered);
+			GetWorld()->GetTimerManager().SetTimer(ResetTimerHandle, this, &ACalibratioActor::ClusterReset, ResetTime, false);
+		}
+	}
+}
+
+/* Checks if last 10 calls to this function handed in roughly the same Angle */
+bool ACalibratioActor::IsDeviceMoving(float Angle)
+{
+	LastRotations.Add(Angle); /* Push into back */
+	if (LastRotations.Num() > 10) LastRotations.RemoveAt(0); /* Remove first one */
+	
+	float Sum = 0.0f;
+	for (float& CurrentAngle : LastRotations)
+	{
+		Sum += CurrentAngle;
+	}
+	const float Average = Sum / LastRotations.Num();
+	
+	return FMath::Abs(Average - Angle) > 5 * Threshold && LastRotations.Num() >= 10;
+}
+
+/* Adjusts min and max rotation values */
+void ACalibratioActor::CalibrationRun(float Angle)
+{
+	if(!UVirtualRealityUtilities::IsMaster()) return; //Not our Business
+	
+	MinRotation = FMath::Min(MinRotation, Angle);
+	MaxRotation = FMath::Max(MaxRotation, Angle);
+	Overlay->SetThresholds(MinRotation, MaxRotation, Threshold);
+	
+	CurrentCalibrationRuns++;
+}
+
+bool ACalibratioActor::IsTrackerCurrentlyVisible()
+{
+	return (FDateTime::Now() - LastTimeVisible).GetTotalMilliseconds() <= AcceptedAbscenceTime;
+}
diff --git a/Source/Calibratio/Private/CalibratioOverlay.cpp b/Source/Calibratio/Private/CalibratioOverlay.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af91d38aa2403abd2c70739c3731027b5d65d42c
--- /dev/null
+++ b/Source/Calibratio/Private/CalibratioOverlay.cpp
@@ -0,0 +1,60 @@
+#include "CalibratioOverlay.h"
+
+bool UCalibratioOverlay::Initialize()
+{
+	const bool Result = Super::Initialize();
+	DismissButton->OnClicked.AddDynamic(this, &UCalibratioOverlay::Dismiss);
+	return Result;
+}
+
+void UCalibratioOverlay::SetStatus(const ECalibratioProtocolStatus Status)
+{
+	if(CurrentStatus == Status) return;
+	switch(Status)
+	{
+	case Calibrating:
+		StatusProtocol->SetText(FText::FromString(TEXT("Calibrating")));
+		break;
+	case Waiting:
+		StatusProtocol->SetText(FText::FromString(TEXT("Waiting")));
+		break;
+	case Triggered:
+		StatusProtocol->SetText(FText::FromString(TEXT("Triggered")));
+		break;
+	}
+	CurrentStatus = Status;
+}
+
+void UCalibratioOverlay::SetThresholds(const float Min, const float Max, const float Threshold)
+{
+	MinAngle->SetText(FText::FromString(FString::Printf(TEXT("%.2f\u00B0"), FMath::Fmod(FMath::RadiansToDegrees(Min), 360))));
+	MaxAngle->SetText(FText::FromString(FString::Printf(TEXT("%.2f\u00B0"), FMath::Fmod(FMath::RadiansToDegrees(Max), 360))));
+	CurrentThreshold->SetText(FText::FromString(FString::Printf(TEXT("+-%.2f\u00B0s"), FMath::Fmod(FMath::RadiansToDegrees(Threshold), 360))));
+}
+
+void UCalibratioOverlay::SetPhysicalStatus(const ECalibratioPhysicalStatus Status)
+{
+	if(CurrentPhysicalStatus == Status) return;
+	switch(Status)
+	{
+	case Found:
+		StatusCalibratio->SetText(FText::FromString(TEXT("Found")));
+		StatusCalibratio->SetColorAndOpacity(FSlateColor(FLinearColor::Green));
+		break;
+	case Unknown:
+	case NotFound:
+		StatusCalibratio->SetText(FText::FromString(TEXT("Not Found")));
+		StatusCalibratio->SetColorAndOpacity(FSlateColor(FLinearColor::Red));
+		break;
+	case Moving:
+		StatusCalibratio->SetText(FText::FromString(TEXT("Moving")));
+		StatusCalibratio->SetColorAndOpacity(FSlateColor(FLinearColor::Yellow));
+		break;
+	}
+	CurrentPhysicalStatus = Status;
+}
+
+void UCalibratioOverlay::Dismiss()
+{
+	Owner->ClusterDespawn();
+}
diff --git a/Source/Calibratio/Public/Calibratio.h b/Source/Calibratio/Public/Calibratio.h
new file mode 100644
index 0000000000000000000000000000000000000000..0acb193d56c0d4535840d100a5ad9d149289ee9a
--- /dev/null
+++ b/Source/Calibratio/Public/Calibratio.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Modules/ModuleManager.h"
+#include "CalibratioActor.h"
+#include "Cluster/IDisplayClusterClusterManager.h"
+
+class FCalibratioModule : public IModuleInterface
+{
+public:
+	virtual void StartupModule () override;
+	virtual void ShutdownModule() override;
+
+public:
+	static void SpawnCalibratio();
+
+private:
+	IConsoleCommand* CalibratioConsoleCommand = nullptr;
+	FOnClusterEventJsonListener ClusterEventListenerDelegate;
+};
diff --git a/Source/Calibratio/Public/CalibratioActor.h b/Source/Calibratio/Public/CalibratioActor.h
new file mode 100644
index 0000000000000000000000000000000000000000..a2bac0d157826ae3ff515032a5170a7704e40b08
--- /dev/null
+++ b/Source/Calibratio/Public/CalibratioActor.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Materials/MaterialInstanceDynamic.h"
+#include "Cluster/IDisplayClusterClusterManager.h"
+#include "Components/DisplayClusterSceneComponent.h"
+
+#include "GameFramework/Actor.h"
+#include "CalibratioActor.generated.h"
+
+UCLASS()
+class CALIBRATIO_API ACalibratioActor : public AActor
+{
+	GENERATED_BODY()
+
+public:
+	ACalibratioActor();
+
+protected:
+	virtual void BeginPlay() override;
+	virtual void PostInitializeComponents() override;
+	virtual void Tick(float DeltaSeconds) override;
+	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
+
+public:
+	UPROPERTY(VisibleAnywhere) UStaticMeshComponent* Mesh;
+	UPROPERTY(EditAnywhere) UMaterialInterface* BaseMaterial;
+	UPROPERTY(BlueprintReadWrite) float Threshold = FMath::DegreesToRadians(1.7f);
+	UPROPERTY(BlueprintReadWrite) float ResetTime = 0.5f;
+	UFUNCTION(Blueprintcallable) void ClusterDespawn();
+
+private:
+	DECLARE_DELEGATE_OneParam(FThresholdDelegate, float);
+	FOnClusterEventJsonListener ClusterEventListenerDelegate;
+
+	void CalibrationRun(float Angle);
+	bool IsTrackerCurrentlyVisible();
+	void LocalSetThreshold(float NewValue);
+	void LocalArmAndSetCalibration(float NewMin, float NewMax);
+	void LocalDespawn();
+	bool IsDeviceMoving(float Angle);
+	void LocalReset();
+
+	// Handling Cluster events
+	UFUNCTION() void ClusterReset();
+	UFUNCTION() void ClusterIncreaseThreshold();
+	UFUNCTION() void ClusterDecreaseThreshold();
+	void ClusterChangeThreshold(float Value);
+	void ClusterArmAndSetCalibration(float MinAngle, float MaxAngle);
+	void HandleClusterEvent(const FDisplayClusterClusterEventJson& Event);
+
+	float MinRotation{0};
+	float MaxRotation{0};
+	int CurrentCalibrationRuns{0};
+	int MaxCalibrationRuns{60};
+	FTimerHandle ResetTimerHandle;
+	TArray<float> LastRotations;
+
+	UPROPERTY() UMaterialInstanceDynamic* DynamicMaterial = nullptr;
+
+	FDateTime LastTimeVisible = FDateTime::MinValue();
+	FVector LastVisiblePosition = FVector(NAN, NAN, NAN);
+	bool FirstPositionSet = false;
+	uint32 AcceptedAbscenceTime = 500u; // in Milliseconds
+	UPROPERTY() UDisplayClusterSceneComponent* TrackedClusterComponent = nullptr;
+
+	//Overlay
+	TSubclassOf<class UCalibratioOverlay> Overlay_Class;
+	UPROPERTY() UCalibratioOverlay* Overlay;
+};
diff --git a/Source/Calibratio/Public/CalibratioOverlay.h b/Source/Calibratio/Public/CalibratioOverlay.h
new file mode 100644
index 0000000000000000000000000000000000000000..c7968074fd6fecf3bd3b4cf3ae57dd64982c978c
--- /dev/null
+++ b/Source/Calibratio/Public/CalibratioOverlay.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include "CoreMinimal.h"
+
+#include "CalibratioActor.h"
+#include "Blueprint/UserWidget.h"
+#include "Components/TextBlock.h"
+#include "Components/Button.h"
+
+#include "CalibratioOverlay.generated.h"
+
+
+UENUM(BlueprintType)
+enum ECalibratioProtocolStatus
+{
+	Calibrating,
+	Waiting,
+	Triggered
+};
+
+UENUM(BlueprintType)
+enum ECalibratioPhysicalStatus
+{
+	Moving,
+	Found,
+	NotFound,
+	Unknown
+};
+
+/**
+ * This is the parent class for the Overlay that is used on the master.
+ * All declarations in it are magically bound to the UMG child class if they are named the same (see "meta = (BindWidget)")
+ */
+UCLASS()
+class CALIBRATIO_API UCalibratioOverlay : public UUserWidget
+{
+	GENERATED_BODY()
+
+virtual bool Initialize() override;
+public:
+	/* Public Buttons */
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UButton* ResettingButton;
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UButton* IncreaseThresholdButton;
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UButton* DecreaseThresholdButton;
+
+protected:
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UButton* DismissButton;
+
+	/* Numbers: */
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UTextBlock* CurrentThreshold;
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UTextBlock* MinAngle;
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UTextBlock* MaxAngle;
+
+	/* Status: */
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UTextBlock* StatusProtocol;
+	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
+	UTextBlock* StatusCalibratio;
+
+public:
+	UFUNCTION() void SetStatus(ECalibratioProtocolStatus Status);
+	UFUNCTION() void SetThresholds(float Min, float Max, float Threshold);
+	UFUNCTION() void SetPhysicalStatus(ECalibratioPhysicalStatus Status);
+	void SetOwner(ACalibratioActor* InOwner) {Owner = InOwner;}
+	UFUNCTION() void Dismiss();
+
+private:
+	ECalibratioPhysicalStatus CurrentPhysicalStatus = Unknown;
+	ECalibratioProtocolStatus CurrentStatus = Calibrating;
+	UPROPERTY() ACalibratioActor* Owner;
+};
diff --git a/Source/RWTHVRToolkit/Private/Cluster/CAVEOverlay/CAVEOverlayController.cpp b/Source/RWTHVRToolkit/Private/Cluster/CAVEOverlay/CAVEOverlayController.cpp
index 71251d1765a7797731356eed2cc8fb2ae49bc7bf..96b53f9733aecd65ab685348cb3aa1d35412f1ad 100644
--- a/Source/RWTHVRToolkit/Private/Cluster/CAVEOverlay/CAVEOverlayController.cpp
+++ b/Source/RWTHVRToolkit/Private/Cluster/CAVEOverlay/CAVEOverlayController.cpp
@@ -33,15 +33,6 @@ UStaticMeshComponent* ACAVEOverlayController::CreateMeshComponent(const FName& N
 	return Result;
 }
 
-template <typename T>
-bool LoadAsset(const FString& Path, T* & Result)
-{
-	ConstructorHelpers::FObjectFinder<T> Loader(*Path);
-	Result = Loader.Object;
-	if (!Loader.Succeeded()) UE_LOG(LogCAVEOverlay, Error, TEXT("Could not find %s. Have you renamed it?"), *Path);
-	return Loader.Succeeded();
-}
-
 // Sets default values
 ACAVEOverlayController::ACAVEOverlayController()
 {
@@ -69,9 +60,9 @@ ACAVEOverlayController::ACAVEOverlayController()
 	SignRoot->SetupAttachment(Root);
 
 	//Loading of Materials and Meshes
-	LoadAsset("/RWTHVRToolkit/CAVEOverlay/Stripes", TapeMaterial);
-	LoadAsset("/RWTHVRToolkit/CAVEOverlay/StopMaterial", SignMaterial);
-	LoadAsset("/RWTHVRToolkit/CAVEOverlay/Plane", PlaneMesh);
+	UVirtualRealityUtilities::LoadAsset("/RWTHVRToolkit/CAVEOverlay/Stripes", TapeMaterial);
+	UVirtualRealityUtilities::LoadAsset("/RWTHVRToolkit/CAVEOverlay/StopMaterial", SignMaterial);
+	UVirtualRealityUtilities::LoadAsset("/RWTHVRToolkit/CAVEOverlay/Plane", PlaneMesh);
 
 	TapeNegativeY = CreateMeshComponent("TapeNegY", PlaneMesh, TapeRoot);
 	TapeNegativeX = CreateMeshComponent("TapeNegX", PlaneMesh, TapeRoot);
diff --git a/Source/RWTHVRToolkit/Private/Cluster/ClusterConsole.cpp b/Source/RWTHVRToolkit/Private/Cluster/ClusterConsole.cpp
index 7f4ecc4086c0664f1a7f11fbce5be6c47acf0566..966f4f01cd87adbb2318c49411c9b69b343cc9c0 100644
--- a/Source/RWTHVRToolkit/Private/Cluster/ClusterConsole.cpp
+++ b/Source/RWTHVRToolkit/Private/Cluster/ClusterConsole.cpp
@@ -8,7 +8,7 @@ void FClusterConsole::Register()
 	ClusterConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand(TEXT("ClusterExecute"), TEXT("<Your Command> - Execute commands on every node of the nDisplay cluster by prepending ClusterExecute"),
 		FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray< FString >& Args)
 	{
-		if(IDisplayCluster::Get().GetClusterMgr() == nullptr) return;
+		if(IDisplayCluster::Get().GetClusterMgr() == nullptr || Args.Num() == 0) return;
 		
 		/* Emitting cluster event */
 		FDisplayClusterClusterEventJson ClusterEvent;
diff --git a/Source/RWTHVRToolkit/Private/Fixes/ActivateConsoleInShipping.cpp b/Source/RWTHVRToolkit/Private/Fixes/ActivateConsoleInShipping.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9164ffbcbe5f86a906c972c9631c421e2e9ba863
--- /dev/null
+++ b/Source/RWTHVRToolkit/Private/Fixes/ActivateConsoleInShipping.cpp
@@ -0,0 +1,24 @@
+#include "Fixes/ActivateConsoleInShipping.h"
+#include "Engine/Console.h"
+
+void FActivateConsoleInShipping::Register()
+{
+	if(FApp::GetBuildConfiguration() != EBuildConfiguration::Shipping) return; /* Should only enable console in shipping */
+
+	On_Post_World_Initialization_Delegate.BindRaw(this, &FActivateConsoleInShipping::OnSessionStart);
+	StartHandle = FWorldDelegates::OnPostWorldInitialization.Add(On_Post_World_Initialization_Delegate);
+}
+
+void FActivateConsoleInShipping::Unregister() const
+{
+	if(FApp::GetBuildConfiguration() != EBuildConfiguration::Shipping) return;
+
+    FWorldDelegates::OnPostWorldInitialization.Remove(StartHandle);
+}
+
+void FActivateConsoleInShipping::OnSessionStart(UWorld* World, const UWorld::InitializationValues Values) const
+{
+    if(!World->IsGameWorld() || !World->GetGameViewport() || World->GetGameViewport()->ViewportConsole != nullptr) return;
+
+    World->GetGameViewport()->ViewportConsole = NewObject<UConsole>(World->GetGameViewport());
+}
diff --git a/Source/RWTHVRToolkit/Private/Fixes/FixNDisplayStereoDevice.cpp b/Source/RWTHVRToolkit/Private/Fixes/FixNDisplayStereoDevice.cpp
deleted file mode 100644
index 3b946733acc7e188612b9e449773154db58b9993..0000000000000000000000000000000000000000
--- a/Source/RWTHVRToolkit/Private/Fixes/FixNDisplayStereoDevice.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "Fixes/FixNDisplayStereoDevice.h"
-
-void FFixNDisplayStereoDevice::Register()
-{
-	On_Post_World_Initialization_Delegate.BindRaw(this, &FFixNDisplayStereoDevice::OnSessionStart);
-	StartHandle = FWorldDelegates::OnPostWorldInitialization.Add(On_Post_World_Initialization_Delegate);
-
-	On_Pre_World_Finish_Destroy_Delegate.BindRaw(this, &FFixNDisplayStereoDevice::OnSessionEnd);
-	EndHandle = FWorldDelegates::OnPreWorldFinishDestroy.Add(On_Pre_World_Finish_Destroy_Delegate);
-}
-
-void FFixNDisplayStereoDevice::Unregister()
-{
-	FWorldDelegates::OnPostWorldInitialization.Remove(StartHandle);
-	FWorldDelegates::OnPreWorldFinishDestroy.Remove(EndHandle);
-}
-
-void FFixNDisplayStereoDevice::OnSessionStart(UWorld*, const UWorld::InitializationValues)
-{
-	/* Store handle before it is released */
-	if(GEngine)
-	{
-		StoredRenderingDevice = GEngine->StereoRenderingDevice;
-	}
-}
-
-void FFixNDisplayStereoDevice::OnSessionEnd(UWorld*)
-{
-	/* Restore handle after it was released */
-	if(GEngine)
-	{
-		GEngine->StereoRenderingDevice = StoredRenderingDevice;
-	}
-}
diff --git a/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp b/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp
index 1b35313f6149bdfd35643d44764cb49f524d0c8d..bf76c57c0140c3239bac2d16e89ee351364e0849 100644
--- a/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp
+++ b/Source/RWTHVRToolkit/Private/RWTHVRToolkit.cpp
@@ -5,14 +5,14 @@
 void FRWTHVRToolkitModule::StartupModule ()
 {
 	ClusterConsole.Register();
-	StereoDeviceFix.Register();
 	CAVEOverlay.Register();
+	ConsoleActivation.Register();
 }
 void FRWTHVRToolkitModule::ShutdownModule()
 {
 	ClusterConsole.Unregister();
-	StereoDeviceFix.Unregister();
 	CAVEOverlay.Unregister();
+	ConsoleActivation.Unregister();
 }
 
 #undef LOCTEXT_NAMESPACE
diff --git a/Source/RWTHVRToolkit/Private/Utility/VirtualRealityUtilities.cpp b/Source/RWTHVRToolkit/Private/Utility/VirtualRealityUtilities.cpp
index 418b350fa7ce3b798516a43195d75afcc189d45b..2260a1e7261a3addb792a7d531b49da615db6af5 100644
--- a/Source/RWTHVRToolkit/Private/Utility/VirtualRealityUtilities.cpp
+++ b/Source/RWTHVRToolkit/Private/Utility/VirtualRealityUtilities.cpp
@@ -104,7 +104,8 @@ FString UVirtualRealityUtilities::GetNodeName()
 float UVirtualRealityUtilities::GetEyeDistance()
 {
 #if PLATFORM_SUPPORTS_NDISPLAY
-	return IDisplayCluster::Get().GetGameMgr()->GetRootActor()->GetDefaultCamera()->GetInterpupillaryDistance();
+	ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
+	return (RootActor) ? RootActor->GetDefaultCamera()->GetInterpupillaryDistance() : 0;
 #else
 	return 0;
 #endif
@@ -113,7 +114,8 @@ float UVirtualRealityUtilities::GetEyeDistance()
 EEyeStereoOffset UVirtualRealityUtilities::GetNodeEyeType()
 {
 #if PLATFORM_SUPPORTS_NDISPLAY
-	return static_cast<EEyeStereoOffset>(IDisplayCluster::Get().GetGameMgr()->GetRootActor()->GetDefaultCamera()->GetStereoOffset());
+	ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
+	return (RootActor) ? RootActor->GetDefaultCamera()->GetStereoOffset() : EDisplayClusterEyeStereoOffset::None;
 #else
 	return None;
 #endif
@@ -122,7 +124,8 @@ EEyeStereoOffset UVirtualRealityUtilities::GetNodeEyeType()
 USceneComponent* UVirtualRealityUtilities::GetClusterComponent(const FString& Name)
 {
 #if PLATFORM_SUPPORTS_NDISPLAY
-	return IDisplayCluster::Get().GetGameMgr()->GetRootActor()->GetComponentById(Name);
+	ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
+	return (RootActor) ? RootActor->GetComponentById(Name) : nullptr;
 #else
 	return nullptr;
 #endif
@@ -141,6 +144,7 @@ USceneComponent* UVirtualRealityUtilities::GetNamedClusterComponent(const ENamed
 	case ENamedClusterComponent::NCC_FLYSTICK: return GetClusterComponent("flystick");
 	case ENamedClusterComponent::NCC_TDW_ORIGIN: return GetClusterComponent("tdw_origin_floor");
 	case ENamedClusterComponent::NCC_TDW_CENTER: return GetClusterComponent("tdw_center");
+	case ENamedClusterComponent::NCC_CALIBRATIO: return GetClusterComponent("calibratio");
 	case ENamedClusterComponent::NCC_TRACKING_ORIGIN:
 		USceneComponent* Result;
 		if((Result = GetClusterComponent("cave_origin"))) return Result;
@@ -150,4 +154,3 @@ USceneComponent* UVirtualRealityUtilities::GetNamedClusterComponent(const ENamed
 	default: return nullptr;
 	}
 }
-
diff --git a/Source/RWTHVRToolkit/Public/Fixes/ActivateConsoleInShipping.h b/Source/RWTHVRToolkit/Public/Fixes/ActivateConsoleInShipping.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae67362545450edba46a852c9d318cf1cf073c19
--- /dev/null
+++ b/Source/RWTHVRToolkit/Public/Fixes/ActivateConsoleInShipping.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Engine/World.h"
+#include "ActivateConsoleInShipping.generated.h"
+
+/**
+ * This fixes activates the debugging console shipping builds. Unfortunately, it can't activate the auto-completion inside the console
+ */
+USTRUCT()
+struct RWTHVRTOOLKIT_API FActivateConsoleInShipping
+{
+	GENERATED_BODY()
+
+	void Register();
+	void Unregister() const;
+	
+private:
+	void OnSessionStart(UWorld*, const UWorld::InitializationValues) const;
+
+	TDelegate<void (UWorld*, const UWorld::InitializationValues)> On_Post_World_Initialization_Delegate;
+
+	FDelegateHandle StartHandle;
+};
diff --git a/Source/RWTHVRToolkit/Public/Fixes/FixNDisplayStereoDevice.h b/Source/RWTHVRToolkit/Public/Fixes/FixNDisplayStereoDevice.h
deleted file mode 100644
index 81761f9df315466baccd090dfca962fc7ad903d4..0000000000000000000000000000000000000000
--- a/Source/RWTHVRToolkit/Public/Fixes/FixNDisplayStereoDevice.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "Engine/World.h"
-#include "FixNDisplayStereoDevice.generated.h"
-
-/**
- * This fixes the behavior of nDisplay DisplayClusterRenderManager, which resets the global stereo render device
- * This is problematic, since it resets the pointer (L128) to the StereoRenderDevice, even if it does not re-initialize (L113) it.
- * This results in a fine first start, but crashes on the second VR start. For Desktop this seems to still function fine.
- *
- * For this behavior a Pull-Request is in progress. See https://github.com/EpicGames/UnrealEngine/pull/7738
- */
-USTRUCT()
-struct RWTHVRTOOLKIT_API FFixNDisplayStereoDevice
-{
-	GENERATED_BODY()
-
-	void Register();
-	void Unregister();
-	
-private:
-	void OnSessionStart(UWorld*, const UWorld::InitializationValues);
-	void OnSessionEnd(UWorld*);
-
-	TSharedPtr< class IStereoRendering, ESPMode::ThreadSafe > StoredRenderingDevice;
-
-	TDelegate<void (UWorld*, const UWorld::InitializationValues)> On_Post_World_Initialization_Delegate;
-	TDelegate<void (UWorld*)> On_Pre_World_Finish_Destroy_Delegate;
-
-	FDelegateHandle StartHandle;
-	FDelegateHandle EndHandle;
-};
diff --git a/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h b/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h
index 3e0da836a6f873c48c5e4a8c3ef5475e8c0e352f..eb0b6662ae73da395fcd4c433b6ad601ca0c8ba1 100644
--- a/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h
+++ b/Source/RWTHVRToolkit/Public/RWTHVRToolkit.h
@@ -2,9 +2,9 @@
 
 #include "CoreMinimal.h"
 #include "Cluster/CAVEOverlay/CAVEOverlay.h"
-#include "Fixes/FixNDisplayStereoDevice.h"
 #include "Modules/ModuleManager.h"
 #include "Cluster/ClusterConsole.h"
+#include "Fixes/ActivateConsoleInShipping.h"
 
 
 class FRWTHVRToolkitModule : public IModuleInterface
@@ -15,6 +15,6 @@ public:
 
 private:
 	FClusterConsole ClusterConsole;
-	FFixNDisplayStereoDevice StereoDeviceFix;
 	FCAVEOverlay CAVEOverlay;
+	FActivateConsoleInShipping ConsoleActivation;
 };
diff --git a/Source/RWTHVRToolkit/Public/Utility/VirtualRealityUtilities.h b/Source/RWTHVRToolkit/Public/Utility/VirtualRealityUtilities.h
index d96d066b0045f4909a1c17c44969455728601369..ac1d18728792013b9c759fdefe3582ed12bad7c3 100644
--- a/Source/RWTHVRToolkit/Public/Utility/VirtualRealityUtilities.h
+++ b/Source/RWTHVRToolkit/Public/Utility/VirtualRealityUtilities.h
@@ -21,6 +21,7 @@ enum class ENamedClusterComponent : uint8
 	NCC_TDW_CENTER UMETA(DisplayName = "TDW Center"),
 
 	/* Non Specific */
+	NCC_CALIBRATIO UMETA(DisplayName = "Calibratio Motion to Photon Measurement Device"),
 	NCC_SHUTTERGLASSES UMETA(DisplayName = "CAVE/ROLV/TDW Shutter Glasses"),
 	NCC_FLYSTICK UMETA(DisplayName = "CAVE/ROLV/TDW Flystick"),
 	NCC_TRACKING_ORIGIN UMETA(DisplayName = "CAVE/ROLV/TDW Origin")
@@ -55,7 +56,33 @@ public:
 
 	UFUNCTION(BlueprintPure, Category = "DisplayCluster") static EEyeStereoOffset GetNodeEyeType();
 
-	//Get Compenent of Display Cluster by it's name, which is specified in the nDisplay config
+	//Get Component of Display Cluster by it's name, which is specified in the nDisplay config
 	UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster") static USceneComponent* GetClusterComponent(const FString& Name);
 	UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster") static USceneComponent* GetNamedClusterComponent(const ENamedClusterComponent& Component);
+
+	/* Load and create an Object from an asset path. This only works in the constructor */
+    template <class T>
+    static bool LoadAsset(const FString& Path, T*& Result);
+
+    /* Finds and returns a class of an asset. This only works in the constructor */
+    template <class T>
+    static bool LoadClass(const FString& Path, TSubclassOf<T>& Result);
 };
+
+template <typename T>
+bool UVirtualRealityUtilities::LoadAsset(const FString& Path, T* & Result)
+{
+	ConstructorHelpers::FObjectFinder<T> Loader(*Path);
+	Result = Loader.Object;
+	if (!Loader.Succeeded()) UE_LOG(LogTemp, Error, TEXT("Could not find %s. Have you renamed it?"), *Path);
+	return Loader.Succeeded();
+}
+
+template <typename T>
+bool UVirtualRealityUtilities::LoadClass(const FString& Path, TSubclassOf<T> & Result)
+{
+    ConstructorHelpers::FClassFinder<T> Loader(*Path);
+	Result = Loader.Class;
+	if (!Loader.Succeeded()) UE_LOG(LogTemp, Error, TEXT("Could not find %s. Have you renamed it?"), *Path);
+	return Loader.Succeeded();
+}
\ No newline at end of file
diff --git a/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp b/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp
index 22e614956f4810a3d4326318c5ac211d677ef861..ca8f91aab9430ac8b1617d1b1c365ad1d045f3d5 100644
--- a/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp
+++ b/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp
@@ -12,7 +12,7 @@
 
 IMPLEMENT_GAME_MODULE(FRWTHVRToolkitEditorModule, RWTHVRToolkitEditor);
 
-#define LOCTEXT_NAMESPACE "RWTHVRToolkitEdito"
+#define LOCTEXT_NAMESPACE "RWTHVRToolkitEditor"
 
 void FRWTHVRToolkitEditorModule::StartupModule()
 {