PortraitRenderer.cs
using Sandbox;
using System;
using System.Linq;

public sealed class PortraitRenderer : Component
{
    [Property] 
    public CameraComponent Camera { get; set; }

    public Texture RenderedTexture { get; private set; }

    private GameObject _headObj;
    private Vector3 _localFaceDir;

    protected override void OnStart()
    {
        if ( Camera == null ) Camera = Components.Get<CameraComponent>();

        var bodyRenderer = GameObject.Root.Components.GetAll<SkinnedModelRenderer>( FindMode.EverythingInSelfAndDescendants ).FirstOrDefault();
        if ( bodyRenderer != null )
        {
            string[] boneNames = { "head", "Head", "mixamorig:Head", "Bip01_Head", "Bip01 Head", "neck", "Neck" };
            foreach ( var name in boneNames )
            {
                var obj = bodyRenderer.GetBoneObject( name );
                if ( obj.IsValid() )
                {
                    _headObj = obj;
                    break;
                }
            }

            if ( _headObj != null )
            {
                // На старті гри персонаж дивиться туди ж, куди й Root (вперед).
                // Ми вираховуємо, яка саме локальна вісь кістки голови відповідає за "перед" обличчя!
                var rootForward = GameObject.Root.Transform.Rotation.Forward;
                _localFaceDir = _headObj.Transform.Rotation.Inverse * rootForward;
            }

            bodyRenderer.GameObject.Tags.Add( "portrait_target" );
        }
    }

    protected override void OnUpdate()
    {
        if ( Camera != null && RenderedTexture == null )
        {
            RenderedTexture = Texture.CreateRenderTarget()
                .WithSize( 256, 256 )
                .WithFormat( ImageFormat.RGBA8888 )
                .Create();

            Camera.RenderTarget = RenderedTexture;
            Camera.RenderTags.Add( "portrait_target" );
            Camera.ZNear = 1f;
        }

        if ( Camera != null )
        {
            if ( _headObj != null )
            {
                // Отримуємо поточний СВІТОВИЙ напрямок обличчя (крутиться разом з анімаціями)
                Vector3 worldFaceDir = _headObj.Transform.Rotation * _localFaceDir;
                
                Vector3 headPos = _headObj.Transform.Position;

                // Жорстко ставимо камеру на 30 юнітів ПЕРЕД обличчям (ігноруючи те, як вона стоїть у редакторі)
                Vector3 cameraPos = headPos + worldFaceDir * 30f;
                
                // Камера дивиться на лице. Вектор Up забороняє їй завалюватися набік.
                Rotation cameraRot = Rotation.LookAt( -worldFaceDir, Vector3.Up );

                Transform.World = new Transform( cameraPos, cameraRot );
            }
            else
            {
                // Запасний варіант, якщо кістки взагалі немає
                var rootForward = GameObject.Root.Transform.Rotation.Forward;
                var headPos = GameObject.Root.Transform.Position + Vector3.Up * 64f;
                Transform.World = new Transform( headPos + rootForward * 30f, Rotation.LookAt( -rootForward, Vector3.Up ) );
            }
        }
    }
}