VrCalibrationRig.cs
using Sandbox;

/// <summary>Local-only VR join rig: tracked camera, no locomotion, WorldPanel calibration UI.</summary>
public sealed class VrCalibrationRig : Component
{
	public PlayerSession Session { get; set; }

	private CameraComponent _camera;
	private GameObject _panelGo;

	private const float PanelDistance = 40f;
	private const float PanelHeightOffset = -4f;

	/// <summary>Call after the VR root (with camera) has been parented under this rig.</summary>
	public void EnsurePanel()
	{
		ResolveCamera();

		if ( !_panelGo.IsValid() )
			CreateWorldPanel();
	}

	protected override void OnUpdate()
	{
		ResolveCamera();

		if ( !_panelGo.IsValid() )
			CreateWorldPanel();

		UpdatePanelTransform();
	}

	private void ResolveCamera()
	{
		if ( _camera.IsValid() )
			return;

		_camera = Components.Get<CameraComponent>( FindMode.EnabledInSelfAndDescendants );
	}

	protected override void OnDestroy()
	{
		if ( _panelGo.IsValid() )
			_panelGo.Destroy();

		_panelGo = null;
	}

	/// <summary>Eye height above this rig's floor origin, matching in-game duck measurement.</summary>
	public float MeasureEyeHeight()
	{
		if ( !_camera.IsValid() )
			return Input.VR.Head.Position.z;

		return _camera.WorldPosition.z - WorldPosition.z;
	}

	private void CreateWorldPanel()
	{
		_panelGo = new GameObject( parent: GameObject, name: "HeightCalibrationPanel" )
		{
			NetworkMode = NetworkMode.Never
		};

		var worldPanel = _panelGo.AddComponent<WorldPanel>();
		worldPanel.PanelSize = new Vector2( 700f, 560f );
		worldPanel.RenderScale = 0.25f;
		worldPanel.LookAtCamera = true;
		worldPanel.InteractionRange = 1000f;

		_panelGo.AddComponent<HeightCalibrationPanel>();

		Log.Info( "VrCalibrationRig: HeightCalibrationPanel WorldPanel created." );
		UpdatePanelTransform();
	}

	private void UpdatePanelTransform()
	{
		if ( !_panelGo.IsValid() )
			return;

		if ( _camera.IsValid() )
		{
			var camTx = _camera.WorldTransform;
			_panelGo.WorldPosition = camTx.Position
				+ camTx.Forward * PanelDistance
				+ camTx.Up * PanelHeightOffset;
			return;
		}

		// Fallback before headset tracking settles: place in front of the spawn facing.
		_panelGo.WorldPosition = WorldPosition
			+ WorldRotation.Forward * PanelDistance
			+ Vector3.Up * 60f;
	}
}