{"TotalCount":609,"Files":[{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"FlowSampler.cs","FileName":"FlowSampler.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"// C# adaptation of FlowHMR\u0027s x1 Euler sampling. See THIRD_PARTY_NOTICES.md.\nusing System;\nusing System.Threading;\n\nnamespace HumanoidMocapX;\n\n/// \u003Csummary\u003EPredicts the clean 491-channel motion latent at a normalized time in [0,1).\n/// Writes every output element; failures and cancellation propagate.\u003C/summary\u003E\npublic delegate void FlowPrediction(ReadOnlySpan\u003Cfloat\u003E state, float time, Span\u003Cfloat\u003E output, CancellationToken cancellation);\n\n/// \u003Csummary\u003EThe released Base and Latest models use twenty Euler steps and x1 prediction.\u003C/summary\u003E\npublic static class FlowSampler\n{\n    public const int Channels = 491;\n    public const int Steps = 20;\n\n    /// \u003Csummary\u003EReplaces caller-supplied initial noise with sampled motion using a reusable\n    /// prediction buffer. Rejects invalid shapes and non-finite predictions. A failed or\n    /// cancelled run may leave state partially advanced; it must not be exported.\u003C/summary\u003E\n    public static void Sample(float[] state, float[] prediction, FlowPrediction predict,\n        CancellationToken cancellation = default)\n    {\n        ArgumentNullException.ThrowIfNull(state);\n        ArgumentNullException.ThrowIfNull(prediction);\n        ArgumentNullException.ThrowIfNull(predict);\n        if (state.Length == 0 || state.Length % Channels != 0 || state.Length / Channels \u003E FlowMotion.MaximumFrames\n            || prediction.Length != state.Length || ReferenceEquals(state, prediction))\n            throw new ArgumentException(\u0022Sampling needs separate, equally sized [frames,491] state and prediction buffers.\u0022);\n        CheckFinite(state);\n        const float minimumRemaining = 1f / Steps;\n        for (var step = 0; step \u003C Steps; step\u002B\u002B)\n        {\n            cancellation.ThrowIfCancellationRequested();\n            var time = step / (float)Steps;\n            var delta = (step \u002B 1) / (float)Steps - time;\n            predict(state, time, prediction, cancellation);\n            cancellation.ThrowIfCancellationRequested();\n            CheckFinite(prediction);\n            var remaining = Math.Max(1f - time, minimumRemaining);\n            for (var i = 0; i \u003C state.Length; i\u002B\u002B)\n                state[i] \u002B= (prediction[i] - state[i]) / remaining * delta;\n            CheckFinite(state);\n        }\n    }\n\n    static void CheckFinite(ReadOnlySpan\u003Cfloat\u003E values)\n    {\n        foreach (var value in values)\n            if (!float.IsFinite(value)) throw new ArithmeticException(\u0022FlowHMR sampling produced or received a non-finite latent.\u0022);\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HostedCaptureOptions.cs","FileName":"HostedCaptureOptions.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\n\nnamespace HumanoidMocapX;\n\n/// \u003Csummary\u003EVideo-range and model settings sent to a processing host. Times are source seconds.\u003C/summary\u003E\npublic sealed record HostedCaptureOptions(FlowModel Model, int CameraInterval, double Start, double? End)\n{\n    /// \u003Csummary\u003ERejects unsupported models, sampling intervals and invalid time ranges.\u003C/summary\u003E\n    public void Validate()\n    {\n        new CaptureOptions { Model = Model, CameraInterval = CameraInterval }.Validate();\n        if (!double.IsFinite(Start) || Start \u003C 0 || End is double end \u0026\u0026 (!double.IsFinite(end) || end \u003C= Start))\n            throw new ArgumentException(\u0022The video range needs a finite, nonnegative start and a later end.\u0022);\n    }\n}\n\n/// \u003Csummary\u003EProtocol version, processor readiness, the upload limit in bytes, how many unfinished\n/// jobs one account may have, how many jobs wait and run across all accounts, how many process at\n/// once, and the longest video range in seconds. A provider\u0027s site reports the signed-in account\u0027s\n/// own limits and whether its jobs wait in the priority queue.\u003C/summary\u003E\npublic sealed record HostedCapabilities(int Protocol, bool ProcessingAvailable, long MaximumUploadBytes,\n    int MaximumActiveJobs = 1, int QueueLength = 0, int Processing = 0, int ConcurrentJobs = 1,\n    double? MaximumClipSeconds = null, bool Priority = false);\n\n/// \u003Csummary\u003EJob state returned by the host. QueuePosition is one-based while queued, out of\n/// QueueLength waiting jobs; Progress (0 to 1) is set while processing. SecondsUntilStart and\n/// SecondsRemaining are the host\u0027s estimates. ExpiresAt is when a finished job and its result\n/// are deleted. Priority jobs wait ahead of the others. IDs are opaque; result URLs are derived locally.\u003C/summary\u003E\n#nullable enable annotations\npublic sealed record HostedJob(Guid Id, string State, string Message, int? QueuePosition = null, string? Name = null,\n    DateTimeOffset CreatedAt = default, int QueueLength = 0, double? Progress = null, int? SecondsUntilStart = null,\n    int? SecondsRemaining = null, DateTimeOffset? ExpiresAt = null, bool Priority = false);\n#nullable restore\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Formats/Fbx/FbxImportOptions.cs","FileName":"FbxImportOptions.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing System.Threading;\nusing HumanoidMocapX.Core.Maths;\nusing HumanoidMocapX.Core.Skeleton;\n\nnamespace HumanoidMocapX.Core.Formats.Fbx;\n\nusing Vector3 = System.Numerics.Vector3; // s\u0026box compat: shadow engine\u0027s global-namespace Vector3 (see Code/HumanoidMocap/Assembly.cs)\n\n/// \u003Csummary\u003EOptions for \u003Csee cref=\u0022FbxImporter.Import\u0022/\u003E.\u003C/summary\u003E\npublic sealed class FbxImportOptions\n{\n    /// \u003Csummary\u003EFixed resampling rate for all clips, frames per second.\u003C/summary\u003E\n    public float SampleFps { get; init; } = 30f;\n    public long MaximumTransformSamples { get; init; } = long.MaxValue;\n    public CancellationToken CancellationToken { get; init; }\n\n    /// \u003Csummary\u003E\n    /// When the static rest pose is degenerate (Mixamo-style zeroed bind translations) and no\n    /// usable BindPose node exists, sample frame 0 of the first clip as the rest pose.\n    /// \u003C/summary\u003E\n    public bool RestFromFrame0WhenBindDegenerate { get; init; } = true;\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Formats/Fbx/FbxTransform.cs","FileName":"FbxTransform.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Numerics;\nusing HumanoidMocapX.Core.Maths;\n\nnamespace HumanoidMocapX.Core.Formats.Fbx;\n\nusing Vector3 = System.Numerics.Vector3; // s\u0026box compat: shadow engine\u0027s global-namespace Vector3 (see Code/HumanoidMocap/Assembly.cs)\n\n/// \u003Csummary\u003E\n/// Per-node FBX local-transform evaluation: the static pivot/pre-rotation data of one Model\n/// plus the full FBX transform formula.\n/// \u003C/summary\u003E\n/// \u003Cremarks\u003E\n/// The FBX SDK formula (column-vector convention, right-multiply children):\n/// \u003Ccode\u003E\n/// World = ParentWorld \u00B7 T \u00B7 Roff \u00B7 Rp \u00B7 Rpre \u00B7 R \u00B7 Rpost\u207B\u00B9 \u00B7 Rp\u207B\u00B9 \u00B7 Soff \u00B7 Sp \u00B7 S \u00B7 Sp\u207B\u00B9\n/// \u003C/code\u003E\n/// System.Numerics matrices are row-vector (\u003Cc\u003Ep\u0027 = p\u00B7M\u003C/c\u003E), so the local matrix is composed\n/// in reverse order with row-form factors:\n/// \u003Ccode\u003E\n/// Local = T(-Sp)\u00B7S\u00B7T(Sp)\u00B7T(Soff)\u00B7T(-Rp)\u00B7R(Rpre\u00B7R\u00B7Rpost\u207B\u00B9)\u00B7T(Rp)\u00B7T(Roff)\u00B7T(t)\n/// World = Local \u00B7 ParentWorld\n/// \u003C/code\u003E\n/// \u003Cpara\u003E\u003Cb\u003ERotationOrder\u003C/b\u003E (0=XYZ, 1=XZY, 2=YZX, 3=YXZ, 4=ZXY, 5=ZYX): the letters give the\n/// application order, first letter applied first \u2014 eEulerXYZ composes \u003Cc\u003ER = Rz\u00B7Ry\u00B7Rx\u003C/c\u003E in\n/// column convention (verified against Blender-imported ground truth of Mixamo and citizen\n/// rigs). Pre/Post rotations always use XYZ order and are only applied when\n/// \u003Cc\u003ERotationActive\u003C/c\u003E is set (matching Blender\u0027s importer; defaults to active when the\n/// property is absent everywhere).\u003C/para\u003E\n/// \u003Cpara\u003E\u003Cb\u003EInheritType\u003C/b\u003E (0=RrSs, 1=RSrs, 2=Rrs): scale is dropped to rigid transforms by\n/// this importer \u2014 world matrices are evaluated with full scale, then decomposed to pos\u002Brot\n/// with scale folded into child translations \u2014 so types 0 and 1 are handled identically.\n/// Files that use non-uniform scale meaningfully with InheritType 2 (no parent scale\n/// propagation) are evaluated as type 0; this is a documented limitation.\u003C/para\u003E\n/// \u003C/remarks\u003E\npublic sealed class FbxTransform\n{\n    /// \u003Csummary\u003EStatic \u0022Lcl Translation\u0022 default (native units).\u003C/summary\u003E\n    public Vector3 LclTranslation { get; init; }\n\n    /// \u003Csummary\u003EStatic \u0022Lcl Rotation\u0022 default, euler degrees in \u003Csee cref=\u0022RotationOrder\u0022/\u003E.\u003C/summary\u003E\n    public Vector3 LclRotationDeg { get; init; }\n\n    /// \u003Csummary\u003EStatic \u0022Lcl Scaling\u0022 default.\u003C/summary\u003E\n    public Vector3 LclScaling { get; init; } = Vector3.One;\n\n    /// \u003Csummary\u003EPreRotation as a quaternion (identity when inactive or absent).\u003C/summary\u003E\n    public Quaternion PreRotation { get; init; } = Quaternion.Identity;\n\n    /// \u003Csummary\u003EPostRotation as a quaternion (identity when inactive or absent).\u003C/summary\u003E\n    public Quaternion PostRotation { get; init; } = Quaternion.Identity;\n\n    /// \u003Csummary\u003ERotationOffset (Roff).\u003C/summary\u003E\n    public Vector3 RotationOffset { get; init; }\n\n    /// \u003Csummary\u003ERotationPivot (Rp).\u003C/summary\u003E\n    public Vector3 RotationPivot { get; init; }\n\n    /// \u003Csummary\u003EScalingOffset (Soff).\u003C/summary\u003E\n    public Vector3 ScalingOffset { get; init; }\n\n    /// \u003Csummary\u003EScalingPivot (Sp).\u003C/summary\u003E\n    public Vector3 ScalingPivot { get; init; }\n\n    /// \u003Csummary\u003EEuler application order code, 0=XYZ \u2026 5=ZYX (see class remarks).\u003C/summary\u003E\n    public int RotationOrder { get; init; }\n\n    /// \u003Csummary\u003EInheritType 0=RrSs, 1=RSrs, 2=Rrs (see class remarks for handling).\u003C/summary\u003E\n    public int InheritType { get; init; }\n\n    /// \u003Csummary\u003EReads the static transform data of a Model from its (template-backed) properties.\u003C/summary\u003E\n    public static FbxTransform FromModel(FbxScene scene, FbxObject model)\n    {\n        ArgumentNullException.ThrowIfNull(scene);\n        ArgumentNullException.ThrowIfNull(model);\n\n        // Pre/Post rotation participate only when RotationActive is set (Blender-compatible).\n        // When the property is absent on both the object and its template, default to active \u2014\n        // exporters that strip RotationActive but keep PreRotation expect it applied.\n        bool rotationActive = scene.FindProperty(model, \u0022RotationActive\u0022) is { } ra\n            ? ra.GetInt() != 0\n            : true;\n\n        var pre = scene.GetVector3(model, \u0022PreRotation\u0022, Vector3.Zero);\n        var post = scene.GetVector3(model, \u0022PostRotation\u0022, Vector3.Zero);\n\n        return new FbxTransform\n        {\n            LclTranslation = scene.GetVector3(model, \u0022Lcl Translation\u0022, Vector3.Zero),\n            LclRotationDeg = scene.GetVector3(model, \u0022Lcl Rotation\u0022, Vector3.Zero),\n            LclScaling = scene.GetVector3(model, \u0022Lcl Scaling\u0022, Vector3.One),\n            PreRotation = rotationActive ? EulerDegreesToQuaternion(pre, 0) : Quaternion.Identity,\n            PostRotation = rotationActive ? EulerDegreesToQuaternion(post, 0) : Quaternion.Identity,\n            RotationOffset = scene.GetVector3(model, \u0022RotationOffset\u0022, Vector3.Zero),\n            RotationPivot = scene.GetVector3(model, \u0022RotationPivot\u0022, Vector3.Zero),\n            ScalingOffset = scene.GetVector3(model, \u0022ScalingOffset\u0022, Vector3.Zero),\n            ScalingPivot = scene.GetVector3(model, \u0022ScalingPivot\u0022, Vector3.Zero),\n            RotationOrder = scene.GetInt(model, \u0022RotationOrder\u0022, 0),\n            InheritType = scene.GetInt(model, \u0022InheritType\u0022, 0),\n        };\n    }\n\n    /// \u003Csummary\u003E\n    /// Local matrix (row-vector layout) for given TRS values; pass the Lcl defaults for the\n    /// rest pose or per-frame sampled values for animation.\n    /// \u003C/summary\u003E\n    public Matrix4x4 LocalMatrix(Vector3 translation, Vector3 rotationDeg, Vector3 scaling)\n    {\n        // Column chain R-part: Rpre \u00B7 R \u00B7 Rpost\u207B\u00B9  \u2192  our quaternion convention (a*b applies\n        // b first) composes the same way.\n        var rotation = MathQ.Normalize(\n            PreRotation *\n            EulerDegreesToQuaternion(rotationDeg, RotationOrder) *\n            Quaternion.Conjugate(PostRotation));\n\n        // Row-vector composition, first-applied factor leftmost (see class remarks).\n        var m = Matrix4x4.CreateTranslation(-ScalingPivot);\n        m *= Matrix4x4.CreateScale(scaling);\n        m *= Matrix4x4.CreateTranslation(ScalingPivot \u002B ScalingOffset - RotationPivot);\n        m *= Matrix4x4.CreateFromQuaternion(rotation);\n        m *= Matrix4x4.CreateTranslation(RotationPivot \u002B RotationOffset \u002B translation);\n        return m;\n    }\n\n    /// \u003Csummary\u003ELocal matrix from the static Lcl defaults (rest evaluation, no animation).\u003C/summary\u003E\n    public Matrix4x4 LocalMatrixDefault() =\u003E LocalMatrix(LclTranslation, LclRotationDeg, LclScaling);\n\n    /// \u003Csummary\u003E\n    /// Converts FBX euler angles (degrees) to a quaternion for the given RotationOrder code.\n    /// The order letters list the application sequence (XYZ = X first, then Y, then Z).\n    /// \u003C/summary\u003E\n    public static Quaternion EulerDegreesToQuaternion(Vector3 degrees, int order)\n    {\n        const float degToRad = MathF.PI / 180f;\n        var qx = Quaternion.CreateFromAxisAngle(Vector3.UnitX, degrees.X * degToRad);\n        var qy = Quaternion.CreateFromAxisAngle(Vector3.UnitY, degrees.Y * degToRad);\n        var qz = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, degrees.Z * degToRad);\n\n        // q = third * second * first (our convention applies the right factor first).\n        return order switch\n        {\n            0 =\u003E qz * qy * qx, // XYZ\n            1 =\u003E qy * qz * qx, // XZY\n            2 =\u003E qx * qz * qy, // YZX\n            3 =\u003E qz * qx * qy, // YXZ\n            4 =\u003E qy * qx * qz, // ZXY\n            5 =\u003E qx * qy * qz, // ZYX\n            6 =\u003E qz * qy * qx, // eSphericXYZ \u2014 treated as XYZ\n            _ =\u003E throw new FormatException($\u0022Unsupported FBX RotationOrder {order}.\u0022),\n        };\n    }\n\n    /// \u003Csummary\u003E\n    /// Extracts the rigid part of a (possibly scaled) world matrix: translation taken directly,\n    /// rotation from the orthonormalized basis. Scale is thereby folded into child translations\n    /// when parent-relative transforms are derived from rigid worlds. Mirrored (negative\n    /// determinant) bases fall back to the dominant proper rotation (best effort \u2014 mirrored\n    /// skeletons are not meaningfully supported).\n    /// \u003C/summary\u003E\n    public static XForm ToRigid(in Matrix4x4 world)\n    {\n        var pos = world.Translation;\n\n        var x = new Vector3(world.M11, world.M12, world.M13);\n        var y = new Vector3(world.M21, world.M22, world.M23);\n        var z = new Vector3(world.M31, world.M32, world.M33);\n\n        x = SafeNormalize(x, Vector3.UnitX);\n        y = SafeNormalize(y, Vector3.UnitY);\n        z = SafeNormalize(z, Vector3.UnitZ);\n\n        // Mirrored basis: flip the third axis to restore a proper rotation.\n        if (Vector3.Dot(Vector3.Cross(x, y), z) \u003C 0f)\n            z = -z;\n\n        var m = new Matrix4x4(\n            x.X, x.Y, x.Z, 0f,\n            y.X, y.Y, y.Z, 0f,\n            z.X, z.Y, z.Z, 0f,\n            0f, 0f, 0f, 1f);\n\n        return new XForm(pos, MathQ.Normalize(Quaternion.CreateFromRotationMatrix(m)));\n    }\n\n    private static Vector3 SafeNormalize(Vector3 v, Vector3 fallback)\n    {\n        float lsq = v.LengthSquared();\n        if (!float.IsFinite(lsq) || lsq \u003C 1e-20f)\n            return fallback;\n        return v / MathF.Sqrt(lsq);\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Formats/Fbx/ModelDocFbxExport.cs","FileName":"ModelDocFbxExport.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing HumanoidMocapX.Core.Maths;\nusing HumanoidMocapX.Core.Skeleton;\n\nnamespace HumanoidMocapX.Core.Formats.Fbx;\nusing SkeletonModel = HumanoidMocapX.Core.Skeleton.Skeleton;\n\n/// \u003Csummary\u003EFBX with the source-to-engine scale baked into every translation for direct ModelDoc import.\u003C/summary\u003E\npublic static class ModelDocFbxExport\n{\n\t/// \u003Csummary\u003EUses Humanoid Retargeter\u0027s source scale for centimetre rigs; compiled engine rigs already use inches.\u003C/summary\u003E\n\tpublic static byte[] Write( SkeletonModel skeleton, string name, IReadOnlyList\u003CXForm[]\u003E frames,\n\t\tIReadOnlyList\u003Cdouble\u003E times, double fps, TargetUpAxis axis, string motionSpace )\n\t{\n\t\tArgumentNullException.ThrowIfNull( skeleton );\n\t\tArgumentNullException.ThrowIfNull( frames );\n\t\tif ( frames.Count is \u003C 1 or \u003E 108000 || skeleton.Count is \u003C 1 or \u003E 1024\n\t\t\t|| (long)frames.Count * skeleton.Count \u003E FbxAnimationWriter.MaximumTransformSamples )\n\t\t\tthrow new ArgumentException( \u0022Animation exceeds the export budget. Select a shorter range.\u0022 );\n\t\tif ( axis is not (TargetUpAxis.YUpCm or TargetUpAxis.ZUpEngine) )\n\t\t\tthrow new ArgumentOutOfRangeException( nameof( axis ) );\n\n\t\t// Like Retargeter\u0027s ModelModifier_ScaleAndMirror, this converts raw source values.\n\t\t// UnitScaleFactor alone is insufficient for ModelDoc\u0027s raw-unit import. Bake the\n\t\t// factor into bind positions, all local translations, root motion and appended props.\n\t\tif ( axis == TargetUpAxis.YUpCm )\n\t\t{\n\t\t\tXForm Scale( XForm pose ) =\u003E new( pose.Pos * RetargetTargetSpec.SboxSourceScale, pose.Rot );\n\t\t\tskeleton = SkeletonModel.Create( skeleton.Bones.Select( bone =\u003E new BoneDefinition(\n\t\t\t\tbone.Name, bone.ParentIndex \u003C 0 ? null : skeleton[ bone.ParentIndex ].Name,\n\t\t\t\tScale( bone.RestLocal ) ) ).ToArray() );\n\t\t\tframes = frames.Select( frame =\u003E frame.Select( Scale ).ToArray() ).ToArray();\n\t\t}\n\n\t\treturn FbxAnimationWriter.Write( skeleton, name, frames, times, fps,\n\t\t\taxis == TargetUpAxis.YUpCm ? 1 : 2, 2.54, motionSpace );\n\t}\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/InspectResult.cs","FileName":"InspectResult.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing HumanoidMocapX.Core.Mapping;\nusing HumanoidMocapX.Core.Maths;\nusing HumanoidMocapX.Core.Target;\nusing HumanoidMocapX.Core.Skeleton;\n\nnamespace HumanoidMocapX.Core;\n\n/// \u003Csummary\u003E\n/// Result of \u003Csee cref=\u0022Retargeter.Inspect\u0022/\u003E: the mapping report plus the file\u0027s take\n/// metadata, so UI listings can expand a multi-take file into one entry per take (each\n/// convertible independently via \u003Csee cref=\u0022RetargetRequest.TakeIndex\u0022/\u003E).\n/// \u003C/summary\u003E\npublic sealed class InspectResult\n{\n    /// \u003Csummary\u003EMapping report from the same preset-then-auto cascade conversion uses.\u003C/summary\u003E\n    public required MappingReportInfo Mapping { get; init; }\n\n    /// \u003Csummary\u003ENames of the file\u0027s animation takes, in take-index order (the index is what\n    /// \u003Csee cref=\u0022RetargetRequest.TakeIndex\u0022/\u003E accepts). Empty when the file has no animation.\u003C/summary\u003E\n    public required IReadOnlyList\u003Cstring\u003E TakeNames { get; init; }\n\n    /// \u003Csummary\u003ENumber of animation takes in the file.\u003C/summary\u003E\n    public int TakeCount =\u003E TakeNames.Count;\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Motion/ArmSettings.cs","FileName":"ArmSettings.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\nusing System.Numerics;\nusing HumanoidMocapX.Core.Maths;\n\nnamespace HumanoidMocapX.Core.Motion;\nusing Vector3 = System.Numerics.Vector3;\n\npublic sealed class ArmSettings\n{\n    public Vector3 Shoulder { get; set; } = new(.18f,-.15f,0);\n    public Vector3 ElbowTarget { get; set; } = new(.4f,-.4f,.2f);\n    public float UpperLength { get; set; } = .28f;\n    public float ForearmLength { get; set; } = .25f;\n    public float MaximumReach { get; set; } = .995f;\n    public float MinimumElbowDegrees { get; set; } = 5;\n    public float MaximumElbowDegrees { get; set; } = 155;\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Motion/CaptureLegReach.cs","FileName":"CaptureLegReach.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\n\nnamespace HumanoidMocapX.Core.Motion;\n\nusing Vector3 = System.Numerics.Vector3;\n\n/// \u003Csummary\u003ELeaves a small knee bend when moving the pelvis to reach captured foot targets.\u003C/summary\u003E\ninternal static class CaptureLegReach\n{\n\t// Exact full extension is singular: a millimetre of ankle travel can unfold the knee\n\t// by centimetres. Reserve half a percent of reach and enter the correction smoothly.\n\tinternal const float ReachFraction = .995f;\n\n\tinternal static float Lowering( Vector3 hipToFoot, Vector3 up, float length )\n\t{\n\t\tvar vertical = Vector3.Dot( hipToFoot, up );\n\t\tvar horizontal = hipToFoot - up * vertical;\n\t\tvar reach = length * ReachFraction;\n\t\tif ( length \u003C= 0 || vertical \u003C= 0 || horizontal.LengthSquared() \u003E= reach * reach ) return 0;\n\n\t\tvar deficit = vertical - MathF.Sqrt( reach * reach - horizontal.LengthSquared() );\n\t\tvar ease = length * .01f;\n\t\t// Smooth positive part, evaluated without subtracting two nearly equal numbers.\n\t\tvar diagonal = MathF.Sqrt( deficit * deficit \u002B ease * ease );\n\t\treturn deficit \u003E= 0 ? (deficit \u002B diagonal) * .5f : ease * ease / (2 * (diagonal - deficit));\n\t}\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Preview/PreviewFrameBuffer.cs","FileName":"PreviewFrameBuffer.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\n\nnamespace HumanoidMocapX.Core.Preview;\n\n/// \u003Csummary\u003EOwns a bounded RGBA preview frame. Reuses storage until the preview size\n/// changes; callers must synchronize concurrent readers and writers.\u003C/summary\u003E\npublic sealed class PreviewFrameBuffer\n{\n    const int MaximumWidth = 960, MaximumHeight = 540, PixelBytes = 4;\n    byte[] pixels = Array.Empty\u003Cbyte\u003E();\n    /// \u003Csummary\u003EWidth of the owned preview in pixels; zero before the first frame.\u003C/summary\u003E\n    public int Width { get; private set; }\n    /// \u003Csummary\u003EHeight of the owned preview in pixels; zero before the first frame.\u003C/summary\u003E\n    public int Height { get; private set; }\n    /// \u003Csummary\u003EIncreases after each successful copy so consumers can skip unchanged frames.\u003C/summary\u003E\n    public long Version { get; private set; }\n    /// \u003Csummary\u003EBorrowed pixels, valid until the next Copy call.\u003C/summary\u003E\n    public ReadOnlySpan\u003Cbyte\u003E Pixels =\u003E pixels;\n\n    /// \u003Csummary\u003ECopies a packed RGBA frame, reducing it to fit 960\u00D7540 without changing\n    /// aspect ratio. Rejects nonpositive dimensions and an incorrect byte count.\u003C/summary\u003E\n    public void Copy(ReadOnlySpan\u003Cbyte\u003E source, int width, int height)\n    {\n        if (width \u003C 1 || height \u003C 1 || (long)width * height * PixelBytes != source.Length)\n            throw new ArgumentException(\u0022Video preview requires a complete packed RGBA frame.\u0022);\n        var scale = Math.Min(1, Math.Min((double)MaximumWidth / width, (double)MaximumHeight / height));\n        var targetWidth = Math.Max(1, (int)(width * scale));\n        var targetHeight = Math.Max(1, (int)(height * scale));\n        var length = targetWidth * targetHeight * PixelBytes;\n        if (pixels.Length != length) pixels = new byte[length];\n        if (targetWidth == width \u0026\u0026 targetHeight == height) source.CopyTo(pixels);\n        else\n            for (var y = 0; y \u003C targetHeight; y\u002B\u002B)\n                for (var x = 0; x \u003C targetWidth; x\u002B\u002B)\n                {\n                    var from = ((long)y * height / targetHeight * width \u002B (long)x * width / targetWidth) * PixelBytes;\n                    var to = (y * targetWidth \u002B x) * PixelBytes;\n                    source.Slice((int)from, PixelBytes).CopyTo(pixels.AsSpan(to, PixelBytes));\n                }\n        Width = targetWidth; Height = targetHeight; Version\u002B\u002B;\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Retargeter.cs","FileName":"Retargeter.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing System.Text;\nusing HumanoidMocapX.Core.Cleanup;\nusing HumanoidMocapX.Core.Formats;\nusing HumanoidMocapX.Core.Formats.Dmx;\nusing HumanoidMocapX.Core.Formats.Fbx;\nusing HumanoidMocapX.Core.Formats.Gltf;\nusing HumanoidMocapX.Core.Mapping;\nusing HumanoidMocapX.Core.Maths;\nusing HumanoidMocapX.Core.Skeleton;\nusing HumanoidMocapX.Core.Solve;\nusing HumanoidMocapX.Core.Target;\nusing SkeletonModel = HumanoidMocapX.Core.Skeleton.Skeleton;\n\nnamespace HumanoidMocapX.Core;\n\nusing Vector3 = System.Numerics.Vector3; // s\u0026box compat: shadow engine\u0027s global-namespace Vector3 (see Code/HumanoidMocap/Assembly.cs)\n\n/// \u003Csummary\u003E\n/// Engine-agnostic pipeline facade (design \u00A75): bytes in \u2192 DMX \u002B vmdl text out. Composes\n/// import \u2192 mapping \u2192 solve \u2192 cleanup \u2192 IK baking \u2192 DMX \u2192 vmdl assembly. Batch is\n/// first-class: N files \u00D7 all takes per file \u2192 ONE combined vmdl, with per-request profile\n/// detection (a batch may mix Mixamo \u002B ActorCore \u002B BVH sources) and per-clip failure\n/// isolation. No file IO anywhere in this type \u2014 callers pass bytes/strings and write the\n/// returned strings.\n/// \u003C/summary\u003E\n/// \u003Cremarks\u003E\n/// Pipeline per clip:\n/// \u003Clist type=\u0022number\u0022\u003E\n/// \u003Citem\u003E\u003Cb\u003EImport\u003C/b\u003E \u2014 format by file extension (\u003Cc\u003E.hmotion\u003C/c\u003E/\u003Cc\u003E.fbx\u003C/c\u003E/\u003Cc\u003E.glb\u003C/c\u003E/\n/// \u003Cc\u003E.gltf\u003C/c\u003E/\u003Cc\u003E.vrm\u003C/c\u003E), content sniff as fallback \u2192 \u003Csee cref=\u0022SourceScene\u0022/\u003E (cm,\n/// native axes).\u003C/item\u003E\n/// \u003Citem\u003E\u003Cb\u003EMapping\u003C/b\u003E \u2014 per request: \u003Csee cref=\u0022RetargetRequest.MappingOverride\u0022/\u003E wins;\n/// else \u003Csee cref=\u0022ProfileDetector.Detect\u0022/\u003E over the preset library (user presets are\n/// loaded Editor-side and arrive as overrides); else \u003Csee cref=\u0022AutoMapper.Map\u0022/\u003E as best\n/// effort with \u003Csee cref=\u0022MappingReportInfo.NeedsUserDecision\u0022/\u003E set when its confidence is\n/// below \u003Csee cref=\u0022ProfileDetector.DetectionThreshold\u0022/\u003E.\u003C/item\u003E\n/// \u003Citem\u003E\u003Cb\u003ESolve\u003C/b\u003E \u2014 \u003Csee cref=\u0022GeometricSolver\u0022/\u003E per take (clip name = take name, or\n/// \u003Csee cref=\u0022RetargetRequest.ClipNameOverride\u0022/\u003E \u002B index).\u003C/item\u003E\n/// \u003Citem\u003E\u003Cb\u003ECleanup\u003C/b\u003E (target space) \u2014 \u003Csee cref=\u0022FootPlant\u0022/\u003E when enabled (chains from\n/// the target rig\u0027s UpperLeg/LowerLeg/Foot/Toe roles, up axis from the TARGET character\n/// frame, fps from the clip); optional arm \u003Csee cref=\u0022EffectorIk\u0022/\u003E (off by default \u2014 the\n/// solver already matches anatomical directions); \u003Csee cref=\u0022RootMotion\u0022/\u003E per mode (see\n/// below).\u003C/item\u003E\n/// \u003Citem\u003E\u003Cb\u003EIK baking\u003C/b\u003E \u2014 \u003Csee cref=\u0022IkBoneBaker.Bake\u0022/\u003E when the rig has\n/// \u003Csee cref=\u0022BoneClass.IkBaked\u0022/\u003E bones.\u003C/item\u003E\n/// \u003Citem\u003E\u003Cb\u003EDMX\u003C/b\u003E \u2014 \u003Csee cref=\u0022DmxWriter\u0022/\u003E over the target skeleton.\u003C/item\u003E\n/// \u003Citem\u003E\u003Cb\u003EAssembly\u003C/b\u003E \u2014 \u003Csee cref=\u0022VmdlWriter.GenerateStandalone\u0022/\u003E over all successful\n/// clips, plus \u003Csee cref=\u0022VmdlAugmenter.Augment\u0022/\u003E when\n/// \u003Csee cref=\u0022BatchOptions.AugmentVmdlText\u0022/\u003E is provided; clip-name collisions are\n/// auto-suffixed (\u003Cc\u003E_2\u003C/c\u003E, \u003Cc\u003E_3\u003C/c\u003E, \u2026) across the batch.\u003C/item\u003E\n/// \u003C/list\u003E\n/// \u003Cpara\u003E\u003Cb\u003ERoot-motion \u2194 target mapping.\u003C/b\u003E \u003Csee cref=\u0022RootMotionMode.Extract\u0022/\u003E bakes the\n/// ground-projected hips path onto the target\u0027s dedicated root bone \u2014 defined as a parentless\n/// \u003Csee cref=\u0022BoneClass.Animated\u0022/\u003E bone that is an ancestor of (and distinct from) the Hips\n/// bone. The s\u0026amp;box rig has NO such bone (pelvis is itself parentless; root_IK is IkBaked),\n/// so there Extract leaves the frames untouched, adds a report note, and instead sets\n/// \u003Csee cref=\u0022AnimEntry.ExtractMotion\u0022/\u003E on the clip\u0027s vmdl entry: Source 2 extracts the\n/// ground-plane translation from \u003Csee cref=\u0022RetargetTargetSpec.DefaultRootBone\u0022/\u003E at compile\n/// time, which is the engine-native equivalent. The ExtractMotion flag is set for every\n/// Extract request either way. \u003Csee cref=\u0022RootMotionMode.InPlace\u0022/\u003E always operates on the\n/// hips channels directly and needs no dedicated root.\u003C/para\u003E\n/// \u003C/remarks\u003E\npublic static class Retargeter\n{\n\t/// \u003Csummary\u003E\n\t/// Applies the same mapping, diagnostics, and mid-pose bind-rest selection used by\n\t/// \u003Csee cref=\u0022ConvertBatch\u0022/\u003E, while leaving the sampled clips available to an editor\n\t/// integration that needs an in-memory target rather than DMX output.\n\t/// \u003C/summary\u003E\n\tpublic static ResolvedSource ResolveSource( SourceScene scene, MappingResult? mappingOverride = null,\n\t\tFunc\u003Cstring, MappingResult?\u003E? userPresetLookup = null )\n\t{\n\t\tArgumentNullException.ThrowIfNull( scene );\n\t\tvar (map, report) = ResolveMapping( scene.Skeleton, mappingOverride, userPresetLookup, scene.AuthoredMapping );\n\t\tforeach ( var note in scene.Notes ) AddNote( report, note );\n\t\tscene = MaybeAdoptBindRest( scene, map, report );\n\t\treturn new( scene, map, report );\n\t}\n\n    /// \u003Csummary\u003EConverts one source file \u2014 all takes, or only\n    /// \u003Csee cref=\u0022RetargetRequest.TakeIndex\u0022/\u003E when set. Equivalent to a one-request batch.\u003C/summary\u003E\n    public static RetargetResult Convert(RetargetRequest request, RetargetTargetSpec target)\n    {\n        ArgumentNullException.ThrowIfNull(request);\n        var batch = ConvertBatch(new[] { request }, target);\n        return new RetargetResult\n        {\n            Clips = batch.Clips,\n            StandaloneVmdl = batch.StandaloneVmdl,\n            Errors = batch.Errors,\n        };\n    }\n\n    /// \u003Csummary\u003E\n    /// Converts a batch of source files against one target. Per-request profile detection,\n    /// per-clip failure isolation (a bad file yields a failed \u003Csee cref=\u0022ClipResult\u0022/\u003E and\n    /// the batch continues), one standalone vmdl with every successful clip, optional\n    /// augmentation of an existing vmdl.\n    /// \u003C/summary\u003E\n    public static RetargetBatchResult ConvertBatch(\n        IReadOnlyList\u003CRetargetRequest\u003E requests, RetargetTargetSpec target, BatchOptions? options = null)\n    {\n        ArgumentNullException.ThrowIfNull(requests);\n        ArgumentNullException.ThrowIfNull(target);\n        options ??= new BatchOptions();\n\n        var context = new TargetContext(target.Rig);\n        var result = new RetargetBatchResult();\n        var usedNames = new HashSet\u003Cstring\u003E(StringComparer.OrdinalIgnoreCase);\n        var entries = new List\u003CAnimEntry\u003E();\n\n        // Augment mode: names already taken in the existing vmdl\u0027s AnimationList must not be\n        // silently repointed \u2014 seed the collision set with every existing node name EXCEPT\n        // our own AnimFiles (source_filename under DmxFolderRelative), which are replaceable\n        // so re-running the same batch stays idempotent.\n        if (options.AugmentVmdlText is not null)\n            SeedUsedNamesFromExistingVmdl(options.AugmentVmdlText, options.DmxFolderRelative, usedNames);\n\n        var mappedPinky = false;\n        foreach (var request in requests)\n        {\n            if (request is null)\n                continue;\n            mappedPinky |= ProcessRequest(\n                request, target, context, options, usedNames, result.Clips, entries);\n        }\n\n        foreach (var clip in result.Clips)\n        {\n            if (!clip.Success)\n                result.Errors.Add($\u0022{clip.SourceFileName}: {clip.Error}\u0022);\n        }\n\n        // Locomotion families are detected on the FINAL (collision-suffixed) clip names so\n        // the blend grids reference exactly what the vmdl registers; folder/blend names are\n        // made unique against the same name set the clips used.\n        IReadOnlyList\u003CLocomotionSetSpec\u003E? locomotionSets = null;\n        if (options.DetectLocomotionSets)\n        {\n            var (sets, reports) = LocomotionSetDetector.Detect(\n                entries, usedNames, options.AutoSuffixCollisions);\n            result.LocomotionSets.AddRange(reports);\n            if (sets.Count \u003E 0)\n                locomotionSets = sets;\n        }\n\n        // The target\u0027s OWN embedded animations ride along every generated vmdl (an FBX\n        // picked as target keeps its animation next to the retargeted ones). Skipped when\n        // a same-named entry is already registered (idempotent re-runs / augment targets\n        // that carry them from an earlier conversion); the retargeted clips claimed their\n        // names first, so an embedded take never displaces a converted clip.\n        if (target.ExtraAnimFiles is { Count: \u003E 0 })\n        {\n            foreach (var extra in target.ExtraAnimFiles)\n            {\n                if (usedNames.Add(extra.Name))\n                    entries.Add(extra);\n            }\n        }\n\n        result.StandaloneVmdl = VmdlWriter.GenerateStandalone(\n            target.BaseModelPath, entries, target.VmdlScale, target.DefaultRootBone,\n            locomotionSets, target.MeshFilePath, target.MeshImportScale, target.MaterialRemaps,\n            target.MeshImportNames);\n\n        if (options.AugmentVmdlText is not null)\n        {\n            try\n            {\n                var removedSequences = new List\u003Cstring\u003E();\n                result.AugmentedVmdl = VmdlAugmenter.Augment(\n                    options.AugmentVmdlText, entries, out _,\n                    new AugmentOptions\n                    {\n                        DefaultRootBone = target.DefaultRootBone,\n                        // The citizen base model copies ring\u2192pinky via its CopyPinky\n                        // constraints; when this batch actually drives the pinky, the\n                        // augmented vmdl must neutralize them or the exported pinky\n                        // channels get overridden at runtime.\n                        NeutralizePinkyConstraints = mappedPinky,\n                        LocomotionSets = locomotionSets,\n                        // Same ownership rule the name seeding above used: pipeline-owned\n                        // locomotion folders (every AnimFile sourced under our DMX folder)\n                        // are replaceable wholesale on re-runs.\n                        DmxFolderRelative = options.DmxFolderRelative,\n                        // Stale entries whose DMX the caller found missing on disk: keep\n                        // them and the WHOLE vmdl stops compiling (\u0022Node \u0027X\u0027 resolve\n                        // failure\u0022), new sequences included.\n                        MissingSourceFiles = options.MissingAnimSources,\n                    },\n                    removedSequences);\n                foreach (var name in removedSequences)\n                {\n                    result.Warnings.Add(\n                        $\u0022removed stale sequence \u0027{name}\u0027 from the augmented vmdl: its \u0022\n                        \u002B \u0022animation source file no longer exists on disk (a missing source \u0022\n                        \u002B \u0022fails the whole model recompile)\u0022);\n                }\n            }\n            catch (Exception e)\n            {\n                result.Errors.Add($\u0022vmdl augmentation failed: {e.Message}\u0022);\n            }\n        }\n\n        return result;\n    }\n\n    /// \u003Csummary\u003ECollects names already present in the existing vmdl\u0027s AnimationList that the\n    /// batch must not reuse (everything except our own replaceable AnimFiles).\u003C/summary\u003E\n    private static void SeedUsedNamesFromExistingVmdl(\n        string vmdlText, string dmxFolderRelative, HashSet\u003Cstring\u003E usedNames)\n    {\n        Kv3Document doc;\n        try\n        {\n            doc = Kv3.Parse(vmdlText);\n        }\n        catch (FormatException)\n        {\n            return; // the augmentation step itself surfaces the parse error\n        }\n\n        if (doc.Root is not KvObject root || root.GetOrNull(\u0022rootNode\u0022) is not KvObject rootNode\n            || rootNode.GetOrNull(\u0022children\u0022) is not KvArray children)\n            return;\n        var animList = children.Items.OfType\u003CKvObject\u003E()\n            .FirstOrDefault(o =\u003E o.GetString(\u0022_class\u0022) == \u0022AnimationList\u0022);\n        if (animList?.GetOrNull(\u0022children\u0022) is not KvArray items)\n            return;\n\n        var folder = dmxFolderRelative.Replace(\u0027\\\\\u0027, \u0027/\u0027).TrimEnd(\u0027/\u0027);\n        SeedNames(items, folder, usedNames);\n    }\n\n    /// \u003Csummary\u003E\n    /// Recursive seeding step: every named AnimationList node reserves its name EXCEPT our\n    /// own replaceable output \u2014 AnimFiles whose source lives in the batch\u0027s DMX folder, and\n    /// locomotion Folders consisting entirely of such AnimFiles (a re-run replaces the whole\n    /// folder, so neither its name nor its content may block the new batch\u0027s names). Foreign\n    /// folders are seeded by name and their content seeded recursively.\n    /// \u003C/summary\u003E\n    private static void SeedNames(KvArray items, string dmxFolder, HashSet\u003Cstring\u003E usedNames)\n    {\n        foreach (var node in items.Items.OfType\u003CKvObject\u003E())\n        {\n            var name = node.GetString(\u0022name\u0022);\n            var cls = node.GetString(\u0022_class\u0022);\n\n            if (cls == \u0022AnimFile\u0022)\n            {\n                if (!string.IsNullOrEmpty(name) \u0026\u0026 !IsOurAnimFile(node, dmxFolder))\n                    usedNames.Add(name);\n                continue;\n            }\n\n            if (cls == \u0022Folder\u0022)\n            {\n                if (IsOurLocomotionFolder(node, dmxFolder))\n                    continue; // replaceable wholesale \u2014 nothing inside reserves a name\n                if (!string.IsNullOrEmpty(name))\n                    usedNames.Add(name);\n                if (node.GetOrNull(\u0022children\u0022) is KvArray nested)\n                    SeedNames(nested, dmxFolder, usedNames);\n                continue;\n            }\n\n            if (!string.IsNullOrEmpty(name))\n                usedNames.Add(name);\n        }\n    }\n\n    /// \u003Csummary\u003EWhether an AnimFile was written by this pipeline: its source_filename sits\n    /// inside the batch\u0027s DMX folder.\u003C/summary\u003E\n    private static bool IsOurAnimFile(KvObject node, string dmxFolder)\n    {\n        var source = (node.GetString(\u0022source_filename\u0022) ?? \u0022\u0022).Replace(\u0027\\\\\u0027, \u0027/\u0027);\n        return dmxFolder.Length == 0\n            ? !source.Contains(\u0027/\u0027)\n            : source.StartsWith(dmxFolder \u002B \u0022/\u0022, StringComparison.OrdinalIgnoreCase);\n    }\n\n    /// \u003Csummary\u003EWhether a Folder is a locomotion group this pipeline spliced: it contains at\n    /// least one AnimFile and every AnimFile inside it (recursively) is ours.\u003C/summary\u003E\n    private static bool IsOurLocomotionFolder(KvObject folderNode, string dmxFolder)\n    {\n        var sawAnimFile = false;\n        return Walk(folderNode) \u0026\u0026 sawAnimFile;\n\n        bool Walk(KvObject node)\n        {\n            if (node.GetString(\u0022_class\u0022) == \u0022AnimFile\u0022)\n            {\n                sawAnimFile = true;\n                return IsOurAnimFile(node, dmxFolder);\n            }\n            if (node.GetOrNull(\u0022children\u0022) is KvArray children)\n            {\n                foreach (var child in children.Items.OfType\u003CKvObject\u003E())\n                {\n                    if (!Walk(child))\n                        return false;\n                }\n            }\n            return true;\n        }\n    }\n\n    /// \u003Csummary\u003E\n    /// Detection-only entry point for UI listings: imports the file and runs the same\n    /// preset-then-auto mapping as conversion, without solving anything. Also reports the\n    /// file\u0027s take metadata (clip names, in take-index order) so listings can expand a\n    /// multi-take file into one entry per take. Throws \u003Csee cref=\u0022FormatException\u0022/\u003E when\n    /// the file is unreadable.\n    /// \u003C/summary\u003E\n    public static InspectResult Inspect(byte[] sourceData, string fileName)\n    {\n        ArgumentNullException.ThrowIfNull(sourceData);\n        ArgumentNullException.ThrowIfNull(fileName);\n        var scene = ImportSource(sourceData, fileName);\n        var takeNames = new List\u003Cstring\u003E(scene.Clips.Count);\n        foreach (var clip in scene.Clips)\n            takeNames.Add(clip.Name);\n        return new InspectResult\n        {\n            Mapping = ResolveMapping(scene.Skeleton, authoredMapping: scene.AuthoredMapping).Report,\n            TakeNames = takeNames,\n        };\n    }\n\n    // ================================================================ per-request pipeline\n\n    /// \u003Csummary\u003ERuns one request end to end. Returns true when at least one clip converted\n    /// successfully with a mapping that drives a pinky role (CopyPinky handling).\u003C/summary\u003E\n    private static bool ProcessRequest(\n        RetargetRequest request, RetargetTargetSpec target, TargetContext context,\n        BatchOptions options, HashSet\u003Cstring\u003E usedNames,\n        List\u003CClipResult\u003E clips, List\u003CAnimEntry\u003E entries)\n    {\n        var sourceId = request.SourceId ?? request.SourceFileName;\n        SourceScene scene;\n        MappingReportInfo report;\n        MappingResult map;\n        try\n        {\n            scene = ImportSource(\n                request.SourceData, request.SourceFileName, request.SampleFps,\n                request.ExternalBufferResolver);\n            (map, report) = ResolveMapping(\n                scene.Skeleton, request.MappingOverride, authoredMapping: scene.AuthoredMapping);\n            // Import diagnostics (mid-pose exports, cross-stack static disagreements, ...)\n            // ride the mapping report so UIs can surface them next to the conversion result.\n            foreach (var note in scene.Notes)\n                AddNote(report, note);\n            scene = MaybeAdoptBindRest(scene, map, report);\n        }\n        catch (Exception e)\n        {\n            clips.Add(new ClipResult\n            {\n                ClipName = FileStem(request.SourceFileName),\n                SourceFileName = request.SourceFileName,\n                SourceId = sourceId,\n                Success = false,\n                Error = e.Message,\n            });\n            return false;\n        }\n\n        if (scene.Clips.Count == 0)\n        {\n            clips.Add(new ClipResult\n            {\n                ClipName = FileStem(request.SourceFileName),\n                SourceFileName = request.SourceFileName,\n                SourceId = sourceId,\n                Mapping = report,\n                Success = false,\n                Error = \u0022Source file contains no animation takes.\u0022,\n            });\n            return false;\n        }\n\n        var mapsPinky = MapsPinkyRole(map);\n        if (mapsPinky \u0026\u0026 options.AugmentVmdlText is null\n            \u0026\u0026 target.BaseModelPath == RetargetTargetSpec.SboxHumanMalePath)\n        {\n            // A standalone child vmdl cannot override the base model\u0027s AnimConstraintList:\n            // the citizen\u0027s CopyPinky (ring \u2192 pinky orient copy) keeps driving the pinky at\n            // runtime even though the DMX carries real pinky channels.\n            AddNote(report,\n                \u0022Pinky channels are exported, but the base model\u0027s CopyPinky constraints \u0022\n                \u002B \u0022(ring \u2192 pinky copy) cannot be overridden from a standalone vmdl, so the \u0022\n                \u002B \u0022pinky will visibly mirror the ring finger\u0027s motion in engine \u2014 use \u0022\n                \u002B \u0022augment mode (add to the existing vmdl) to neutralize them.\u0022);\n        }\n        if (target.UpAxis == TargetUpAxis.ZUpEngine)\n        {\n            AddNote(report,\n                \u0022Target rig is engine-space (Z-up, inches): the DMX declares a Z-up axis \u0022\n                \u002B \u0022system so resourcecompiler performs no Y-up conversion (best-effort \u2014 \u0022\n                \u002B \u0022verify the compiled sequence on engine-space targets).\u0022);\n        }\n\n        // External clip definitions (Unity .fbx.meta clipAnimations): one output clip per\n        // DEFINITION, sliced out of its take; TakeIndex addresses the definitions then\n        // (see RetargetRequest.ClipDefinitions).\n        if (request.ClipDefinitions is { Count: \u003E 0 } clipDefs)\n        {\n            return ProcessClipDefinitions(\n                request, target, context, options, usedNames, clips, entries,\n                scene, map, report, sourceId, mapsPinky, clipDefs);\n        }\n\n        // TakeIndex narrows the conversion to a single take (UI per-take entries submit one\n        // request per selected take); null keeps the historical convert-all-takes behavior.\n        var takeStart = 0;\n        var takeEnd = scene.Clips.Count;\n        if (request.TakeIndex is { } takeIndex)\n        {\n            if (takeIndex \u003C 0 || takeIndex \u003E= scene.Clips.Count)\n            {\n                clips.Add(new ClipResult\n                {\n                    ClipName = FileStem(request.SourceFileName),\n                    SourceFileName = request.SourceFileName,\n                    SourceId = sourceId,\n                    Mapping = report,\n                    Success = false,\n                    Error = $\u0022Take index {takeIndex} is out of range: the source file \u0022\n                        \u002B $\u0022contains {scene.Clips.Count} take(s).\u0022,\n                });\n                return false;\n            }\n            takeStart = takeIndex;\n            takeEnd = takeIndex \u002B 1;\n        }\n\n        var anyPinkySuccess = false;\n        for (var take = takeStart; take \u003C takeEnd; take\u002B\u002B)\n        {\n            var clipName = UniqueClipName(\n                SanitizeClipName(RequestedClipName(request, scene, take)),\n                usedNames, options.AutoSuffixCollisions);\n            anyPinkySuccess |= ConvertOne(\n                request, target, context, options, usedNames, clips, entries,\n                scene, map, report, sourceId, mapsPinky, take, clipName);\n        }\n\n        return anyPinkySuccess;\n    }\n\n    /// \u003Csummary\u003E\n    /// The definitions variant of the take loop: each \u003Csee cref=\u0022ExternalClipDef\u0022/\u003E becomes\n    /// its own clip result \u2014 the definition\u0027s take is located by\n    /// \u003Csee cref=\u0022ExternalClipDef.TakeName\u0022/\u003E (falling back to the file\u0027s first take), sliced\n    /// to the definition\u0027s native-frame range via \u003Csee cref=\u0022UnityMeta.Slice\u0022/\u003E and solved as\n    /// a single-clip scene. Returns true when at least one clip converted successfully with a\n    /// pinky-driving mapping.\n    /// \u003C/summary\u003E\n    private static bool ProcessClipDefinitions(\n        RetargetRequest request, RetargetTargetSpec target, TargetContext context,\n        BatchOptions options, HashSet\u003Cstring\u003E usedNames,\n        List\u003CClipResult\u003E clips, List\u003CAnimEntry\u003E entries,\n        SourceScene scene, MappingResult map, MappingReportInfo report,\n        string sourceId, bool mapsPinky, IReadOnlyList\u003CExternalClipDef\u003E clipDefs)\n    {\n        var defStart = 0;\n        var defEnd = clipDefs.Count;\n        if (request.TakeIndex is { } defIndex)\n        {\n            if (defIndex \u003C 0 || defIndex \u003E= clipDefs.Count)\n            {\n                clips.Add(new ClipResult\n                {\n                    ClipName = FileStem(request.SourceFileName),\n                    SourceFileName = request.SourceFileName,\n                    SourceId = sourceId,\n                    Mapping = report,\n                    Success = false,\n                    Error = $\u0022Clip-definition index {defIndex} is out of range: the request \u0022\n                        \u002B $\u0022carries {clipDefs.Count} clip definition(s).\u0022,\n                });\n                return false;\n            }\n            defStart = defIndex;\n            defEnd = defIndex \u002B 1;\n        }\n\n        var anyPinkySuccess = false;\n        for (var d = defStart; d \u003C defEnd; d\u002B\u002B)\n        {\n            var def = clipDefs[d];\n            var requestedName = !string.IsNullOrWhiteSpace(def.Name)\n                ? def.Name\n                : clipDefs.Count \u003E 1 ? $\u0022{FileStem(request.SourceFileName)}_{d \u002B 1}\u0022 : FileStem(request.SourceFileName);\n            var clipName = UniqueClipName(\n                SanitizeClipName(requestedName), usedNames, options.AutoSuffixCollisions);\n\n            var take = TakeForDefinition(scene, def);\n            var sliced = UnityMeta.Slice(scene.Clips[take], def, clipName);\n\n            // Same skeleton/axes, ONE clip: the regular pipeline then solves \u0022take 0\u0022 of it.\n            var defScene = new SourceScene(\n                scene.Skeleton, new[] { sliced }, scene.UnitScaleCm,\n                scene.UpAxis, scene.UpAxisSign,\n                scene.FrontAxis, scene.FrontAxisSign,\n                scene.CoordAxis, scene.CoordAxisSign,\n                scene.OriginalUpAxis, scene.Notes)\n            {\n                AuthoredMapping = scene.AuthoredMapping,\n                RestPlacementAuthored = scene.RestPlacementAuthored,\n            };\n\n            anyPinkySuccess |= ConvertOne(\n                request, target, context, options, usedNames, clips, entries,\n                defScene, map, report, sourceId, mapsPinky, take: 0, clipName);\n        }\n\n        return anyPinkySuccess;\n    }\n\n    /// \u003Csummary\u003EThe take a definition\u0027s frame range refers to: matched by take name when the\n    /// definition records one (Unity\u0027s \u003Cc\u003EtakeName\u003C/c\u003E, e.g. \u003Cc\u003Eroot|Animation\u003C/c\u003E), else \u2014\n    /// and when nothing matches \u2014 the file\u0027s first take.\u003C/summary\u003E\n    private static int TakeForDefinition(SourceScene scene, ExternalClipDef def)\n    {\n        if (!string.IsNullOrWhiteSpace(def.TakeName))\n        {\n            for (var i = 0; i \u003C scene.Clips.Count; i\u002B\u002B)\n            {\n                if (string.Equals(scene.Clips[i].Name, def.TakeName, StringComparison.Ordinal))\n                    return i;\n            }\n        }\n        return 0;\n    }\n\n    /// \u003Csummary\u003ESolves ONE clip (take \u003Cparamref name=\u0022take\u0022/\u003E of \u003Cparamref name=\u0022scene\u0022/\u003E)\n    /// end to end \u2014 solve \u002B cleanup \u002B DMX, plus the optional mirrored twin\n    /// (\u003Csee cref=\u0022RetargetRequest.CreateMirroredVariant\u0022/\u003E) \u2014 appending success or failure\n    /// \u003Csee cref=\u0022ClipResult\u0022/\u003Es (failures never abort the batch). Returns true on success\n    /// with a pinky-driving mapping.\u003C/summary\u003E\n    private static bool ConvertOne(\n        RetargetRequest request, RetargetTargetSpec target, TargetContext context,\n        BatchOptions options, HashSet\u003Cstring\u003E usedNames,\n        List\u003CClipResult\u003E clips, List\u003CAnimEntry\u003E entries,\n        SourceScene scene, MappingResult map, MappingReportInfo report,\n        string sourceId, bool mapsPinky, int take, string clipName)\n    {\n        Clip clip;\n        try\n        {\n            clip = SolveAndClean(request, target, context, scene, map, report, take, clipName);\n            EmitClip(request, target, context, options, usedNames, clips, entries, report,\n                sourceId, clipName, clip.Frames, clip.Fps, clip.Looping, isMirrored: false);\n        }\n        catch (Exception e)\n        {\n            clips.Add(new ClipResult\n            {\n                ClipName = clipName,\n                SourceFileName = request.SourceFileName,\n                SourceId = sourceId,\n                Mapping = report,\n                Success = false,\n                Error = e.Message,\n            });\n            return false;\n        }\n\n        if (request.CreateMirroredVariant)\n        {\n            // The twin gets its own collision-suffixed name and its own failure isolation:\n            // a mirror problem (asymmetric rig) fails ONLY the twin, never the primary clip.\n            var mirroredName = UniqueClipName(\n                SanitizeClipName(clipName \u002B \u0022_M\u0022), usedNames, options.AutoSuffixCollisions);\n            try\n            {\n                // SOURCE-SIDE MIRROR (southpaw G8 mirror fix, gate3_review.md 3.4 and the\n                // G8 bisect evidence): the SOURCE clip is mirrored across the source\n                // character\u0027s sagittal plane and the twin then runs through the COMPLETE\n                // unmodified primary pipeline (solver, cleanups, ground alignment, IK\n                // bake, orphan re-anchor). The emitted _M clip is a first-class primary\n                // clip in every representational respect, indistinguishable from a clip\n                // an animator authored mirrored. Target-space channel mirroring, however\n                // geometrically exact, produced data the ENGINE\u0027s render-side sequence\n                // evaluation mangles (measured: a mirrored pelvis channel alone renders\n                // the whole model upside down while every CPU-side bone API reports a\n                // perfect upright mirror); no data conjugation convention survived that\n                // stage, so the mirror moved to the source side where no alien data\n                // shape can exist.\n                var mirroredScene = SourceMirror.MirrorTake(scene, map, take);\n                var mirroredClip = SolveAndClean(\n                    request, target, context, mirroredScene, map, report, take, mirroredName);\n                EmitClip(request, target, context, options, usedNames, clips, entries, report,\n                    sourceId, mirroredName, mirroredClip.Frames, mirroredClip.Fps,\n                    clip.Looping, isMirrored: true);\n            }\n            catch (Exception e)\n            {\n                clips.Add(new ClipResult\n                {\n                    ClipName = mirroredName,\n                    SourceFileName = request.SourceFileName,\n                    SourceId = sourceId,\n                    Mapping = report,\n                    Success = false,\n                    Error = $\u0022mirrored variant: {e.Message}\u0022,\n                });\n            }\n        }\n\n        return mapsPinky;\n    }\n\n    /// \u003Csummary\u003EShared tail of clip production (primary and mirrored twin): optional footstep\n    /// events, DMX serialization, the \u003Csee cref=\u0022ClipResult\u0022/\u003E and the vmdl\n    /// \u003Csee cref=\u0022AnimEntry\u0022/\u003E \u2014 plus the additive (\u003Cc\u003E_delta\u003C/c\u003E) companion entry when\n    /// \u003Csee cref=\u0022RetargetRequest.CreateAdditiveVariant\u0022/\u003E is on (a second AnimFile REUSING\n    /// the clip\u0027s DMX with an AnimSubtract child, shipped-citizen shape; no separate\n    /// \u003Csee cref=\u0022ClipResult\u0022/\u003E since no separate DMX exists).\u003C/summary\u003E\n    private static void EmitClip(\n        RetargetRequest request, RetargetTargetSpec target, TargetContext context,\n        BatchOptions options, HashSet\u003Cstring\u003E usedNames,\n        List\u003CClipResult\u003E clips, List\u003CAnimEntry\u003E entries,\n        MappingReportInfo report, string sourceId,\n        string clipName, List\u003CXForm[]\u003E frames, float fps, bool looping, bool isMirrored)\n    {\n        var events = GenerateFootsteps(request, target, context, report, frames, fps);\n        var dmxFileName = SanitizeFileName(clipName) \u002B \u0022.dmx\u0022;\n        // Embedded-mesh vmdls and compiled Z-up targets compile root channels 90\u00B0 about the declared\n        // up axis away from the mesh bind; child channels are unaffected. Compensate the\n        // serialized copy only so compiled playback matches the solved preview.\n        var dmxFrames = !string.IsNullOrEmpty(target.MeshFilePath) || target.UpAxis == TargetUpAxis.ZUpEngine\n            ? CompensateEmbeddedMeshRootYaw(frames, target.Rig, target.UpAxis)\n            : frames;\n        var dmx = DmxWriter.Write(\n            target.Rig.Skeleton, new Clip(clipName, fps, looping, dmxFrames), new DmxWriteOptions\n            {\n                Name = clipName,\n                SourceNote = isMirrored ? request.SourceFileName \u002B \u0022 (mirrored)\u0022 : request.SourceFileName,\n                // Design \u00A73: ConstraintDriven (twist/helper) bones keep their joints \u002B\n                // bind in the DMX but get NO channels \u2014 the model\u0027s AnimConstraintList\n                // drives them. Face bones are exempt from the exclusion (rest-local\n                // channels): nothing drives them in a compiled sequence, and channel-less\n                // face joints bake statically (eyes out of sockets in ModelDoc). Custom\n                // rigs (FromSkeleton) have NO constraint list \u2014 their helpers keep baked\n                // channels or twist bones freeze (candy-wrapped wrists).\n                // MIRRORED clips use the IDENTICAL exclusion set (data-shape parity with\n                // primary clips, southpaw G8 mirror fix): a channel-less constraint-driven\n                // bone on a mirrored-body clip is no different from one on any leftward\n                // primary pose; the model\u0027s AnimConstraintList drives it at runtime either\n                // way. (ClipMirror.MirrorSafeExclusions remains available for consumers\n                // that need reflection-exact data for excluded bones.)\n                ChannelExcludedBones = target.Rig.HelpersAreConstraintDriven\n                    ? context.ConstraintDrivenBones\n                    : null,\n                UpAxisY = target.UpAxis == TargetUpAxis.YUpCm,\n            });\n\n        var extractMotion = request.RootMotion == RootMotionMode.Extract;\n\n        // Additive variant: \u0027\u003Cclip\u003E_delta\u0027 (shipped naming), collision-suffixed like every\n        // other batch name. Only the NAME is produced here \u2014 the vmdl entry below reuses\n        // the base clip\u0027s DMX (resourcecompiler does the reference-frame subtraction).\n        var deltaName = request.CreateAdditiveVariant\n            ? UniqueClipName(\n                SanitizeClipName(clipName \u002B \u0022_delta\u0022), usedNames, options.AutoSuffixCollisions)\n            : null;\n\n        clips.Add(new ClipResult\n        {\n            ClipName = clipName,\n            SourceFileName = request.SourceFileName,\n            SourceId = sourceId,\n            DmxFileName = dmxFileName,\n            DmxContent = dmx,\n            Mapping = report,\n            Success = true,\n            SolvedFrames = frames,\n            Fps = fps,\n            Looping = looping,\n            ExtractMotion = extractMotion,\n            FootstepEvents = events,\n            IsMirroredVariant = isMirrored,\n            HasAdditiveVariant = deltaName is not null,\n            AdditiveVariantName = deltaName,\n        });\n        var sourceFilename = JoinAssetPath(options.DmxFolderRelative, dmxFileName);\n        entries.Add(new AnimEntry\n        {\n            Name = clipName,\n            SourceFilename = sourceFilename,\n            Looping = looping,\n            ExtractMotion = extractMotion,\n            Events = events,\n        });\n        if (deltaName is not null)\n        {\n            // The shipped _delta sequences carry the AnimSubtract child and nothing else\n            // (no motion extraction, no events) \u2014 an additive layer fires no footsteps and\n            // extracting root motion from a delta makes no sense.\n            entries.Add(new AnimEntry\n            {\n                Name = deltaName,\n                SourceFilename = sourceFilename,\n                Looping = looping,\n                SubtractAnimName = clipName,\n                SubtractFrame = 0,\n            });\n        }\n    }\n\n    /// \u003Csummary\u003E\n    /// Generates the \u003Cc\u003EAE_FOOTSTEP\u003C/c\u003E events for a solved clip when the request asks for\n    /// them (\u003Csee cref=\u0022RetargetRequest.GenerateFootstepEvents\u0022/\u003E): plant intervals are\n    /// detected on the SOLVED TARGET frames (this is where the engine plays the clip, so\n    /// touchdowns must be measured here), each interval start = one footstep\n    /// (\u003Csee cref=\u0022FootstepEvents\u0022/\u003E). Empty when the feature is off or the target rig lacks\n    /// the leg chains / character up (noted on the report then).\n    /// \u003C/summary\u003E\n    private static IReadOnlyList\u003CAnimEventEntry\u003E GenerateFootsteps(\n        RetargetRequest request, RetargetTargetSpec target, TargetContext context,\n        MappingReportInfo report, List\u003CXForm[]\u003E frames, float fps)\n    {\n        if (!request.GenerateFootstepEvents)\n            return Array.Empty\u003CAnimEventEntry\u003E();\n        if (context.Up is not { } up || context.FootChains is not { } feet)\n        {\n            AddNote(report, \u0022Footstep events skipped: \u0022 \u002B context.UpOrChainProblem);\n            return Array.Empty\u003CAnimEventEntry\u003E();\n        }\n        return FootstepEvents.Generate(\n            frames, target.Rig.Skeleton, feet.Left, feet.Right, up, fps,\n            ScaledPlantOptions(target));\n    }\n\n    /// \u003Csummary\u003EDefault plant thresholds are cm-tuned; engine-space rigs are in inches, so\n    /// they are scaled by the cm\u2192inch factor to keep the same physical sensitivity (shared by\n    /// the foot-plant cleanup and the footstep-event detection).\u003C/summary\u003E\n    private static FootPlantOptions ScaledPlantOptions(RetargetTargetSpec target)\n    {\n        var options = new FootPlantOptions();\n        if (target.UpAxis == TargetUpAxis.ZUpEngine)\n        {\n            options.SpeedThresholdCmPerSec *= RetargetTargetSpec.SboxSourceScale;\n            options.HeightThresholdCm *= RetargetTargetSpec.SboxSourceScale;\n        }\n        return options;\n    }\n\n    private static bool MapsPinkyRole(MappingResult map)\n    {\n        foreach (var role in map.RoleToBone.Keys)\n        {\n            if (role.ToString().StartsWith(\u0022Pinky\u0022, StringComparison.Ordinal))\n                return true;\n        }\n        return false;\n    }\n\n    /// \u003Csummary\u003ESolve one take and run the target-space cleanup \u002B IK baking passes.\u003C/summary\u003E\n    private static Clip SolveAndClean(\n        RetargetRequest request, RetargetTargetSpec target, TargetContext context,\n        SourceScene scene, MappingResult map, MappingReportInfo report, int take, string clipName)\n    {\n        var requested = request.Solve ?? new SolveOptions();\n        if(request.MocapCorrections is {} wristSettings)\n        {\n            Motion.WristPositionOffsets.Validate(wristSettings.WristOffsets);\n            if(wristSettings.WristOffsets.Any(e=\u003Ee.Enabled))\n                throw new NotSupportedException(\u0022Manual wrist offsets currently require camera-relative hand capture.\u0022);\n        }\n        if(scene.CaptureContacts?.Contacts.Any(c=\u003Ec.Review==Motion.ContactReview.Confirmed\u0026\u0026!string.IsNullOrEmpty(c.Object))==true)\n            throw new NotSupportedException(\u0022Confirmed prop constraints currently require camera-relative hand capture. Disable those constraints to preview body motion; object tracks remain available in captured-skeleton export.\u0022);\n        var captureClavicleDirections = scene.CaptureSpace is not null \u0026\u0026 requested.TransferModes is null;\n        if (captureClavicleDirections)\n        {\n            // Body-model collar joints are not the target\u0027s anatomical rest carriage.\n            // SMPL\u0027s zero-pose collar-\u003Eshoulder slopes upward; its reconstructed neutral\n            // pose rotates that line down to level. Replaying the same delta onto the\n            // Human\u0027s already-level collar line lowers its shoulders a second time.\n            AddNote(report, \u0022Full-body capture transfers observed clavicle directions while retaining target bone lengths and attachment positions.\u0022);\n        }\n        var solved = new GeometricSolver().Solve(scene, map, target.Rig, new SolveOptions\n        {\n            GroundedLegDirections = request.FootPlantCleanup,\n            HipScaleHorizontal = requested.HipScaleHorizontal,\n            HipScaleVertical = requested.HipScaleVertical,\n            TransferFingers = requested.TransferFingers,\n            TransferModes = requested.TransferModes,\n            CaptureClavicleDirections = captureClavicleDirections,\n            NeutralSourceRest = captureClavicleDirections,\n            ClipIndex = take,\n            ClipName = clipName,\n        });\n        var frames = solved.Frames;\n\n        // ---- embedded-take fidelity: authored local translations pass through ----------\n        if (request.PreserveSourceTranslations)\n            PassThroughSourceTranslations(scene, target.Rig, frames, take, report);\n\n        // ---- foot-plant cleanup (target space; up axis from the TARGET character frame) ----\n        if (request.FootPlantCleanup)\n        {\n            if (context.Up is { } up \u0026\u0026 context.FootChains is { } feet)\n            {\n                // Grounded stance alignment first: levels planted soles against the ground\n                // (removes the stance offset a non-stance source rest leaves in the solver\u0027s\n                // rest-relative foot transfer). Plants are detected on the SOURCE clip \u2014\n                // source-space candidates; hip-height rescaling can push the solved target trajectories\n                // outside the cm-tuned Kovar thresholds. Composes with the position pinning\n                // below (this rotates feet about their own joints; the pinning preserves\n                // foot world rotations).\n                // Reconstructed bodies: restore the performer\u0027s stance width on differently\n                // proportioned hips before anything is levelled or anchored.\n                if(scene.CaptureSpace is not null)\n                {\n                    var stance=Motion.CaptureStanceProportion.Apply(frames,scene,map,target.Rig,feet.Left,feet.Right);\n                    if(stance.Samples\u003E0)AddNote(report,$\u0022Stance proportion: each foot moved {stance.HalfWidthCorrection:F2} target units toward the body\u0027s centre line, because this target\u0027s hip joints are wider relative to its legs than the performer\u0027s. Leg lengths and foot orientation are preserved.\u0022);\n                }\n                GroundAlignFeet(frames, scene, map, target.Rig.Skeleton, feet, up, solved.Fps, take);\n\n                var plantOptions=ScaledPlantOptions(target);\n                // Reconstructed contacts can be unreachable on different proportions.\n                // Keep captured target limb lengths fixed instead of stretching to a guess.\n                if(scene.CaptureSpace is not null)plantOptions.MaxStretch=0f;\n                FootPlant.Apply(\n                    frames, target.Rig.Skeleton, feet.Left, feet.Right, up, solved.Fps,\n                    plantOptions);\n\n                // Support ground alignment: one constant vertical offset per clip that\n                // restores the SOURCE-authored foot-to-ground relationship (southpaw\n                // final regeneration package, gate4_review.md 3.1 / DEFERRED.md f2).\n                AlignSupportToGround(frames, scene, map, target.Rig, feet, up, report, take);\n                MatchSourceFootHeights(frames, scene, map, target.Rig, feet, up, take);\n            }\n            else\n            {\n                AddNote(report, \u0022Foot-plant cleanup skipped: \u0022 \u002B context.UpOrChainProblem);\n            }\n        }\n\n        // A reconstructed body has no finger tracks; give its hands a resting shape, not the bind pose.\n        if(scene.CaptureSpace is not null)\n        {\n            if(Motion.CaptureSpineSpread.Apply(frames,target.Rig)\u003E0)AddNote(report,\u0022Spine: each frame\u0027s bend from the hips to the chest is shared evenly between the spine bones; the network puts most of it in the lowest one. Chest, head and arms are unchanged.\u0022);\n            var shoulders=Motion.CaptureShoulderCarriage.Apply(frames,scene.Clips[take].Frames,scene.Skeleton,map,target.Rig);\n            if(shoulders\u003E0)AddNote(report,$\u0022Shoulders: {shoulders} clavicle samples carry the performer\u0027s change from their own rest shoulder line onto this target\u0027s rest shoulder line, instead of copying a differently built clavicle\u0027s direction. Arms keep their solved orientation.\u0022);\n            // After the shoulders are placed: restore the performer\u0027s hand spacing on differently proportioned shoulders.\n            var arms=Motion.CaptureArmProportion.Apply(frames,scene.Skeleton,map,target.Rig);\n            if(arms.Samples\u003E0)AddNote(report,$\u0022Hand spacing: wrists in front of or across the body moved up to {arms.HalfWidthCorrection:F2} target units toward the centre line, because this target\u0027s shoulders are wider relative to its arms than the performer\u0027s. Arm lengths and hand orientation are preserved; outstretched arms are left alone.\u0022);\n            var together=Motion.CaptureHandRelation.Apply(frames,scene.Clips[take].Frames,scene.Skeleton,map,target.Rig);\n            if(together\u003E0)AddNote(report,$\u0022Hands together: in {together} frames the performer\u0027s hands were close (crossing, clapping or touching) and the character\u0027s hands were placed the same way from each other, scaled to its arms.\u0022);\n            var relaxed=Motion.RelaxedHands.Apply(frames,map,target.Rig);\n            if(relaxed\u003E0)AddNote(report,$\u0022Hands: this body capture has no finger tracks, so {relaxed} target finger joints hold one authored, slightly curled resting pose instead of the bind pose. It is not captured finger motion.\u0022);\n        }\n\n        // ---- optional arm effector IK (default off: the solver already matches anatomical\n        // directions; arm IK is only for reach-critical work) ----\n        if (request.ArmEffectorIk)\n        {\n            var problem = ArmIkCleanup.Apply(frames, scene, map, target.Rig, context, take);\n            if (problem is not null)\n                AddNote(report, \u0022Arm effector IK skipped: \u0022 \u002B problem);\n        }\n\n        // ---- root motion (see class remarks for the Extract \u2194 ExtractMotion mapping) ----\n        if(request.FootPlantCleanup\u0026\u0026(request.MocapCorrections?.StabilizeFeet??true))\n        {\n            var anchored=Motion.CaptureContactRoot.Apply(frames,scene,map,target.Rig,target.UpAxis);\n            if(anchored\u003E0)AddNote(report,FormattableString.Invariant($\u0022Travel from contacts: planted feet no longer slide; the body\u0027s travel was corrected by up to {anchored:F0} cm to match them.\u0022));\n            var locking=Motion.CaptureFootLock.Apply(frames,scene,map,target.Rig,target.UpAxis);\n            if(locking.ConstrainedSamples\u003E0)AddNote(report,$\u0022Final target foot anchors: {locking.ConstrainedSamples} leg samples; maximum reach residual {locking.MaximumReachResidual:F4} target units; level-floor height drift of up to {locking.MaximumFloorDrift:F2} target units removed from the root. Backend static probabilities are contact suggestions, not measured ground truth.\u0022);\n            // Keep the whole clip on the floor, including camera-relative captures and dance with few plants.\n            if(scene.CaptureSpace is not null)\n            {\n                var contactMask=Motion.CaptureContactRoot.ContactMask(frames,scene,map,target.Rig,target.UpAxis);\n                var grounded=Motion.CaptureGround.Apply(frames,target.Rig,target.UpAxis,solved.Fps,contactMask);\n                if(grounded\u003E0)AddNote(report,FormattableString.Invariant($\u0022Floor followed through the clip: up to {grounded:F1} cm of drift toward or away from the floor removed.\u0022));\n                var hovering=Motion.CaptureHover.Apply(frames,target.Rig,target.UpAxis,solved.Fps,contactMask);\n                if(hovering\u003E0)AddNote(report,$\u0022Kept on the floor in {hovering} frames: brief hovering above it or sinking into it removed.\u0022);\n                var seatedFrames=Motion.CaptureSeat.Apply(frames,scene,map,target.Rig,target.UpAxis);\n                if(seatedFrames\u003E0)AddNote(report,$\u0022Seated on the floor in {seatedFrames} frames: hips lowered onto the floor, feet and resting hands held in place.\u0022);\n                var handsHeld=Motion.CaptureHandPlant.Apply(frames,target.Rig,target.UpAxis,solved.Fps,PlantedHands(scene,map,frames.Count),HandSpread(scene,map,take));\n                if(handsHeld\u003E0)AddNote(report,$\u0022Hands on the floor held in place in {handsHeld} hand samples: palms resting on the floor no longer slide or hover.\u0022);\n            }\n        }\n        // Last of the leg work: no thigh, shin or foot turns far more in one frame than around it.\n        if(scene.CaptureSpace is not null\u0026\u0026Motion.CaptureLegSnaps.Apply(frames,target.Rig,solved.Fps,target.UpAxis==TargetUpAxis.ZUpEngine?39.3700787f:100f,PlantedFeet(scene,map,frames.Count)) is var snaps\u0026\u0026snaps\u003E0)\n            AddNote(report,$\u0022Leg continuity corrected in {snaps} samples: isolated rotation or knee-position jolts were spread over neighbouring frames, preserving foot anchors where the constraints allowed.\u0022);\n        ApplyRootMotion(request.RootMotion, frames, context, report);\n\n        if (request.MocapCorrections is { } corrections)\n        {\n            Motion.TargetCorrections.Apply(frames, target.Rig, target.UpAxis, corrections);\n            if (corrections.FirstPerson) AddNote(report, \u0022Shoulders and elbows are generated target-rig IK, not measured joints.\u0022);\n        }\n\n        if (scene.CaptureSpace is not null)\n        {\n            var clearance = Motion.CaptureArmClearance.Apply(frames, scene.Clips[take].Frames, scene.Skeleton, map,\n                target.Rig, solved.Fps, out var unresolvedContacts, out var maximumPenetration);\n            if (clearance.Samples \u003E 0)\n                AddNote(report, FormattableString.Invariant($\u0022Torso contact: DigitalRune CCD adjusted {clearance.Samples} hand samples by up to {clearance.Largest:F2} target units, preserving wrist attitude and finger articulation. Clearance uses a bone-derived body proxy.\u0022));\n            if (unresolvedContacts \u003E 0)\n                AddNote(report, FormattableString.Invariant($\u0022Torso contact remains unresolved in {unresolvedContacts} hand samples (up to {maximumPenetration:F3} target units). Fixed arm lengths and wrist attitude prevented a clear proxy pose; review these contacts.\u0022));\n        }\n\n        // Last of the pose cleanup: whatever snap a step above left (an IK flip, a contact pushed clear, a hold handed\n        // over) is pulled back onto its neighbours\u0027 path, keeping planted hands and feet where they are.\n        if (scene.CaptureSpace is not null \u0026\u0026 Motion.CaptureDespike.Apply(frames, target.Rig, target.UpAxis == TargetUpAxis.ZUpEngine ? 1 / 2.54f : 1f) is var smoothedSnaps \u0026\u0026 smoothedSnaps \u003E 0)\n            AddNote(report, $\u0022Snaps removed after cleanup: {smoothedSnaps} joint samples that left the smooth path through their neighbours were pulled back onto it.\u0022);\n\n        // ---- IK helper bones (root_IK, IK targets, ikrule) need real baked channels ----\n        if (context.HasIkBakedBones)\n            IkBoneBaker.Bake(frames, target.Rig);\n\n        // ---- unmapped limb twist bones follow their joint\u0027s roll ------------------------\n        // Mocap exports a portable baked armature, so it cannot rely on the target\n        // model\u0027s runtime constraints. Its preview overrides those helpers too.\n        // Keep runtime-owned helpers only for the ordinary model-constraint path.\n        var twistCount = TwistBoneFollow.Apply(frames, target.Rig,\n            request.MocapCorrections is null \u0026\u0026 target.Rig.HelpersAreConstraintDriven ? context.ConstraintDrivenBones : null);\n        if (twistCount \u003E 0)\n            AddNote(report, $\u0022{twistCount} limb deform helper bone(s) follow their \u0022\n                \u002B \u0022neighboring joints (left at rest they pinch or candy-wrap the skin).\u0022);\n\n        // ---- orphan helper bones ride the hips (LAST: anchored to the FINAL hips, after\n        // foot-plant pinning / root motion have settled the trajectory) -------------------\n        FollowHipsWithOrphanBones(target.Rig, frames, report);\n\n        var looping = request.LoopingOverride ?? solved.Looping;\n        return new Clip(clipName, solved.Fps, looping, frames);\n    }\n\n    /// \u003Csummary\u003EPer source frame, how far apart the performer\u0027s hands are across the floor, in shoulder widths; null when the\n    /// source lacks hands or shoulders. The capture is Y-up.\u003C/summary\u003E\n    static float[] HandSpread(SourceScene scene,MappingResult map,int take)\n    {\n        if(!map.RoleToBone.TryGetValue(BoneRole.HandL,out var handL)||!map.RoleToBone.TryGetValue(BoneRole.HandR,out var handR)\n            ||!map.RoleToBone.TryGetValue(BoneRole.UpperArmL,out var armL)||!map.RoleToBone.TryGetValue(BoneRole.UpperArmR,out var armR))return null;\n        var source=scene.Clips[take].Frames;var world=new XForm[scene.Skeleton.Count];var spread=new float[source.Count];\n        for(var f=0;f\u003Csource.Count;f\u002B\u002B)\n        {\n            FkUtil.ToWorld(source[f],scene.Skeleton,world);\n            var apart=world[handL].Pos-world[handR].Pos;apart.Y=0;\n            var shoulders=Vector3.Distance(world[armL].Pos,world[armR].Pos);\n            spread[f]=shoulders\u003E1e-6f?apart.Length()/shoulders:0;\n        }\n        return spread;\n    }\n\n    /// \u003Csummary\u003EFrames where the capture marks each hand on the floor (stationary probability at least one half).\u003C/summary\u003E\n    static Dictionary\u003CBoneRole,bool[]\u003E PlantedHands(SourceScene scene,MappingResult map,int count)\n        =\u003Enew[]{BoneRole.HandL,BoneRole.HandR}.ToDictionary(role=\u003Erole,role=\u003E\n        {\n            var result=new bool[count];\n            if(map.RoleToBone.TryGetValue(role,out var bone)\u0026\u0026scene.CaptureStationaryJoints?.TryGetValue(scene.Skeleton[bone].Name,out var p)==true\u0026\u0026p.Length==count)\n                for(var f=0;f\u003Ccount;f\u002B\u002B)result[f]=p[f]\u003E=.5f;\n            return result;\n        });\n\n    /// \u003Csummary\u003EFrames where the capture marks each joint planted (stationary probability at least one half): left ankle, left\n    /// toe, right ankle, right toe.\u003C/summary\u003E\n    static bool[][] PlantedFeet(SourceScene scene,MappingResult map,int count)\n        =\u003Enew[]{BoneRole.FootL,BoneRole.ToeL,BoneRole.FootR,BoneRole.ToeR}.Select(role=\u003E\n        {\n            var result=new bool[count];\n            if(map.RoleToBone.TryGetValue(role,out var bone)\u0026\u0026scene.CaptureStationaryJoints?.TryGetValue(scene.Skeleton[bone].Name,out var p)==true\u0026\u0026p.Length==count)\n                for(var f=0;f\u003Ccount;f\u002B\u002B)result[f]=p[f]\u003E=.5f;\n            return result;\n        }).ToArray();\n\n    /// \u003Csummary\u003E\n    /// Unmapped bone subtrees OUTSIDE the mapped skeleton (no mapped ancestor \u2014 cloth and\n    /// physics helpers parented to the scene root; real case: a skirt of 48 kilt bones on\n    /// a Sketchfab catgirl, siblings of the body root) ride the character rigidly. Left\n    /// at their rest locals they freeze at the bind spot while the body animates away\n    /// (\u0022one part of the body doesn\u0027t move at all\u0022) and the mesh skinned across the\n    /// boundary shears (\u0022completely stretched\u0022). Each subtree\u0027s topmost bone anchors to\n    /// the HIPS \u2014 or to an extremity (hand/foot/head) when its rest sits clearly closer\n    /// to it (a sword resting in the hand follows the hand, not the pelvis). Descendants\n    /// ride along on their rest locals; bones on the hips\u0027 own ancestor path stay\n    /// solver-owned (trajectory). A mapped body branch on a separate control tree is\n    /// similarly anchored to the nearest hips-connected mapped joint; its solved rotation\n    /// remains unchanged.\n    /// \u003C/summary\u003E\n    private static void FollowHipsWithOrphanBones(\n        TargetRig rig, List\u003CXForm[]\u003E frames, MappingReportInfo report)\n    {\n        var skeleton = rig.Skeleton;\n        if (rig.BoneForRole(BoneRole.Hips) is not { } hips || frames.Count == 0)\n            return;\n\n        var hipsPath = new HashSet\u003Cint\u003E();\n        for (var b = hips; b \u003E= 0; b = skeleton[b].ParentIndex)\n            hipsPath.Add(b);\n\n        bool HasMappedAncestor(int bone)\n        {\n            for (var b = skeleton[bone].ParentIndex; b \u003E= 0; b = skeleton[b].ParentIndex)\n            {\n                if (rig.RoleOf(b) is not null)\n                    return true;\n            }\n            return false;\n        }\n\n        var rest = skeleton.RestWorld;\n\n        bool DescendsFrom(int bone, int ancestor)\n        {\n            for (var b = bone; b \u003E= 0; b = skeleton[b].ParentIndex)\n                if (b == ancestor)\n                    return true;\n            return false;\n        }\n\n        // Extremity anchors: adopted only when the orphan rests at less than half its\n        // hips distance \u2014 near-torso helpers (skirts, tails, capes) stay on the hips,\n        // which never mistakes a skirt panel brushing a thigh for hand luggage.\n        var extremities = new List\u003Cint\u003E();\n        foreach (var role in new[]\n        {\n            BoneRole.HandL, BoneRole.HandR, BoneRole.FootL, BoneRole.FootR, BoneRole.Head,\n        })\n        {\n            if (rig.BoneForRole(role) is { } bone)\n                extremities.Add(bone);\n        }\n\n        // Topmost orphans: unmapped, off the hips\u0027 ancestor path, no mapped ancestor,\n        // and the parent is either the scene root path or absent (children of deeper\n        // orphans ride along unchanged).\n        var tops = new List\u003C(int Bone, int Anchor)\u003E();\n        for (var i = 0; i \u003C skeleton.Count; i\u002B\u002B)\n        {\n            if (rig.RoleOf(i) is not null || hipsPath.Contains(i) || HasMappedAncestor(i))\n                continue;\n            var parent = skeleton[i].ParentIndex;\n            if (parent \u003E= 0 \u0026\u0026 !hipsPath.Contains(parent))\n                continue;\n\n            var anchor = hips;\n            var hipsDistance = (rest[i].Pos - rest[hips].Pos).Length();\n            var best = hipsDistance * 0.5f;\n            foreach (var candidate in extremities)\n            {\n                var distance = (rest[i].Pos - rest[candidate].Pos).Length();\n                if (distance \u003C best)\n                {\n                    best = distance;\n                    anchor = candidate;\n                }\n            }\n            tops.Add((i, anchor));\n        }\n\n        // A few constraint-oriented exports place a real mapped body branch on a parallel\n        // control hierarchy. The common case is a skinned head under CONTROL_NECK while\n        // the deform cervical chain is under the hips. glTF/FBX does not preserve the DCC\n        // constraint that joined those trees, so rotations solve but the branch stays at\n        // its bind position. Anchor each topmost detached mapped branch to the nearest\n        // mapped joint that really descends from the hips, preserving its solved rotation.\n        var connectedMapped = Enumerable.Range(0, skeleton.Count)\n            .Where(i =\u003E rig.RoleOf(i) is not null \u0026\u0026 DescendsFrom(i, hips))\n            .ToList();\n        var detachedMapped = new List\u003C(int Bone, int Anchor)\u003E();\n        for (var i = 0; i \u003C skeleton.Count; i\u002B\u002B)\n        {\n            if (rig.RoleOf(i) is null || hipsPath.Contains(i) || DescendsFrom(i, hips)\n                || HasMappedAncestor(i) || connectedMapped.Count == 0)\n                continue;\n            var anchor = connectedMapped\n                .OrderBy(candidate =\u003E (rest[i].Pos - rest[candidate].Pos).LengthSquared())\n                .First();\n            detachedMapped.Add((i, anchor));\n        }\n\n        // A detached deform head may retain a small control-space bind pitch after the DCC\n        // constraint is lost. Infer its gaze only when one local axis already agrees closely\n        // with character-forward, then remove the small vertical component. Applying the\n        // correction in rest-local space preserves every solved animation delta.\n        var neutralHead = -1;\n        var neutralHeadCorrection = Quaternion.Identity;\n        foreach (var (bone, _) in detachedMapped)\n        {\n            if (rig.RoleOf(bone) == BoneRole.Head\n                \u0026\u0026 TryDetachedHeadNeutralCorrection(rig, bone, out neutralHeadCorrection))\n            {\n                neutralHead = bone;\n                break;\n            }\n        }\n\n        if (tops.Count == 0 \u0026\u0026 detachedMapped.Count == 0)\n            return;\n\n        var anchorRestInverse = new Dictionary\u003Cint, XForm\u003E();\n        foreach (var (_, anchor) in tops)\n            anchorRestInverse[anchor] = rest[anchor].Inverse();\n        foreach (var (_, anchor) in detachedMapped)\n            anchorRestInverse[anchor] = rest[anchor].Inverse();\n\n        foreach (var frame in frames)\n        {\n            var world = new Skeleton.Pose(frame).ToWorld(skeleton);\n            foreach (var (top, anchor) in tops)\n            {\n                var delta = XForm.Compose(world[anchor], anchorRestInverse[anchor]);\n                var parent = skeleton[top].ParentIndex;\n                var parentWorld = parent \u003E= 0 ? world[parent] : XForm.Identity;\n                frame[top] = XForm.ToLocal(\n                    parentWorld, XForm.Compose(delta, rest[top]));\n            }\n\n            if (detachedMapped.Count == 0)\n                continue;\n\n            // Re-evaluate after moving orphan control roots (the detached branch\u0027s actual\n            // parent may be inside one). Only position is anchored: its mapped rotation is\n            // the solver\u0027s result and must remain authoritative.\n            world = new Skeleton.Pose(frame).ToWorld(skeleton);\n            foreach (var (bone, anchor) in detachedMapped)\n            {\n                var delta = XForm.Compose(world[anchor], anchorRestInverse[anchor]);\n                var rotation = bone == neutralHead\n                    ? MathQ.Normalize(world[bone].Rot * neutralHeadCorrection)\n                    : world[bone].Rot;\n                var desired = new XForm(\n                    XForm.Compose(delta, rest[bone]).Pos,\n                    rotation);\n                var parent = skeleton[bone].ParentIndex;\n                frame[bone] = parent \u003C 0\n                    ? desired\n                    : XForm.ToLocal(world[parent], desired);\n            }\n        }\n        if (tops.Count \u003E 0)\n            AddNote(report,\n                $\u0022{tops.Count} helper bone subtree(s) outside the mapped skeleton ride the \u0022\n                \u002B \u0022character (cloth/physics/prop bones would otherwise freeze at their bind position).\u0022);\n        if (detachedMapped.Count \u003E 0)\n            AddNote(report,\n                $\u0022{detachedMapped.Count} mapped body branch(es) on separate control hierarchies \u0022\n                \u002B \u0022follow the connected skeleton (exported DCC constraints are not available at runtime).\u0022);\n        if (neutralHead \u003E= 0)\n            AddNote(report,\n                \u0022Detached head bind pitch was leveled to the character facing plane while preserving animation.\u0022);\n    }\n\n    private static void MatchSourceFootHeights(\n        List\u003CXForm[]\u003E frames, SourceScene scene, MappingResult map, TargetRig rig,\n        (FootChain Left, FootChain Right) feet, Vector3 up, int take)\n    {\n        if (frames.Count == 0 || !map.RoleToBone.TryGetValue(BoneRole.Hips, out var srcHips)\n            || rig.BoneForRole(BoneRole.Hips) is not int tgtHips)\n            return;\n        var source = scene.Skeleton;\n        var target = rig.Skeleton;\n        if (!scene.RestPlacementAuthored \u0026\u0026 !RestNormalizer.IsAnatomicalRest(source, map, source.RestWorld))\n            return; // Bone-length-only rests cannot calibrate an anatomical support height.\n        var srcFrames = scene.Clips[take].Frames;\n        if (srcFrames.Count != frames.Count)\n            return;\n        var srcUp = scene.UpAxis switch\n        {\n            0 =\u003E new Vector3(scene.UpAxisSign, 0, 0),\n            2 =\u003E new Vector3(0, 0, scene.UpAxisSign),\n            _ =\u003E new Vector3(0, scene.UpAxisSign, 0),\n        };\n        up = GroundUp(up);\n        var worlds = new XForm[frames.Count][];\n        var restGround = float.PositiveInfinity;\n        var motionGround = float.PositiveInfinity;\n        foreach (var rest in source.RestWorld)\n            restGround = MathF.Min(restGround, Vector3.Dot(rest.Pos, srcUp));\n        for (var f = 0; f \u003C frames.Count; f\u002B\u002B)\n        {\n            worlds[f] = new Skeleton.Pose(srcFrames[f]).ToWorld(source);\n            foreach (var bone in worlds[f])\n                motionGround = MathF.Min(motionGround, Vector3.Dot(bone.Pos, srcUp));\n        }\n        var placement = scene.RestPlacementAuthored ? 0f : motionGround - restGround;\n        var corrections = new List\u003C(FootChain Chain, Vector3[] Goals)\u003E();\n        var lowerPelvis = new float[frames.Count];\n        foreach (var (footRole, toeRole, chain) in new[]\n        {\n            (BoneRole.FootL, BoneRole.ToeL, feet.Left), (BoneRole.FootR, BoneRole.ToeR, feet.Right),\n        })\n        {\n            if (!map.RoleToBone.TryGetValue(footRole, out var foot)\n                || !map.RoleToBone.TryGetValue(toeRole, out var toe) || chain.Toe is not int tgtToe)\n                continue;\n            float Support(IReadOnlyList\u003CXForm\u003E pose, int ankle, int tip, Vector3 vertical)\n                =\u003E MathF.Min(Vector3.Dot(pose[ankle].Pos, vertical), Vector3.Dot(pose[tip].Pos, vertical));\n            var srcRest = Support(source.RestWorld, foot, toe, srcUp);\n            var tgtRest = Support(target.RestWorld, chain.Ankle, tgtToe, up);\n            // Animation-only FBXs can store a mid-stride rest, with one foot lifted.\n            // That raised foot is not a ground reference: subtracting it drives its\n            // planted frames below the floor. An authored rest never needs a higher\n            // support baseline than the lowest support actually reached by that foot.\n            if (scene.RestPlacementAuthored)\n                foreach (var pose in worlds)\n                    srcRest = MathF.Min(srcRest, Support(pose, foot, toe, srcUp));\n            var srcHeight = Vector3.Dot(source.RestWorld[srcHips].Pos, srcUp) - srcRest;\n            if (srcHeight \u003C= .001f)\n                continue;\n            var ratio = Math.Clamp((Vector3.Dot(target.RestWorld[tgtHips].Pos, up) - tgtRest) / srcHeight, .25f, 4f);\n            var goals = new Vector3[frames.Count];\n            for (var f = 0; f \u003C frames.Count; f\u002B\u002B)\n            {\n                var world = new Skeleton.Pose(frames[f]).ToWorld(target);\n                var desired = tgtRest \u002B (Support(worlds[f], foot, toe, srcUp) - srcRest - placement) * ratio;\n                goals[f] = world[chain.Ankle].Pos \u002B up * (desired - Support(world, chain.Ankle, tgtToe, up));\n                var reach = Vector3.Distance(world[chain.Hip].Pos, world[chain.Knee].Pos)\n                    \u002B Vector3.Distance(world[chain.Knee].Pos, world[chain.Ankle].Pos);\n                var toHip = world[chain.Hip].Pos - goals[f];\n                if (scene.CaptureSpace is not null)\n                {\n                    lowerPelvis[f] = MathF.Max(lowerPelvis[f], Motion.CaptureLegReach.Lowering(toHip, up, reach));\n                    continue;\n                }\n                var vertical = Vector3.Dot(toHip, up);\n                var horizontal = toHip - up * vertical;\n                if (horizontal.LengthSquared() \u003C reach * reach)\n                    lowerPelvis[f] = MathF.Max(lowerPelvis[f], vertical\n                        - MathF.Sqrt(reach * reach - horizontal.LengthSquared()));\n            }\n            corrections.Add((chain, goals));\n        }\n        // At full extension, lower the pelvis only as far as needed to reach BOTH\n        // contacts. Stretching bones or accepting an unreachable goal leaves a hover.\n        for (var f = 0; f \u003C frames.Count; f\u002B\u002B)\n        {\n            if (lowerPelvis[f] \u003C= 0f) continue;\n            var parent = target[tgtHips].ParentIndex;\n            var shift = -up * lowerPelvis[f];\n            if (parent \u003E= 0)\n                shift = Vector3.Transform(shift, Quaternion.Conjugate(\n                    new Skeleton.Pose(frames[f]).ToWorld(target)[parent].Rot));\n            frames[f][tgtHips].Pos \u002B= shift;\n        }\n        foreach (var (chain, goals) in corrections)\n        {\n            // Vertical IK preserves horizontal travel and foot rotation; it never scales bones.\n            EffectorIk.ApplyGoals(frames, target,\n                new LimbChain { Upper = chain.Hip, Lower = chain.Knee, End = chain.Ankle },\n                goals, ArmIkCleanup.RestBendAxis(target, chain.Hip, chain.Knee, chain.Ankle), soften: 0f);\n        }\n    }\n\n    private static bool TryDetachedHeadNeutralCorrection(\n        TargetRig rig, int head, out Quaternion localCorrection)\n    {\n        localCorrection = Quaternion.Identity;\n        CharacterFrame frame;\n        try\n        {\n            frame = CharacterFrame.Compute(\n                rig.Skeleton, rig.ToMappingResult(), rig.Skeleton.RestWorld);\n        }\n        catch (ArgumentException)\n        {\n            return false;\n        }\n\n        var restRotation = MathQ.Normalize(rig.Skeleton.RestWorld[head].Rot);\n        var gaze = Vector3.Zero;\n        var agreement = float.NegativeInfinity;\n        foreach (var localAxis in new[] { Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ })\n        {\n            var axis = Vector3.Transform(localAxis, restRotation);\n            var dot = Vector3.Dot(axis, frame.Forward);\n            if (MathF.Abs(dot) \u003C= agreement)\n                continue;\n            agreement = MathF.Abs(dot);\n            gaze = dot \u003C 0f ? -axis : axis;\n        }\n\n        var vertical = Vector3.Dot(gaze, frame.Up);\n        const float minAgreement = 0.94f; // local axis must be within 20\u00B0 of facing\n        const float minPitch = 0.5f * MathF.PI / 180f;\n        const float maxPitch = 12f * MathF.PI / 180f;\n        var pitch = MathF.Asin(Math.Clamp(vertical, -1f, 1f));\n        if (agreement \u003C minAgreement || MathF.Abs(pitch) \u003C minPitch || MathF.Abs(pitch) \u003E maxPitch)\n            return false;\n\n        var levelGaze = gaze - frame.Up * vertical;\n        if (levelGaze.LengthSquared() \u003C 1e-8f)\n            return false;\n        levelGaze = Vector3.Normalize(levelGaze);\n\n        var worldCorrection = MathQ.FromTo(gaze, levelGaze);\n        localCorrection = MathQ.Normalize(\n            Quaternion.Conjugate(restRotation) * worldCorrection * restRotation);\n        return true;\n    }\n\n    /// \u003Csummary\u003E\n    /// The engine-side yaw correction for embedded meshes and compiled Z-up targets (see\n    /// \u003Csee cref=\u0022EmitClip\u0022/\u003E): the compiler\u0027s source-axis conversion for ROOT-LEVEL\n    /// animation channels lands 90\u00B0 about up away from where it puts the mesh bind.\n    /// Pre-rotating root locals by the inverse importer yaw (\u221290\u00B0 for Y-up,\n    /// \u002B90\u00B0 for Z-up) makes compiled playback match the bind; children are parent-relative.\n    /// \u003C/summary\u003E\n    private static List\u003CXForm[]\u003E CompensateEmbeddedMeshRootYaw(\n        IReadOnlyList\u003CXForm[]\u003E frames, TargetRig rig, TargetUpAxis upAxis)\n    {\n        var yUp = upAxis == TargetUpAxis.YUpCm;\n        var axis = yUp ? Vector3.UnitY : Vector3.UnitZ;\n        var yaw = Quaternion.CreateFromAxisAngle(axis, (yUp ? -1f : 1f) * MathF.PI * 0.5f);\n        var skeleton = rig.Skeleton;\n        var result = new List\u003CXForm[]\u003E(frames.Count);\n        foreach (var frame in frames)\n        {\n            var copy = new XForm[frame.Length];\n            for (var i = 0; i \u003C frame.Length; i\u002B\u002B)\n            {\n                copy[i] = i \u003C skeleton.Count \u0026\u0026 skeleton[i].ParentIndex \u003C 0\n                    ? new XForm(\n                        Vector3.Transform(frame[i].Pos, yaw),\n                        MathQ.Normalize(yaw * frame[i].Rot))\n                    : frame[i];\n            }\n            result.Add(copy);\n        }\n        return result;\n    }\n\n    /// \u003Csummary\u003ETest seam for \u003Csee cref=\u0022CompensateEmbeddedMeshRootYaw\u0022/\u003E (gate bisects\n    /// re-serialize mutated frames with the same compensation the pipeline applies).\u003C/summary\u003E\n    public static List\u003CXForm[]\u003E TestHook_CompensateEmbeddedMeshRootYaw(\n        IReadOnlyList\u003CXForm[]\u003E frames, RetargetTargetSpec target)\n        =\u003E !string.IsNullOrEmpty(target.MeshFilePath) || target.UpAxis == TargetUpAxis.ZUpEngine\n            ? CompensateEmbeddedMeshRootYaw(frames, target.Rig, target.UpAxis)\n            : frames.ToList();\n\n    /// \u003Csummary\u003ETest seam for \u003Csee cref=\u0022FollowHipsWithOrphanBones\u0022/\u003E.\u003C/summary\u003E\n    public static void TestHook_FollowOrphans(TargetRig rig, List\u003CXForm[]\u003E frames)\n        =\u003E FollowHipsWithOrphanBones(rig, frames, new MappingReportInfo\n        {\n            ProfileName = \u0022test\u0022,\n            Source = MappingSource.Manual,\n            Confidence = 1f,\n            NeedsUserDecision = false,\n            MappedRoleCount = 0,\n            SkeletonSignature = \u0022\u0022,\n        });\n\n    /// \u003Csummary\u003E\n    /// \u003Csee cref=\u0022RetargetRequest.PreserveSourceTranslations\u0022/\u003E: per-frame source local\n    /// translations onto same-named target bones. Names are compared engine-sanitized\n    /// (non-alphanumerics \u2192 \u003Cc\u003E_\u003C/c\u003E: the compiled-model rig the editor rebuilds carries\n    /// \u003Cc\u003EBip01_R_Hand\u003C/c\u003E for the file\u0027s \u003Cc\u003EBip01 R Hand\u003C/c\u003E). A matched bone whose REST\n    /// translation disagrees between the rigs is skipped \u2014 the name collision is then\n    /// coincidence, not the same joint. The hips and its ancestors always stay\n    /// solver-owned (trajectory, root-motion modes, hip rescale).\n    /// \u003C/summary\u003E\n    private static void PassThroughSourceTranslations(\n        SourceScene scene, TargetRig rig, List\u003CXForm[]\u003E frames, int take,\n        MappingReportInfo report)\n    {\n        var src = scene.Skeleton;\n        var tgt = rig.Skeleton;\n        var srcClip = scene.Clips[take];\n        if (srcClip.Frames.Count != frames.Count)\n        {\n            AddNote(report, \u0022Source translations not preserved: frame counts differ \u0022\n                \u002B $\u0022({srcClip.Frames.Count} source vs {frames.Count} solved).\u0022);\n            return;\n        }\n\n        static string Key(string name)\n        {\n            Span\u003Cchar\u003E c = stackalloc char[name.Length];\n            for (var i = 0; i \u003C name.Length; i\u002B\u002B)\n                c[i] = char.IsLetterOrDigit(name[i]) ? char.ToLowerInvariant(name[i]) : \u0027_\u0027;\n            return new string(c);\n        }\n\n        var srcByName = new Dictionary\u003Cstring, int\u003E();\n        for (var i = 0; i \u003C src.Count; i\u002B\u002B)\n        {\n            // Duplicate keys are ambiguous - poison them rather than guess.\n            var key = Key(src[i].Name);\n            srcByName[key] = srcByName.ContainsKey(key) ? -1 : i;\n        }\n\n        var excluded = new HashSet\u003Cint\u003E();\n        if (rig.BoneForRole(BoneRole.Hips) is { } hips)\n            for (var b = hips; b \u003E= 0; b = tgt[b].ParentIndex)\n                excluded.Add(b);\n\n        var applied = 0;\n        for (var t = 0; t \u003C tgt.Count; t\u002B\u002B)\n        {\n            if (excluded.Contains(t)\n                || !srcByName.TryGetValue(Key(tgt[t].Name), out var s) || s \u003C 0)\n                continue;\n            // Same joint check: rest translations must agree (same rig, same space).\n            var restDelta = (src[s].RestLocal.Pos - tgt[t].RestLocal.Pos).Length();\n            if (restDelta \u003E MathF.Max(1f, 0.1f * tgt[t].RestLocal.Pos.Length()))\n                continue;\n            for (var f = 0; f \u003C frames.Count; f\u002B\u002B)\n                frames[f][t] = new XForm(srcClip.Frames[f][s].Pos, frames[f][t].Rot);\n            applied\u002B\u002B;\n        }\n        if (applied \u003E 0)\n            AddNote(report, $\u0022Embedded take: authored local translations preserved on {applied} bones.\u0022);\n    }\n\n    /// \u003Csummary\u003E\n    /// Normalized-rest foot pitch beyond which (toe approaching/above ankle level) the rest\n    /// cannot be a flat stance \u2014 measured stance rests sit at \u221211\u00B0\u2026\u221251\u00B0; the repro artifact\n    /// rig measured \u002B2.7\u00B0 on one foot.\n    /// \u003C/summary\u003E\n    private const float StancePitchMaxDeg = -5f;\n\n    /// \u003Csummary\u003ELeft/right normalized-rest foot pitch asymmetry beyond which the rest is not\n    /// a (symmetric) stance \u2014 measured stance rests differ \u2264 2.4\u00B0; the repro artifact rig\n    /// 13.8\u00B0.\u003C/summary\u003E\n    private const float StancePitchAsymmetryDeg = 6f;\n\n    /// \u003Csummary\u003E\n    /// The grounded-foot stance recalibration step (\u003Csee cref=\u0022FootGroundAlign\u0022/\u003E). Runs ONLY\n    /// when the source\u0027s NORMALIZED rest \u2014 the solver\u0027s delta reference \u2014 is implausible as a\n    /// flat stance (a foot\u0027s toe at/above ankle level, or the two feet resting asymmetrically;\n    /// both measured on the repro rig, where T-pose normalization of a bent-leg rest swings\n    /// the feet 14\u201326\u00B0 away from the rig\u0027s true stance). On plausible stance rests the solver\u0027s\n    /// rest-relative foot transfer is already faithful, and planted-sole deviations are\n    /// genuine articulation (boxing stances, heel rolls) that must NOT be flattened. Plant\n    /// intervals are detected on the SOURCE clip (cm space, default Kovar thresholds).\n    /// Best-effort \u2014 silently skipped when the source maps no complete leg chains \u002B toes or a\n    /// character frame is not computable (the foot transfer is then simply left as solved).\n    /// \u003C/summary\u003E\n    private static void GroundAlignFeet(\n        List\u003CXForm[]\u003E frames, SourceScene scene, MappingResult map, SkeletonModel targetSkeleton,\n        (FootChain Left, FootChain Right) targetFeet, Vector3 targetUp, float fps, int take)\n    {\n        FootChain? SourceChain(BoneRole upper, BoneRole lower, BoneRole foot, BoneRole toe)\n            =\u003E map.RoleToBone.TryGetValue(upper, out var hip)\n               \u0026\u0026 map.RoleToBone.TryGetValue(lower, out var knee)\n               \u0026\u0026 map.RoleToBone.TryGetValue(foot, out var ankle)\n                ? new FootChain\n                {\n                    Hip = hip,\n                    Knee = knee,\n                    Ankle = ankle,\n                    Toe = map.RoleToBone.TryGetValue(toe, out var t) ? t : null,\n                }\n                : null;\n\n        var srcLeft = SourceChain(BoneRole.UpperLegL, BoneRole.LowerLegL, BoneRole.FootL, BoneRole.ToeL);\n        var srcRight = SourceChain(BoneRole.UpperLegR, BoneRole.LowerLegR, BoneRole.FootR, BoneRole.ToeR);\n        if (srcLeft?.Toe is not int srcToeL || srcRight?.Toe is not int srcToeR)\n            return; // toe-less sources take the solver\u0027s virtual-foot fallback instead\n\n        // ---- rest-stance plausibility (normalized rest, the solver\u0027s delta reference) ----\n        float pitchL, pitchR;\n        Vector3 srcUp;\n        try\n        {\n            var (srcNorm, _) = RestNormalizer.Normalize(scene.Skeleton, map);\n            var srcCanon = CanonicalFrames.Build(scene.Skeleton, map, srcNorm.WorldRest);\n            srcUp = Vector3.Normalize(srcCanon.CharacterUp);\n\n            float RestPitchDeg(int foot, int toe)\n            {\n                var dir = srcNorm.WorldRest[toe].Pos - srcNorm.WorldRest[foot].Pos;\n                if (dir.LengthSquared() \u003C 1e-8f)\n                    return 0f;\n                var s = Vector3.Dot(Vector3.Normalize(dir), srcUp);\n                return MathF.Asin(Math.Clamp(s, -1f, 1f)) * (180f / MathF.PI);\n            }\n\n            pitchL = RestPitchDeg(srcLeft.Ankle, srcToeL);\n            pitchR = RestPitchDeg(srcRight.Ankle, srcToeR);\n        }\n        catch (ArgumentException)\n        {\n            return;\n        }\n\n        var restIsStance = pitchL \u003C StancePitchMaxDeg \u0026\u0026 pitchR \u003C StancePitchMaxDeg\n            \u0026\u0026 MathF.Abs(pitchL - pitchR) \u003C= StancePitchAsymmetryDeg;\n        if (restIsStance)\n            return;\n\n        var srcFrames = scene.Clips[take].Frames;\n        var (plantsL, plantsR) = FootPlant.DetectPlantIntervals(\n            srcFrames, scene.Skeleton, srcLeft, srcRight, srcUp, fps);\n        if (plantsL.Count == 0 \u0026\u0026 plantsR.Count == 0)\n            return;\n\n        FootGroundAlign.Apply(\n            frames, targetSkeleton, targetFeet.Left, targetFeet.Right, targetUp,\n            plantsL, plantsR);\n    }\n\n    /// \u003Csummary\u003E\n    /// Restores the clip\u0027s SOURCE-authored foot-to-ground relationship with ONE constant\n    /// vertical offset per clip (southpaw final regeneration package: DEFERRED.md f2 and\n    /// gate4_review.md 3.1). The solver\u0027s vertical reference is the source REST pelvis;\n    /// mid-pose exports whose kept node rest erased the authored crouch leave every solved\n    /// frame hovering by exactly the erased crouch depth (measured: stance \u002B5.9 cm, steps\n    /// \u002B7.8 to \u002B10.3, slips ~\u002B9, while the source FBX is grounded everywhere). Fix, the\n    /// generalization of the BVH ClipPlacementOffset vertical logic to every source: measure\n    /// the clip\u0027s minimum foot support (ankles \u002B toes) in the SOLVED target frames and shift\n    /// the whole clip vertically so that support equals the TARGET rest support plus the\n    /// source clip\u0027s own authored support delta (source clip support minus source rest\n    /// support, hip-height scaled). One constant per clip preserves every within-clip lift,\n    /// heel raise and step cycle exactly: authored articulation is never flattened and an\n    /// authored jump stays airborne (its source support delta rides along).\n    /// \u003C/summary\u003E\n    private static void AlignSupportToGround(\n        List\u003CXForm[]\u003E frames, SourceScene scene, MappingResult map, TargetRig rig,\n        (FootChain Left, FootChain Right) feet, Vector3 up, MappingReportInfo report, int take)\n    {\n        if (frames.Count == 0)\n            return;\n        var skeleton = rig.Skeleton;\n        var rest = skeleton.RestWorld;\n        var srcClip = scene.Clips[take];\n        var src = scene.Skeleton;\n\n        // The GROUND normal is the rig-space vertical axis, not the character-lean up:\n        // the character frame\u0027s up tilts a few degrees with the rest posture, and a\n        // tilted dot-metric slants the ground line across a traveling clip (measured:\n        // 28 cm of false offset on a long corpus walk). Snap to the dominant axis.\n        up = GroundUp(up);\n\n        // ---- support-bone set: the roles mapped on BOTH rigs (metrics must compare\n        // the same anatomical points or anthropometric offsets leak into the gap) ----\n        var supportRoles = new List\u003CBoneRole\u003E();\n        foreach (var role in new[] { BoneRole.FootL, BoneRole.FootR, BoneRole.ToeL, BoneRole.ToeR })\n        {\n            if (map.RoleToBone.ContainsKey(role) \u0026\u0026 rig.BoneForRole(role) is not null)\n                supportRoles.Add(role);\n        }\n        var sourceMeasured = supportRoles.Contains(BoneRole.FootL) \u0026\u0026 supportRoles.Contains(BoneRole.FootR)\n            \u0026\u0026 srcClip.Frames.Count \u003E 0 \u0026\u0026 srcClip.Frames[0].Length == src.Count;\n        if (!sourceMeasured)\n        {\n            // No reliable common support metric: fall back to the ankles the target\n            // chains provide and a zero source gap (best guess: grounded).\n            supportRoles.Clear();\n        }\n\n        var tgtSupportBones = new List\u003Cint\u003E();\n        foreach (var role in supportRoles)\n            tgtSupportBones.Add(rig.BoneForRole(role)!.Value);\n        if (tgtSupportBones.Count == 0)\n        {\n            tgtSupportBones.Add(feet.Left.Ankle);\n            tgtSupportBones.Add(feet.Right.Ankle);\n        }\n\n        var tgtRestSupport = float.MaxValue;\n        foreach (var b in tgtSupportBones)\n            tgtRestSupport = MathF.Min(tgtRestSupport, Vector3.Dot(rest[b].Pos, up));\n\n        var solvedSupport = float.MaxValue;\n        foreach (var frame in frames)\n        {\n            var world = new Skeleton.Pose(frame).ToWorld(skeleton);\n            foreach (var b in tgtSupportBones)\n                solvedSupport = MathF.Min(solvedSupport, Vector3.Dot(world[b].Pos, up));\n        }\n\n        // ---- source-authored support gap --------------------------------------\n        float sourceRel = 0f;\n        if (sourceMeasured)\n        {\n            var srcSupportBones = new List\u003Cint\u003E();\n            foreach (var role in supportRoles)\n                srcSupportBones.Add(map.RoleToBone[role]);\n\n            var srcUp = scene.UpAxis switch\n            {\n                0 =\u003E new Vector3(scene.UpAxisSign, 0f, 0f),\n                2 =\u003E new Vector3(0f, 0f, scene.UpAxisSign),\n                _ =\u003E new Vector3(0f, scene.UpAxisSign, 0f),\n            };\n            var srcHips = map.RoleToBone.TryGetValue(BoneRole.Hips, out var sh) ? sh : -1;\n\n            var srcRestSupport = float.MaxValue;\n            var srcRestGround = float.MaxValue;\n            for (var b = 0; b \u003C src.Count; b\u002B\u002B)\n            {\n                var h = Vector3.Dot(src.RestWorld[b].Pos, srcUp);\n                srcRestGround = MathF.Min(srcRestGround, h);\n            }\n            foreach (var b in srcSupportBones)\n                srcRestSupport = MathF.Min(srcRestSupport, Vector3.Dot(src.RestWorld[b].Pos, srcUp));\n\n            var srcClipSupport = float.MaxValue;\n            var srcMotionGround = float.MaxValue;\n            foreach (var frame in srcClip.Frames)\n            {\n                var world = new Skeleton.Pose(frame).ToWorld(src);\n                foreach (var b in srcSupportBones)\n                    srcClipSupport = MathF.Min(srcClipSupport, Vector3.Dot(world[b].Pos, srcUp));\n                if (!scene.RestPlacementAuthored)\n                {\n                    for (var b = 0; b \u003C src.Count; b\u002B\u002B)\n                        srcMotionGround = MathF.Min(srcMotionGround, Vector3.Dot(world[b].Pos, srcUp));\n                }\n            }\n\n            // AUTHORED placements (FBX): the rest stands on the authored ground, so the\n            // gap is simply clip support minus rest support (same bones, same space).\n            // UN-PLACED sources (BVH capture volumes): absolute placement is meaningless,\n            // so both terms go placement-free: the clip\u0027s support above its OWN motion\n            // ground (lowest joint anywhere, incl. static origin markers) compared to the\n            // rest pose\u0027s support above ITS lowest joint. A grounded walk reads ~0, a\n            // jump reads its true airborne height, a crawl reads its raised feet.\n            float gap;\n            if (scene.RestPlacementAuthored)\n                gap = srcClipSupport - srcRestSupport;\n            else\n                gap = (srcClipSupport - srcMotionGround) - (srcRestSupport - srcRestGround);\n\n            // Hip-height ratio scales the (small) source gap into target units,\n            // clamped against degenerate rest measurements.\n            var ratio = 1f;\n            if (srcHips \u003E= 0 \u0026\u0026 rig.BoneForRole(BoneRole.Hips) is { } tgtHips)\n            {\n                var srcHipHeight = Vector3.Dot(src.RestWorld[srcHips].Pos, srcUp) - srcRestSupport;\n                var tgtHipHeight = Vector3.Dot(rest[tgtHips].Pos, up) - tgtRestSupport;\n                if (srcHipHeight \u003E 1e-3f \u0026\u0026 float.IsFinite(tgtHipHeight / srcHipHeight))\n                    ratio = Math.Clamp(tgtHipHeight / srcHipHeight, 0.25f, 4f);\n            }\n            sourceRel = gap * ratio;\n        }\n\n        var delta = tgtRestSupport \u002B sourceRel - solvedSupport;\n        if (!float.IsFinite(delta) || MathF.Abs(delta) \u003E 100f)\n        {\n            AddNote(report, $\u0022Support ground alignment skipped: implausible offset {delta:0.0}.\u0022);\n            return;\n        }\n        if (MathF.Abs(delta) \u003C 0.01f)\n            return; // already aligned\n\n        var shift = up * delta;\n        foreach (var frame in frames)\n        {\n            for (var i = 0; i \u003C skeleton.Count; i\u002B\u002B)\n            {\n                if (skeleton[i].ParentIndex \u003C 0)\n                    frame[i] = new XForm(frame[i].Pos \u002B shift, frame[i].Rot);\n            }\n        }\n        AddNote(report, sourceMeasured\n            ? $\u0022Support ground alignment: {delta:0.00} vertical offset applied \u0022\n              \u002B $\u0022(source-authored support delta {sourceRel:0.00}).\u0022\n            : $\u0022Support ground alignment: {delta:0.00} vertical offset applied \u0022\n              \u002B \u0022(source feet unmapped; clip support aligned to target rest support).\u0022);\n    }\n\n    private static Vector3 GroundUp(Vector3 up)\n    {\n        var absolute = Vector3.Abs(up);\n        return absolute.X \u003E= absolute.Y \u0026\u0026 absolute.X \u003E= absolute.Z\n            ? new Vector3(MathF.Sign(up.X), 0, 0)\n            : absolute.Y \u003E= absolute.Z\n                ? new Vector3(0, MathF.Sign(up.Y), 0)\n                : new Vector3(0, 0, MathF.Sign(up.Z));\n    }\n\n    private static void ApplyRootMotion(\n        RootMotionMode mode, List\u003CXForm[]\u003E frames, TargetContext context, MappingReportInfo report)\n    {\n        if (mode == RootMotionMode.Off)\n            return;\n\n        if (context.HipsIndex is not { } hips)\n        {\n            AddNote(report, $\u0022Root motion ({mode}) skipped: target rig maps no Hips role.\u0022);\n            return;\n        }\n        if (context.Up is not { } up)\n        {\n            AddNote(report, $\u0022Root motion ({mode}) skipped: {context.UpOrChainProblem}\u0022);\n            return;\n        }\n\n        if (mode == RootMotionMode.Extract \u0026\u0026 context.DedicatedRootIndex is null)\n        {\n            // s\u0026box-style target: pelvis is parentless and there is no separate translating\n            // root bone (root_IK is IkBaked). Bone-level extraction is impossible \u2014 the vmdl\n            // AnimFile entry carries an ExtractMotion node instead (compile-time extraction).\n            AddNote(report,\n                \u0022Root-motion extract: target has no dedicated animated root bone distinct from \u0022\n                \u002B \u0022the hips; frames left as solved and motion extraction delegated to the vmdl \u0022\n                \u002B \u0022AnimFile ExtractMotion node.\u0022);\n            return;\n        }\n\n        var root = context.DedicatedRootIndex ?? hips;\n        var worldUp = GroundUp(up);\n        // Skeleton-aware overload: hips world via real parent-chain FK, locals re-derived\n        // against the actual parent (HipsParentIsRoot is ignored by this overload).\n        RootMotion.Apply(frames, context.Rig.Skeleton, new RootMotionAxes\n        {\n            // Match the world vertical used by support-height cleanup. A slightly\n            // leaning target torso must not tilt the plane used to remove travel;\n            // otherwise this final pass reintroduces vertical drift into grounded feet.\n            Up = worldUp,\n            RootIndex = root,\n            HipsIndex = hips,\n            HipsParentIsRoot = context.HipsParentIsRoot,\n        }, mode);\n        if (mode == RootMotionMode.InPlace \u0026\u0026 frames.Count \u003E 0)\n        {\n            // Animation-only files may start far from their static reference pose.\n            // Removing travel alone freezes that offset into the clip, so blending\n            // directions moves the mesh away from its controller. Center every clip\n            // on the target bind hips, preserving vertical motion and local rotations.\n            var skeleton = context.Rig.Skeleton;\n            var center = Vector3.Zero;\n            foreach (var frame in frames)\n                center \u002B= FkUtil.BoneWorld(frame, skeleton, hips).Pos;\n            var offset = skeleton.RestWorld[hips].Pos - center / frames.Count;\n            offset -= Vector3.Dot(offset, worldUp) * worldUp;\n            foreach (var frame in frames)\n                for (var b = 0; b \u003C skeleton.Count; b\u002B\u002B)\n                    if (skeleton[b].ParentIndex \u003C 0)\n                        frame[b] = new XForm(frame[b].Pos \u002B offset, frame[b].Rot);\n        }\n        AddNote(report, mode == RootMotionMode.Extract\n            ? $\u0022Root motion extracted onto dedicated root bone (index {root}).\u0022\n            : \u0022Root motion removed (in-place clip).\u0022);\n    }\n\n    private static void AddNote(MappingReportInfo report, string note)\n    {\n        if (!report.Notes.Contains(note))\n            report.Notes.Add(note);\n    }\n\n    /// \u003Csummary\u003E\n    /// Mid-pose FBX sources: adopts the importer\u0027s bind-rest alternate skeleton when it\n    /// makes the character stand STRAIGHTER along the file\u0027s own up axis. Solving on a\n    /// posed rest breaks the solver\u0027s anatomical reasoning on exactly the posed limbs\n    /// (measured 48\u00B0 mean world-rot off ground truth on a real rig, left foot 124\u00B0); but\n    /// a bind rest can also tilt the character-up estimate (shoulders behind hips on one\n    /// real rig tilted it 7\u00B0, starving plant/stance detection), so the straighter rest\n    /// wins. Clips are authored playback either way \u2014 same bones, same order.\n    /// \u003C/summary\u003E\n    private static SourceScene MaybeAdoptBindRest(\n        SourceScene scene, MappingResult map, MappingReportInfo report)\n    {\n        if (scene.MidPoseBindSkeleton is not { } bindSkeleton)\n            return scene;\n\n        var fileUp = scene.UpAxis switch\n        {\n            0 =\u003E new Vector3(scene.UpAxisSign, 0, 0),\n            2 =\u003E new Vector3(0, 0, scene.UpAxisSign),\n            _ =\u003E new Vector3(0, scene.UpAxisSign, 0),\n        };\n\n        float UpTiltDeg(SkeletonModel skeleton)\n        {\n            var (norm, _) = RestNormalizer.Normalize(skeleton, map);\n            var up = Vector3.Normalize(\n                CanonicalFrames.Build(skeleton, map, norm.WorldRest).CharacterUp);\n            return MathF.Acos(Math.Clamp(Vector3.Dot(up, fileUp), -1f, 1f)) * 180f / MathF.PI;\n        }\n\n        try\n        {\n            float tiltStatics = UpTiltDeg(scene.Skeleton);\n            float tiltBind = UpTiltDeg(bindSkeleton);\n            if (tiltBind \u003E tiltStatics \u002B 1f)\n            {\n                AddNote(report,\n                    $\u0022mid-pose export: kept the exported pose as rest - the file\u0027s bind \u0022\n                    \u002B $\u0022data stands {tiltBind:0.#} deg off the file up axis \u0022\n                    \u002B $\u0022(vs {tiltStatics:0.#} deg)\u0022);\n                return scene;\n            }\n\n            AddNote(report,\n                \u0022mid-pose export: rest pose restored from the file\u0027s own bind data \u0022\n                \u002B \u0022(clips keep their authored playback)\u0022);\n            return new SourceScene(\n                bindSkeleton, scene.Clips, scene.UnitScaleCm,\n                scene.UpAxis, scene.UpAxisSign,\n                scene.FrontAxis, scene.FrontAxisSign,\n                scene.CoordAxis, scene.CoordAxisSign,\n                scene.OriginalUpAxis, scene.Notes)\n            {\n                AuthoredMapping = scene.AuthoredMapping,\n                RestPlacementAuthored = scene.RestPlacementAuthored,\n            };\n        }\n        catch (Exception)\n        {\n            // Anatomy not measurable (mapping lacks the frame\u0027s roles, degenerate rest):\n            // keep today\u0027s behavior.\n            return scene;\n        }\n    }\n\n    // ================================================================ import \u002B mapping\n\n    /// \u003Csummary\u003E\n    /// Imports source-file bytes exactly like conversion does: the extension picks the\n    /// importer; unknown extensions fall back to content sniffing (FBX binary magic / ASCII\n    /// header token / GLB \u0027glTF\u0027 magic / glTF JSON). Public so UI listings\n    /// inspect files through the SAME import path the pipeline uses (no duplicate sniffing\n    /// logic caller-side).\n    /// \u003C/summary\u003E\n    /// \u003Cparam name=\u0022data\u0022\u003ERaw file bytes.\u003C/param\u003E\n    /// \u003Cparam name=\u0022fileName\u0022\u003EFile name; only the extension is consulted.\u003C/param\u003E\n    /// \u003Cparam name=\u0022sampleFps\u0022\u003EResample rate for the imported clips; null = importer default\n    /// (30 fps).\u003C/param\u003E\n    /// \u003Cexception cref=\u0022FormatException\u0022\u003EThrown when the bytes are not a readable\n    /// motion, FBX or glTF animation.\u003C/exception\u003E\n    public static SourceScene ImportSource(\n        byte[] data, string fileName, float? sampleFps = null,\n        Func\u003Cstring, byte[]\u003E? externalBufferResolver = null)\n    {\n        ArgumentNullException.ThrowIfNull(data);\n        ArgumentNullException.ThrowIfNull(fileName);\n\n        var fbxOptions = sampleFps is { } fbxFps ? new FbxImportOptions { SampleFps = fbxFps } : null;\n        var gltfOptions = sampleFps is not null || externalBufferResolver is not null\n            ? new GltfImportOptions\n            {\n                SampleFps = sampleFps ?? 30f,\n                ExternalBufferResolver = externalBufferResolver,\n            }\n            : null;\n        var ext = ExtensionOf(fileName);\n        return ext switch\n        {\n            \u0022hmotion\u0022 =\u003E Motion.MotionDocument.Parse(data).ToSourceScene(sampleFps),\n            \u0022fbx\u0022 =\u003E FbxImporter.Import(data, fbxOptions),\n            // .vrm = glTF 2.0 GLB container \u002B VRM extension (the importer reads the authored\n            // humanoid bone map into SourceScene.AuthoredMapping); unknown-extension VRM\n            // bytes also land here via the GLB magic sniff below.\n            \u0022glb\u0022 or \u0022gltf\u0022 or \u0022vrm\u0022 =\u003E GltfImporter.Import(data, gltfOptions),\n            _ =\u003E SniffFormat(data) switch\n            {\n                \u0022fbx\u0022 =\u003E FbxImporter.Import(data, fbxOptions),\n                \u0022gltf\u0022 =\u003E GltfImporter.Import(data, gltfOptions),\n                _ =\u003E throw new FormatException(\n                    $\u0022Unrecognized source format for \u0027{fileName}\u0027 (expected .hmotion, .fbx, .glb, .gltf or .vrm).\u0022),\n            },\n        };\n    }\n\n    private static string? SniffFormat(byte[] data)\n    {\n        // Binary FBX magic: \u0022Kaydara FBX Binary  \\0\u0022.\n        const string fbxMagic = \u0022Kaydara FBX Binary\u0022;\n        if (StartsWithAscii(data, fbxMagic))\n            return \u0022fbx\u0022;\n\n        // GLB magic: \u0027glTF\u0027 (0x46546C67 little-endian).\n        if (StartsWithAscii(data, \u0022glTF\u0022))\n            return \u0022gltf\u0022;\n\n        var head = Encoding.UTF8.GetString(data, 0, Math.Min(data.Length, 4096));\n        if (head.Contains(\u0022FBXHeaderExtension\u0022, StringComparison.Ordinal))\n            return \u0022fbx\u0022; // ASCII FBX\n        var trimmed = head.TrimStart();\n        if (trimmed.StartsWith(\u0022{\u0022, StringComparison.Ordinal)\n            \u0026\u0026 head.Contains(\u0022\\\u0022asset\\\u0022\u0022, StringComparison.Ordinal))\n            return \u0022gltf\u0022; // plain-JSON glTF\n        return null;\n    }\n\n    private static bool StartsWithAscii(byte[] data, string prefix)\n    {\n        if (data.Length \u003C prefix.Length)\n            return false;\n        for (var i = 0; i \u003C prefix.Length; i\u002B\u002B)\n        {\n            if (data[i] != (byte)prefix[i])\n                return false;\n        }\n        return true;\n    }\n\n    /// \u003Csummary\u003E\n    /// THE mapping cascade, shared by conversion, UI file listings, and custom-target\n    /// detection: explicit override \u2192 authored mapping (from the file itself, e.g. a VRM\u0027s\n    /// humanoid bone map \u2014 authoritative ground truth at confidence 1.0) \u2192 user preset (via\n    /// \u003Cparamref name=\u0022userPresetLookup\u0022/\u003E, keyed by \u003Csee cref=\u0022Mapping.SkeletonSignature\u0022/\u003E)\n    /// \u2192 shipped preset detection \u2192 best-effort auto-map. The report\u0027s\n    /// \u003Csee cref=\u0022MappingReportInfo.NeedsUserDecision\u0022/\u003E is true only on the auto path below\n    /// the preset detection threshold \u2014 conversion still proceeds with that map; callers\n    /// decide whether to ask/reject.\n    /// \u003C/summary\u003E\n    /// \u003Cparam name=\u0022skeleton\u0022\u003ESource (or candidate target) skeleton.\u003C/param\u003E\n    /// \u003Cparam name=\u0022mappingOverride\u0022\u003EExplicit mapping (manual table / already-resolved user\n    /// preset); wins outright when non-null \u2014 a deliberate user decision beats even the\n    /// file\u0027s own bone map.\u003C/param\u003E\n    /// \u003Cparam name=\u0022userPresetLookup\u0022\u003EEditor-side user-preset hook: receives the skeleton\u0027s\n    /// signature, returns the stored mapping or null. The facade itself can do no file IO.\u003C/param\u003E\n    /// \u003Cparam name=\u0022authoredMapping\u0022\u003EA mapping authored INSIDE the source file\n    /// (\u003Csee cref=\u0022SourceScene.AuthoredMapping\u0022/\u003E, \u003Csee cref=\u0022MappingSource.Authored\u0022/\u003E);\n    /// consulted before user presets because the file itself is authoritative.\u003C/param\u003E\n    public static (MappingResult Map, MappingReportInfo Report) ResolveMapping(\n        SkeletonModel skeleton, MappingResult? mappingOverride = null,\n        Func\u003Cstring, MappingResult?\u003E? userPresetLookup = null,\n        MappingResult? authoredMapping = null)\n    {\n        ArgumentNullException.ThrowIfNull(skeleton);\n\n        if (mappingOverride is not null)\n            return (mappingOverride, BuildReport(mappingOverride, needsUserDecision: false, skeleton));\n\n        if (authoredMapping is not null)\n            return (authoredMapping, BuildReport(authoredMapping, needsUserDecision: false, skeleton));\n\n        if (userPresetLookup is not null\n            \u0026\u0026 userPresetLookup(Mapping.SkeletonSignature.Compute(skeleton)) is { } userPreset)\n            return (userPreset, BuildReport(userPreset, needsUserDecision: false, skeleton));\n\n        if (ProfileDetector.Detect(skeleton) is { } detected)\n        {\n            AutoMapper.CompleteSingleJointThumbs(skeleton, detected.Result);\n            AutoMapper.CompleteFingersByTopology(skeleton, detected.Result);\n            AutoMapper.PruneNonArticulatedFingerStubs(skeleton, detected.Result);\n            VetoImpossibleHead(skeleton, detected.Result);\n            return (detected.Result, BuildReport(detected.Result, needsUserDecision: false, skeleton));\n        }\n\n        var auto = AutoMapper.Map(skeleton);\n        VetoImpossibleHead(skeleton, auto);\n        var needsUserDecision = auto.Confidence \u003C ProfileDetector.DetectionThreshold;\n        return (auto, BuildReport(auto, needsUserDecision, skeleton));\n    }\n\n    /// \u003Csummary\u003E\n    /// Drops a detected/auto-mapped Head whose bone cannot anatomically drive a skull: its\n    /// rest sits clearly BELOW the neck (or the topmost mapped spine joint). Real case: an\n    /// Auto-Rig Pro export parks \u003Cc\u003Ehead.x\u003C/c\u003E at chest height ~90cm under \u003Cc\u003Eneck.x\u003C/c\u003E\n    /// with the skin bind compensating \u2014 the mesh is correct at rest, but every skull\n    /// rotation replayed onto that bone sweeps the head geometry on the lever arm (\u0022the\n    /// head is stretched and it stretched more when I played the animation\u0022). With the\n    /// role unmapped the neck \u2014 whose pivot IS at the skull base on such rigs \u2014 carries\n    /// head motion, and the bone holds its rest like any other unmapped helper.\n    /// Neutral-rest corpus rigs measure the neck\u2192head segment \u22128\u00B0\u202633\u00B0 from character up\n    /// (dot \u2265 0.55 even on the posed Defenses bind at 40.7\u00B0); the veto fires only past\n    /// 101\u00B0 (dot \u0026lt; \u22120.2), an impossible carriage on any working rig. Explicit,\n    /// authored and user-preset mappings are authoritative and never second-guessed.\n    /// \u003C/summary\u003E\n    private static void VetoImpossibleHead(SkeletonModel skeleton, MappingResult map)\n    {\n        if (!map.RoleToBone.TryGetValue(BoneRole.Head, out var head)\n            || !map.RoleToBone.TryGetValue(BoneRole.Hips, out var hips))\n            return;\n\n        var reference = map.RoleToBone.TryGetValue(BoneRole.Neck, out var neck)\n            ? neck\n            : SpineTop(map);\n        if (reference is not { } refBone || refBone == hips)\n            return;\n\n        var rest = skeleton.RestWorld;\n        // Axis-free \u0022up\u0022: the body chain ascends hips \u2192 spine \u2192 neck by construction, so\n        // hips\u2192reference is the rig\u0027s own vertical regardless of world axis convention.\n        var up = rest[refBone].Pos - rest[hips].Pos;\n        var seg = rest[head].Pos - rest[refBone].Pos;\n        if (up.LengthSquared() \u003C 1e-6f || seg.Length() \u003C 0.05f * up.Length())\n            return; // degenerate spine / head stacked on the neck: nothing to judge\n\n        if (Vector3.Dot(Vector3.Normalize(seg), Vector3.Normalize(up)) \u003E= -0.2f)\n            return;\n\n        map.RoleToBone.Remove(BoneRole.Head);\n        // The neck of a broken skull region rests with the head. On the real case the\n        // neck bone skins the skull AND a torso column (its weights are where the head\u0027s\n        // should be), so any solved neck bend shears half the body: the source spreads\n        // its idle hunch through its spine while this target\u0027s spine stays put, and the\n        // faithful neck world replay turned into a ~19\u00B0 LOCAL kink rendered as a hump\n        // grafted onto the character\u0027s back. Skull attitude rides the spine instead.\n        var neckNote = \u0022\u0022;\n        if (map.RoleToBone.Remove(BoneRole.Neck))\n            neckNote = $\u0022 Its neck \u0027{skeleton[neck].Name}\u0027 rests too (on such exports it \u0022\n                \u002B \u0022carries the skull/torso skin the head joint should).\u0022;\n        map.Notes.Add(\n            $\u0022Head \u0027{skeleton[head].Name}\u0027 unmapped: its rest sits below \u0022\n            \u002B $\u0022\u0027{skeleton[refBone].Name}\u0027 - not a skull joint the solver can drive \u0022\n            \u002B \u0022(rotations would sweep the head geometry on the offset lever arm).\u0022\n            \u002B neckNote \u002B \u0022 The spine carries the upper body; map manually to override.\u0022);\n    }\n\n    private static int? SpineTop(MappingResult map)\n    {\n        foreach (var role in new[]\n        {\n            BoneRole.Spine4, BoneRole.Spine3, BoneRole.Spine2, BoneRole.Spine1, BoneRole.Spine0,\n        })\n        {\n            if (map.RoleToBone.TryGetValue(role, out var bone))\n                return bone;\n        }\n        return null;\n    }\n\n    private static MappingReportInfo BuildReport(\n        MappingResult map, bool needsUserDecision, SkeletonModel skeleton)\n    {\n        var report = new MappingReportInfo\n        {\n            ProfileName = map.ProfileName,\n            Source = map.Source,\n            Confidence = map.Confidence,\n            NeedsUserDecision = needsUserDecision,\n            MappedRoleCount = map.RoleToBone.Count,\n            SkeletonSignature = Mapping.SkeletonSignature.Compute(skeleton),\n        };\n        report.Notes.AddRange(map.Notes);\n        if (needsUserDecision)\n            report.Notes.Add(\n                $\u0022No preset profile matched and auto-map confidence {map.Confidence:0.00} is below \u0022\n                \u002B $\u0022{ProfileDetector.DetectionThreshold:0.00}; proceeding with the best-effort auto map.\u0022);\n        return report;\n    }\n\n    // ================================================================ naming\n\n    private static string RequestedClipName(RetargetRequest request, SourceScene scene, int take)\n    {\n        var multipleTakes = scene.Clips.Count \u003E 1;\n        if (!string.IsNullOrWhiteSpace(request.ClipNameOverride))\n            return multipleTakes ? $\u0022{request.ClipNameOverride}_{take \u002B 1}\u0022 : request.ClipNameOverride!;\n\n        var takeName = scene.Clips[take].Name;\n        if (!string.IsNullOrWhiteSpace(takeName) \u0026\u0026 takeName != \u0022motion\u0022\n            \u0026\u0026 !takeName.Equals(\u0022mixamo.com\u0022, StringComparison.OrdinalIgnoreCase)\n            \u0026\u0026 !IsExporterPlaceholderTake(takeName))\n            return takeName;\n\n        // BVH files (clip always named \u0022motion\u0022), Mixamo takes (always named\n        // \u0022mixamo.com\u0022), Unreal exports (every stack named \u0022Unreal Take\u0022) and\n        // unnamed takes use the file stem.\n        var stem = FileStem(request.SourceFileName);\n        return multipleTakes ? $\u0022{stem}_{take \u002B 1}\u0022 : stem;\n    }\n\n    /// \u003Csummary\u003E\n    /// True for take names that identify the EXPORTER rather than the animation. Unreal\u0027s\n    /// FBX exporter stamps \u003Cc\u003EUnreal Take\u003C/c\u003E into every AnimStack it writes (numbered \u2014\n    /// \u003Cc\u003EUnreal Take 001\u003C/c\u003E \u2014 when a sequence exports several), so a folder of UE clips\n    /// arrives with one identical take name on every file. Treated as authored, that name\n    /// beats the file stem in \u003Csee cref=\u0022RequestedClipName\u0022/\u003E and the whole batch collapses\n    /// onto one clip name, which \u003Csee cref=\u0022UniqueClipName\u0022/\u003E then has to pull apart into\n    /// \u003Cc\u003EUnreal_Take\u003C/c\u003E, \u003Cc\u003EUnreal_Take_2\u003C/c\u003E, \u003Cc\u003EUnreal_Take_3\u003C/c\u003E\u2026 \u2014 every file\u0027s real\n    /// name lost, and the resulting sequence names carry no meaning in the vmdl. Falling\n    /// through to the file stem restores the same per-file naming BVH and Mixamo sources\n    /// already get. Matched as a PREFIX, and against the underscored spelling too, so the\n    /// numbered variants and any already-sanitized re-import are covered.\n    /// \u003C/summary\u003E\n    private static bool IsExporterPlaceholderTake(string takeName)\n    {\n        var trimmed = takeName.Trim();\n        return trimmed.StartsWith(\u0022unreal take\u0022, StringComparison.OrdinalIgnoreCase)\n            || trimmed.StartsWith(\u0022unreal_take\u0022, StringComparison.OrdinalIgnoreCase);\n    }\n\n    /// \u003Csummary\u003ECollision auto-suffixing across the batch: \u003Cc\u003Ename\u003C/c\u003E, \u003Cc\u003Ename_2\u003C/c\u003E, \u2026\n    /// (case-insensitive \u2014 the names also become DMX file names).\u003C/summary\u003E\n    private static string UniqueClipName(string name, HashSet\u003Cstring\u003E usedNames, bool autoSuffix)\n    {\n        if (usedNames.Add(name) || !autoSuffix)\n            return name;\n        for (var i = 2; ; i\u002B\u002B)\n        {\n            var candidate = $\u0022{name}_{i}\u0022;\n            if (usedNames.Add(candidate))\n                return candidate;\n        }\n    }\n\n    /// \u003Csummary\u003E\n    /// Clip names become ModelDoc AnimFile node names and Source 2 sequence names, which\n    /// must stay within \u003Cc\u003E[A-Za-z0-9_]\u003C/c\u003E \u2014 a take name like \u003Cc\u003Emixamo.com\u003C/c\u003E otherwise\n    /// fails the vmdl compile with \u0022Node \u0027mixamo.com\u0027 resolve failure\u0022. Runs of invalid\n    /// characters collapse to a single underscore; case is preserved. Public so UIs that\n    /// dry-run name-based detection (e.g. the locomotion-set scan over raw take names) see\n    /// the SAME spelling conversion will produce \u2014 a take named \u003Cc\u003EWalk N\u003C/c\u003E becomes the\n    /// clip \u003Cc\u003EWalk_N\u003C/c\u003E.\n    /// \u003C/summary\u003E\n    public static string SanitizeClipName(string name)\n    {\n        var builder = new StringBuilder(name.Length);\n        var lastWasUnderscore = false;\n        foreach (var c in name)\n        {\n            if (c is (\u003E= \u0027a\u0027 and \u003C= \u0027z\u0027) or (\u003E= \u0027A\u0027 and \u003C= \u0027Z\u0027) or (\u003E= \u00270\u0027 and \u003C= \u00279\u0027) or \u0027_\u0027)\n            {\n                builder.Append(c);\n                lastWasUnderscore = c == \u0027_\u0027;\n            }\n            else if (!lastWasUnderscore)\n            {\n                builder.Append(\u0027_\u0027);\n                lastWasUnderscore = true;\n            }\n        }\n        var sanitized = builder.ToString().Trim(\u0027_\u0027);\n        return sanitized.Length \u003E 0 ? sanitized : \u0022clip\u0022;\n    }\n\n    private static string FileStem(string fileName)\n    {\n        var start = Math.Max(fileName.LastIndexOf(\u0027/\u0027), fileName.LastIndexOf(\u0027\\\\\u0027)) \u002B 1;\n        var dot = fileName.LastIndexOf(\u0027.\u0027);\n        var end = dot \u003E start ? dot : fileName.Length;\n        var stem = fileName.Substring(start, end - start);\n        return stem.Length \u003E 0 ? stem : \u0022clip\u0022;\n    }\n\n    private static string ExtensionOf(string fileName)\n    {\n        var dot = fileName.LastIndexOf(\u0027.\u0027);\n        if (dot \u003C 0 || dot == fileName.Length - 1)\n            return \u0022\u0022;\n        var ext = fileName.Substring(dot \u002B 1);\n        return ext.IndexOfAny(new[] { \u0027/\u0027, \u0027\\\\\u0027 }) \u003E= 0 ? \u0022\u0022 : ext.ToLowerInvariant();\n    }\n\n    private static string SanitizeFileName(string name)\n    {\n        var builder = new StringBuilder(name.Length);\n        foreach (var c in name)\n        {\n            builder.Append(\n                c is (\u003E= \u0027a\u0027 and \u003C= \u0027z\u0027) or (\u003E= \u00270\u0027 and \u003C= \u00279\u0027) or \u0027_\u0027 or \u0027-\u0027 ? c\n                : c is \u003E= \u0027A\u0027 and \u003C= \u0027Z\u0027 ? char.ToLowerInvariant(c)\n                : \u0027_\u0027);\n        }\n        var sanitized = builder.ToString().Trim(\u0027_\u0027);\n        return sanitized.Length \u003E 0 ? sanitized : \u0022clip\u0022;\n    }\n\n    private static string JoinAssetPath(string folder, string file)\n    {\n        var f = folder.Replace(\u0027\\\\\u0027, \u0027/\u0027).TrimEnd(\u0027/\u0027);\n        return f.Length == 0 ? file : f \u002B \u0022/\u0022 \u002B file;\n    }\n\n    // ================================================================ target context\n\n    /// \u003Csummary\u003EEverything derived once per batch from the target rig: character up axis,\n    /// foot chains, hips/root indices, IK-bone presence.\u003C/summary\u003E\n    internal sealed class TargetContext\n    {\n        public TargetRig Rig { get; }\n\n        /// \u003Csummary\u003ETarget character up direction (midShoulders \u2212 midHips on the rest pose,\n        /// via \u003Csee cref=\u0022CharacterFrame\u0022/\u003E); null when the rig lacks the bones for it.\u003C/summary\u003E\n        public Vector3? Up { get; }\n\n        /// \u003Csummary\u003ETarget character frame (for the arm-IK basis change); null when not computable.\u003C/summary\u003E\n        public CharacterFrame? Frame { get; }\n\n        /// \u003Csummary\u003ELeft/right leg chains from the rig\u0027s UpperLeg/LowerLeg/Foot/Toe roles;\n        /// null when either leg is incompletely mapped.\u003C/summary\u003E\n        public (FootChain Left, FootChain Right)? FootChains { get; }\n\n        /// \u003Csummary\u003EWhy \u003Csee cref=\u0022Up\u0022/\u003E / \u003Csee cref=\u0022FootChains\u0022/\u003E are unavailable (report note text).\u003C/summary\u003E\n        public string UpOrChainProblem { get; } = \u0022\u0022;\n\n        /// \u003Csummary\u003ETarget bone carrying the Hips role.\u003C/summary\u003E\n        public int? HipsIndex { get; }\n\n        /// \u003Csummary\u003EDedicated translating root: a parentless Animated bone that is an\n        /// ancestor of (and distinct from) the hips. Null on the s\u0026amp;box rig (pelvis is\n        /// itself parentless; root_IK is IkBaked).\u003C/summary\u003E\n        public int? DedicatedRootIndex { get; }\n\n        /// \u003Csummary\u003ETrue when the hips bone\u0027s direct parent is the dedicated root.\u003C/summary\u003E\n        public bool HipsParentIsRoot { get; }\n\n        public bool HasIkBakedBones { get; }\n\n        /// \u003Csummary\u003EConstraintDriven bone indices (twist/helper) \u2014 excluded from DMX\n        /// channels per design \u00A73; null when the rig has none. Face bones\n        /// (\u003Csee cref=\u0022SboxBoneClassifier.IsFaceBone\u0022/\u003E) are NOT in this set even though\n        /// their class is ConstraintDriven: they keep rest-local channels, because no\n        /// constraint re-drives them in a compiled sequence (channel-less face joints\n        /// bake statically \u2014 eyes detach from the moving head in ModelDoc).\u003C/summary\u003E\n        public IReadOnlySet\u003Cint\u003E? ConstraintDrivenBones { get; }\n\n        public TargetContext(TargetRig rig)\n        {\n            Rig = rig;\n            HipsIndex = rig.BoneForRole(BoneRole.Hips);\n            DedicatedRootIndex = FindDedicatedRoot(rig, HipsIndex);\n            HipsParentIsRoot = HipsIndex is { } hips \u0026\u0026 DedicatedRootIndex is { } root\n                \u0026\u0026 rig.Skeleton[hips].ParentIndex == root;\n            foreach (var _ in rig.BonesOfClass(BoneClass.IkBaked))\n            {\n                HasIkBakedBones = true;\n                break;\n            }\n\n            var constraintDriven = new HashSet\u003Cint\u003E(rig.BonesOfClass(BoneClass.ConstraintDriven));\n            // Face bones (eye_/ear_/face_) are ConstraintDriven by class but, unlike the\n            // twist/helper bones, nothing re-drives them when a compiled sequence plays:\n            // the model\u0027s AnimConstraintList never references them and the engine\u0027s eye\n            // look-at / blinking only runs in game. They must KEEP their rest-local DMX\n            // channels (the shipped fbx2dmx clips carry them too) or ModelDoc bakes the\n            // channel-less joints statically and the eyes detach from the moving head\n            // (see SboxBoneClassifier.IsFaceBone).\n            constraintDriven.RemoveWhere(i =\u003E SboxBoneClassifier.IsFaceBone(rig.Skeleton[i].Name));\n            ConstraintDrivenBones = constraintDriven.Count \u003E 0 ? constraintDriven : null;\n\n            try\n            {\n                Frame = CharacterFrame.Compute(rig.Skeleton, rig.ToMappingResult(), rig.Skeleton.RestWorld);\n                Up = Frame.Up;\n            }\n            catch (ArgumentException e)\n            {\n                UpOrChainProblem = $\u0022target character frame not computable ({e.Message})\u0022;\n                return;\n            }\n\n            var left = LegChain(rig, BoneRole.UpperLegL, BoneRole.LowerLegL, BoneRole.FootL, BoneRole.ToeL);\n            var right = LegChain(rig, BoneRole.UpperLegR, BoneRole.LowerLegR, BoneRole.FootR, BoneRole.ToeR);\n            if (left is not null \u0026\u0026 right is not null)\n                FootChains = (left, right);\n            else\n                UpOrChainProblem = \u0022target rig does not map a complete UpperLeg/LowerLeg/Foot chain on both sides\u0022;\n        }\n\n        private static FootChain? LegChain(TargetRig rig, BoneRole upper, BoneRole lower, BoneRole foot, BoneRole toe)\n            =\u003E rig.BoneForRole(upper) is { } hip\n               \u0026\u0026 rig.BoneForRole(lower) is { } knee\n               \u0026\u0026 rig.BoneForRole(foot) is { } ankle\n                ? new FootChain { Hip = hip, Knee = knee, Ankle = ankle, Toe = rig.BoneForRole(toe) }\n                : null;\n\n        private static int? FindDedicatedRoot(TargetRig rig, int? hipsIndex)\n        {\n            if (hipsIndex is not { } hips)\n                return null;\n            // Walk up from the hips; the topmost ancestor qualifies when it is a parentless\n            // Animated bone distinct from the hips itself.\n            var top = hips;\n            while (rig.Skeleton[top].ParentIndex \u003E= 0)\n                top = rig.Skeleton[top].ParentIndex;\n            return top != hips \u0026\u0026 rig.ClassOf(top) == BoneClass.Animated ? top : null;\n        }\n    }\n\n    // ================================================================ arm effector IK\n\n    /// \u003Csummary\u003E\n    /// Optional wrist-reach cleanup: per frame, the source hand offset from its shoulder is\n    /// limb-length-normalized, re-expressed in the target\u0027s character basis, and used as a\n    /// two-bone IK goal for the target arm (\u003Csee cref=\u0022EffectorIk.ApplyGoals\u0022/\u003E).\n    /// \u003C/summary\u003E\n    private static class ArmIkCleanup\n    {\n        /// \u003Csummary\u003ERuns both arms; returns a problem note (and does nothing) when the\n        /// prerequisites are missing, null on success.\u003C/summary\u003E\n        public static string? Apply(\n            List\u003CXForm[]\u003E frames, SourceScene scene, MappingResult map,\n            TargetRig rig, TargetContext context, int take)\n        {\n            if (context.Frame is not { } targetFrame)\n                return context.UpOrChainProblem;\n\n            CharacterFrame sourceFrame;\n            try\n            {\n                sourceFrame = CharacterFrame.Compute(scene.Skeleton, map, scene.Skeleton.RestWorld);\n            }\n            catch (ArgumentException e)\n            {\n                return $\u0022source character frame not computable ({e.Message})\u0022;\n            }\n\n            // Change of basis source space \u2192 target space (this library\u0027s convention:\n            // a * b applies b first).\n            var sourceToTarget = MathQ.Normalize(\n                BasisRotation(targetFrame) * Quaternion.Conjugate(BasisRotation(sourceFrame)));\n\n            var appliedAny = false;\n            appliedAny |= ApplyArm(frames, scene, map, rig, sourceToTarget, take,\n                BoneRole.UpperArmL, BoneRole.LowerArmL, BoneRole.HandL);\n            appliedAny |= ApplyArm(frames, scene, map, rig, sourceToTarget, take,\n                BoneRole.UpperArmR, BoneRole.LowerArmR, BoneRole.HandR);\n            return appliedAny ? null : \u0022no complete UpperArm/LowerArm/Hand chain mapped on source and target\u0022;\n        }\n\n        private static bool ApplyArm(\n            List\u003CXForm[]\u003E frames, SourceScene scene, MappingResult map, TargetRig rig,\n            Quaternion sourceToTarget, int take, BoneRole upperRole, BoneRole lowerRole, BoneRole handRole)\n        {\n            if (!map.RoleToBone.TryGetValue(upperRole, out var srcUpper)\n                || !map.RoleToBone.TryGetValue(lowerRole, out var srcLower)\n                || !map.RoleToBone.TryGetValue(handRole, out var srcHand))\n                return false;\n            if (rig.BoneForRole(upperRole) is not { } tgtUpper\n                || rig.BoneForRole(lowerRole) is not { } tgtLower\n                || rig.BoneForRole(handRole) is not { } tgtHand)\n                return false;\n\n            var src = scene.Skeleton;\n            var tgt = rig.Skeleton;\n            var srcLen = Vector3.Distance(src.RestWorld[srcUpper].Pos, src.RestWorld[srcLower].Pos)\n                       \u002B Vector3.Distance(src.RestWorld[srcLower].Pos, src.RestWorld[srcHand].Pos);\n            var tgtLen = Vector3.Distance(tgt.RestWorld[tgtUpper].Pos, tgt.RestWorld[tgtLower].Pos)\n                       \u002B Vector3.Distance(tgt.RestWorld[tgtLower].Pos, tgt.RestWorld[tgtHand].Pos);\n            if (srcLen \u003C 1e-4f || tgtLen \u003C 1e-4f)\n                return false;\n            var scale = tgtLen / srcLen;\n\n            var sourceFrames = scene.Clips[take].Frames;\n            var count = Math.Min(frames.Count, sourceFrames.Count);\n            var goals = new Vector3[frames.Count];\n            for (var f = 0; f \u003C frames.Count; f\u002B\u002B)\n            {\n                var srcWorld = new Pose(sourceFrames[Math.Min(f, count - 1)]).ToWorld(src);\n                var tgtWorld = new Pose(frames[f]).ToWorld(tgt);\n                var reach = srcWorld[srcHand].Pos - srcWorld[srcUpper].Pos;\n                goals[f] = tgtWorld[tgtUpper].Pos \u002B Vector3.Transform(reach, sourceToTarget) * scale;\n            }\n\n            EffectorIk.ApplyGoals(\n                frames, tgt,\n                new LimbChain { Upper = tgtUpper, Lower = tgtLower, End = tgtHand },\n                goals, RestBendAxis(tgt, tgtUpper, tgtLower, tgtHand));\n            return true;\n        }\n\n        /// \u003Csummary\u003EHinge-axis fallback from the rest bend plane (elbow), like the foot pass.\u003C/summary\u003E\n        internal static Vector3 RestBendAxis(SkeletonModel skeleton, int upper, int lower, int end)\n        {\n            var a = skeleton.RestWorld[upper].Pos;\n            var b = skeleton.RestWorld[lower].Pos;\n            var c = skeleton.RestWorld[end].Pos;\n            var axis = Vector3.Cross(c - a, b - a);\n            if (axis.LengthSquared() \u003E 1e-6f)\n                return Vector3.Normalize(axis);\n            var limb = c - a;\n            axis = Vector3.Cross(limb, Vector3.UnitY);\n            if (axis.LengthSquared() \u003C 1e-6f)\n                axis = Vector3.Cross(limb, Vector3.UnitZ);\n            return axis.LengthSquared() \u003E 1e-12f ? Vector3.Normalize(axis) : Vector3.UnitX;\n        }\n\n        /// \u003Csummary\u003ERotation taking canonical character axes (X=lateral, Y=up, Z=forward)\n        /// to the rig\u0027s world axes.\u003C/summary\u003E\n        private static Quaternion BasisRotation(CharacterFrame frame)\n        {\n            var m = new Matrix4x4(\n                frame.Lateral.X, frame.Lateral.Y, frame.Lateral.Z, 0f,\n                frame.Up.X, frame.Up.Y, frame.Up.Z, 0f,\n                frame.Forward.X, frame.Forward.Y, frame.Forward.Z, 0f,\n                0f, 0f, 0f, 1f);\n            return MathQ.Normalize(Quaternion.CreateFromRotationMatrix(m));\n        }\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Skeleton/Skeleton.cs","FileName":"Skeleton.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Collections.Generic;\nusing HumanoidMocapX.Core.Maths;\n\nnamespace HumanoidMocapX.Core.Skeleton;\n\n/// \u003Csummary\u003E\n/// Immutable bone hierarchy with rest pose. Bones are stored topologically sorted\n/// (every bone\u0027s parent precedes it), which lets forward kinematics run as a single\n/// in-order pass. Supports multiple roots (e.g. the s\u0026amp;box rig has both\n/// \u003Cc\u003Eroot_IK\u003C/c\u003E and \u003Cc\u003Epelvis\u003C/c\u003E as parentless bones).\n/// \u003C/summary\u003E\npublic sealed class Skeleton\n{\n    private readonly Bone[] _bones;\n    private readonly XForm[] _restWorld;\n    private readonly Dictionary\u003Cstring, int\u003E _indexByName;\n\n    private Skeleton(Bone[] bones, XForm[] restWorld, Dictionary\u003Cstring, int\u003E indexByName)\n    {\n        _bones = bones;\n        _restWorld = restWorld;\n        _indexByName = indexByName;\n    }\n\n    /// \u003Csummary\u003ENumber of bones.\u003C/summary\u003E\n    public int Count =\u003E _bones.Length;\n\n    /// \u003Csummary\u003EAll bones, topologically sorted (parents before children).\u003C/summary\u003E\n    public IReadOnlyList\u003CBone\u003E Bones =\u003E _bones;\n\n    /// \u003Csummary\u003ERest (bind) world transforms, indexed like \u003Csee cref=\u0022Bones\u0022/\u003E.\u003C/summary\u003E\n    public IReadOnlyList\u003CXForm\u003E RestWorld =\u003E _restWorld;\n\n    /// \u003Csummary\u003EBone name to index lookup.\u003C/summary\u003E\n    public IReadOnlyDictionary\u003Cstring, int\u003E IndexByName =\u003E _indexByName;\n\n    /// \u003Csummary\u003EThe bone at \u003Cparamref name=\u0022index\u0022/\u003E.\u003C/summary\u003E\n    public Bone this[int index] =\u003E _bones[index];\n\n    /// \u003Csummary\u003EReturns the index of the named bone, or -1 when absent.\u003C/summary\u003E\n    public int IndexOf(string name) =\u003E _indexByName.TryGetValue(name, out var index) ? index : -1;\n\n    /// \u003Csummary\u003E\n    /// Builds a skeleton from bone definitions in any order: validates names and parent links,\n    /// topologically sorts (stable \u2014 input order is preserved among bones whose parents are\n    /// already placed), and computes rest world transforms.\n    /// \u003C/summary\u003E\n    /// \u003Cexception cref=\u0022ArgumentException\u0022\u003E\n    /// Thrown on duplicate bone names, unknown parent names, or parent cycles.\n    /// \u003C/exception\u003E\n    public static Skeleton Create(IReadOnlyList\u003CBoneDefinition\u003E definitions)\n    {\n        ArgumentNullException.ThrowIfNull(definitions);\n\n        var count = definitions.Count;\n        var originalIndexByName = new Dictionary\u003Cstring, int\u003E(count, StringComparer.Ordinal);\n        for (var i = 0; i \u003C count; i\u002B\u002B)\n        {\n            var name = definitions[i].Name;\n            if (string.IsNullOrEmpty(name))\n                throw new ArgumentException($\u0022Bone at position {i} has an empty name.\u0022, nameof(definitions));\n            if (!originalIndexByName.TryAdd(name, i))\n                throw new ArgumentException($\u0022Duplicate bone name \u0027{name}\u0027.\u0022, nameof(definitions));\n        }\n\n        foreach (var def in definitions)\n        {\n            if (def.ParentName is not null \u0026\u0026 !originalIndexByName.ContainsKey(def.ParentName))\n                throw new ArgumentException(\n                    $\u0022Bone \u0027{def.Name}\u0027 references unknown parent \u0027{def.ParentName}\u0027.\u0022, nameof(definitions));\n            if (def.ParentName == def.Name)\n                throw new ArgumentException($\u0022Bone \u0027{def.Name}\u0027 is its own parent.\u0022, nameof(definitions));\n        }\n\n        // Stable topological sort: repeatedly place, in input order, every bone whose parent\n        // is already placed. O(n^2) worst case \u2014 fine for skeleton-sized inputs (~100 bones).\n        var newIndexByOriginal = new int[count];\n        Array.Fill(newIndexByOriginal, -1);\n        var order = new List\u003Cint\u003E(count);\n        while (order.Count \u003C count)\n        {\n            var progressed = false;\n            for (var i = 0; i \u003C count; i\u002B\u002B)\n            {\n                if (newIndexByOriginal[i] \u003E= 0)\n                    continue;\n                var parentName = definitions[i].ParentName;\n                if (parentName is not null \u0026\u0026 newIndexByOriginal[originalIndexByName[parentName]] \u003C 0)\n                    continue;\n                newIndexByOriginal[i] = order.Count;\n                order.Add(i);\n                progressed = true;\n            }\n            if (!progressed)\n                throw new ArgumentException(\u0022Bone hierarchy contains a parent cycle.\u0022, nameof(definitions));\n        }\n\n        var bones = new Bone[count];\n        var restWorld = new XForm[count];\n        var indexByName = new Dictionary\u003Cstring, int\u003E(count, StringComparer.Ordinal);\n        for (var newIndex = 0; newIndex \u003C count; newIndex\u002B\u002B)\n        {\n            var def = definitions[order[newIndex]];\n            var parentIndex = def.ParentName is null ? -1 : newIndexByOriginal[originalIndexByName[def.ParentName]];\n            bones[newIndex] = new Bone(newIndex, def.Name, parentIndex, def.RestLocal);\n            restWorld[newIndex] = parentIndex \u003C 0\n                ? def.RestLocal\n                : XForm.Compose(restWorld[parentIndex], def.RestLocal);\n            indexByName.Add(def.Name, newIndex);\n        }\n\n        return new Skeleton(bones, restWorld, indexByName);\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"HumanoidMocap/Core/Target/KvBool.cs","FileName":"KvBool.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Text;\n\nnamespace HumanoidMocapX.Core.Target;\n\n/// \u003Csummary\u003EA KV3 boolean.\u003C/summary\u003E\npublic sealed class KvBool : KvValue\n{\n    /// \u003Csummary\u003EThe boolean value.\u003C/summary\u003E\n    public bool Value { get; }\n\n    /// \u003Csummary\u003ECreates a boolean value.\u003C/summary\u003E\n    public KvBool(bool value) =\u003E Value = value;\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"dev/clip_checks.cs","FileName":"clip_checks.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System.Diagnostics;\nusing System.Text;\nusing System.Text.Json;\nusing HumanoidMocapX.Core;\nusing HumanoidMocapX.Core.Formats.Fbx;\nusing HumanoidMocapX.Core.Motion;\nusing HumanoidMocapX.Core.Target;\nusing HumanoidMocapX.EditorTools;\nusing HumanoidMocapX.Inference;\nusing Sandbox;\nusing static Sandbox.Internal.GlobalGameNamespace;\n\nnamespace HumanoidMocapX.Checks;\n\n/// \u003Csummary\u003ERuns the full model sequence on a 5\u201310-second predecoded video fixture.\n/// This developer check excludes production decoding and visual motion acceptance.\u003C/summary\u003E\npublic static class ClipChecks\n{\n    public sealed record Fixture(string RgbaPath, int Width, int Height, int Frames, string SourceVideo,\n        string FlowPath, string SamPath, string MhrPath, string OmegaPath, string DetectorPath, string SmplPath, string RigDirectory,\n        int CameraInterval = 10, FlowModel Model = FlowModel.Latest);\n\n    /// \u003Csummary\u003EWrites per-stage evidence, motion documents and Human/Citizen FBX\n    /// exports. Requires installed released weights and a fresh writable result directory.\u003C/summary\u003E\n    public static async Task\u003Cobject\u003E Run(string fixturePath, string directory, CancellationToken cancellation)\n    {\n        var fixture = JsonSerializer.Deserialize\u003CFixture\u003E(await File.ReadAllTextAsync(fixturePath, cancellation))\n            ?? throw new ArgumentException(\u0022Missing clip fixture.\u0022);\n        if (fixture.Frames is \u003C 150 or \u003E 300) throw new ArgumentException(\u0022Clip validation requires 5\u201310 seconds at 30 fps.\u0022);\n        if (Directory.Exists(directory)) throw new ArgumentException(\u0022Use a fresh validation directory to avoid overwriting evidence.\u0022);\n        Directory.CreateDirectory(directory);\n        await File.WriteAllTextAsync(Path.Combine(directory, \u0022fixture.json\u0022), JsonSerializer.Serialize(fixture), cancellation);\n        var processor = Processor(fixture); using var frames = new RawFrames(fixture);\n        await Task.Run(() =\u003E FlowCheckpoint.LoadDecoder(fixture.FlowPath, fixture.SmplPath, cancellation), cancellation);\n        var timer = Stopwatch.StartNew(); var times = new Dictionary\u003Cstring, double\u003E();\n        var person = await processor.DetectAsync(frames, cancellation); times[\u0022Detection\u0022] = timer.Elapsed.TotalSeconds;\n        if (person.First != 0 || person.Count != frames.Count) throw new InvalidDataException(\u0022The validation fixture must show the person in every frame.\u0022);\n        var boxes = person.Boxes; await Save(\u0022boxes.json\u0022, boxes); await Save(\u0022timings.json\u0022, times); timer.Restart();\n        var camera = await processor.CameraAsync(frames, cancellation); times[\u0022Camera\u0022] = timer.Elapsed.TotalSeconds;\n        await Save(\u0022rotations.json\u0022, camera.Rotations); await Save(\u0022intrinsics.json\u0022, camera.Intrinsics); await Save(\u0022travel.json\u0022, camera.Travel); await Save(\u0022timings.json\u0022, times); timer.Restart();\n        var (features, observations) = await processor.FeaturesAsync(frames, boxes, camera.Intrinsics, cancellation); times[\u0022Features\u0022] = timer.Elapsed.TotalSeconds;\n        await Save(\u0022features.json\u0022, features); await Save(\u0022observations.json\u0022, observations); await Save(\u0022timings.json\u0022, times); timer.Restart();\n        var motion = await processor.GenerateAsync(features, camera.Rotations, frames.Count, cancellation); times[\u0022Generation\u0022] = timer.Elapsed.TotalSeconds;\n        var exports = await Export(fixture, motion, new ObservedDetail(observations, camera.Rotations, camera.Travel), directory, cancellation); await Save(\u0022timings.json\u0022, times);\n        var result = new { Passed = true, PredecodedFixture = true, Frames = frames.Count, Seconds = frames.Count / 30.0, StageSeconds = times, Exports = exports };\n        await Save(\u0022result.json\u0022, result);\n        return result;\n\n        Task Save\u003CT\u003E(string name, T value) =\u003E File.WriteAllTextAsync(Path.Combine(directory, name), JsonSerializer.Serialize(value), cancellation);\n    }\n\n    /// \u003Csummary\u003ERepeats generation/export from this check\u0027s saved features. For\n    /// developer diagnosis only: the caller must preserve the same fixture and weights.\u003C/summary\u003E\n    public static async Task\u003Cobject\u003E Generate(string directory, CancellationToken cancellation)\n    {\n        var fixture = JsonSerializer.Deserialize\u003CFixture\u003E(await File.ReadAllTextAsync(Path.Combine(directory, \u0022fixture.json\u0022), cancellation));\n        var features = JsonSerializer.Deserialize\u003Cfloat[]\u003E(await File.ReadAllTextAsync(Path.Combine(directory, \u0022features.json\u0022), cancellation));\n        var rotations = JsonSerializer.Deserialize\u003Cfloat[]\u003E(await File.ReadAllTextAsync(Path.Combine(directory, \u0022rotations.json\u0022), cancellation));\n        var motion = await Processor(fixture).GenerateAsync(features, rotations, fixture.Frames, cancellation);\n        var observed = Path.Combine(directory, \u0022observations.json\u0022);\n        var traveled = Path.Combine(directory, \u0022travel.json\u0022);\n        var travel = File.Exists(traveled) ? JsonSerializer.Deserialize\u003Cfloat\u003E(await File.ReadAllTextAsync(traveled, cancellation)) : float.NaN;\n        var detail = File.Exists(observed) ? new ObservedDetail(JsonSerializer.Deserialize\u003Cfloat[]\u003E(await File.ReadAllTextAsync(observed, cancellation)), rotations, travel) : null;\n        return await Export(fixture, motion, detail, directory, cancellation);\n    }\n\n    static FlowVideoProcessor Processor(Fixture fixture) =\u003E new(new(fixture.FlowPath, fixture.SamPath, fixture.MhrPath, fixture.OmegaPath, fixture.DetectorPath, fixture.SmplPath),\n        new() { CameraInterval = fixture.CameraInterval, Model = fixture.Model }, message =\u003E Log.Info(message));\n\n    static Task\u003Cobject\u003E Export(Fixture fixture, FlowMotion motion, ObservedDetail detail, string directory, CancellationToken cancellation) =\u003E Task.Run\u003Cobject\u003E(async () =\u003E\n    {\n        motion.Video = fixture.SourceVideo; motion.Name = Path.GetFileNameWithoutExtension(fixture.SourceVideo); var document = motion.ToDocument(); detail?.Apply(document);\n        var bytes = Encoding.UTF8.GetBytes(document.ToJson()); await File.WriteAllBytesAsync(Path.Combine(directory, \u0022capture.hmotion\u0022), bytes, cancellation);\n        await File.WriteAllTextAsync(Path.Combine(directory, \u0022flow-motion.json\u0022), JsonSerializer.Serialize(motion), cancellation);\n        var results = new List\u003Cobject\u003E();\n        foreach (var citizen in new[] { false, true })\n        {\n            cancellation.ThrowIfCancellationRequested(); var name = citizen ? \u0022citizen\u0022 : \u0022human\u0022;\n            var rig = await File.ReadAllTextAsync(Path.Combine(fixture.RigDirectory, citizen ? \u0022target_rig_sbox_citizen.json\u0022 : \u0022target_rig_sbox.json\u0022), cancellation);\n            var target = citizen ? RetargetTargetSpec.SboxCitizen(rig) : RetargetTargetSpec.SboxDefault(rig);\n            var result = Retargeter.Convert(new RetargetRequest\n            {\n                SourceData = bytes,\n                SourceFileName = \u0022capture.hmotion\u0022,\n                FootPlantCleanup = true,\n                MocapCorrections = new TargetCorrectionSettings { FirstPerson = false, StabilizeFeet = true }\n            }, target);\n            if (!result.Success) throw new Exception(\u0022Clip retarget failed: \u0022 \u002B string.Join(\u0022; \u0022, result.Errors.Concat(result.Clips.Select(c =\u003E c.Error))));\n            var clip = result.Clips.Single();\n            foreach (var poses in clip.SolvedFrames) foreach (var pose in poses)\n                if (!float.IsFinite(pose.Pos.Length()) || !float.IsFinite(pose.Rot.Length())) throw new Exception(\u0022Non-finite target animation.\u0022);\n            var times = Enumerable.Range(0, clip.SolvedFrames.Count).Select(i =\u003E i / (double)clip.Fps).ToArray();\n            var exported = ModelDocFbxExport.Write(target.Rig.Skeleton, motion.Name, clip.SolvedFrames, times, clip.Fps, target.UpAxis, \u0022WorldRelative\u0022);\n            var roundTrip = FbxImporter.Import(exported);\n            if (roundTrip.Clips.Count != 1 || roundTrip.Clips[0].Frames.Count != clip.SolvedFrames.Count)\n                throw new Exception(\u0022Target FBX lost animation frames.\u0022);\n            var path = Path.Combine(directory, name \u002B \u0022.fbx\u0022); await File.WriteAllBytesAsync(path, exported, cancellation);\n            results.Add(new { Target = name, Frames = clip.SolvedFrames.Count, Bones = target.Rig.Skeleton.Count, FbxBytes = exported.Length, Path = path });\n        }\n        return results;\n    }, cancellation);\n\n    sealed class RawFrames : ICaptureFrames, IDisposable\n    {\n        readonly FileStream stream;\n        readonly int bytes;\n        public int Width { get; }\n        public int Height { get; }\n        public int Count { get; }\n\n        internal RawFrames(Fixture fixture)\n        {\n            Width = fixture.Width; Height = fixture.Height; Count = fixture.Frames;\n            if (Width \u003C 1 || Height \u003C 1 || (long)Width * Height \u003E 33_177_600) throw new ArgumentException(\u0022Invalid RGBA fixture dimensions.\u0022);\n            bytes = checked(Width * Height * 4);\n            stream = new(fixture.RgbaPath, FileMode.Open, FileAccess.Read, FileShare.Read, 1024 * 1024, FileOptions.Asynchronous | FileOptions.RandomAccess);\n            if (stream.Length != (long)bytes * Count) { stream.Dispose(); throw new ArgumentException(\u0022RGBA fixture length does not match its declared frame count.\u0022); }\n        }\n\n        public async ValueTask ReadAsync(int frame, Memory\u003Cbyte\u003E rgba, CancellationToken cancellation)\n        {\n            if ((uint)frame \u003E= (uint)Count || rgba.Length != bytes) throw new ArgumentException(\u0022Invalid fixture frame or destination size.\u0022);\n            cancellation.ThrowIfCancellationRequested(); stream.Position = (long)frame * bytes;\n            await stream.ReadExactlyAsync(rgba, cancellation);\n        }\n\n        public void Dispose() =\u003E stream.Dispose();\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"dev/sam_frame_checks.cs","FileName":"sam_frame_checks.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":439808,"IsPrivate":false,"Code":"using System.Diagnostics;\nusing System.Text.Json;\nusing HumanoidMocapX.EditorTools;\nusing HumanoidMocapX.Inference;\nusing Sandbox;\n\nnamespace HumanoidMocapX.Checks;\n\n/// \u003Csummary\u003ERuns released YOLOX, SAM DINOv3, body decoder and MHR on a real frame.\n/// This is an isolated body-pass diagnostic, not full video or hand refinement.\u003C/summary\u003E\npublic static class SamFrameChecks\n{\n    /// \u003Csummary\u003EWrites crop, keypoint and feature evidence to a JSON file. Requires\n    /// a visible person in an RGBA8 frame and installed, verified model files.\u003C/summary\u003E\n    public static async Task\u003Cobject\u003E Run(string samPath, string mhrPath, string detectorPath, string rgbaPath,\n        int width, int height, string resultPath, CancellationToken cancellation)\n    {\n        var pixels = await File.ReadAllBytesAsync(rgbaPath, cancellation);\n        var box = await Detect(pixels, width, height, detectorPath, cancellation);\n        var shape = DinoShape.Sam(); var crop = new SamCrop(box.Left, box.Top, box.Right, box.Bottom, shape);\n        var focal = (float)Math.Sqrt((double)width * width \u002B (double)height * height);\n        var intrinsics = new float[] { focal, 0, width / 2f, 0, focal, height / 2f, 0, 0, 1 }; var affine = new float[6]; crop.CopyAffine(affine);\n        var rgb = new float[shape.ImageElements]; var rayEncoder = new SamRays(shape); var rays = new float[rayEncoder.Elements];\n        await Task.Run(() =\u003E { crop.Prepare(pixels, width, height, rgb, cancellation); rayEncoder.Prepare(intrinsics, affine, rays, cancellation); }, cancellation);\n        var context = new float[shape.Patches * shape.Channels]; var positions = new float[context.Length];\n        var imageTimes = await Encode(samPath, shape, rgb, rays, context, positions, cancellation);\n        var model = await Task.Run(() =\u003E MhrCheckpoint.LoadBody(mhrPath, cancellation), cancellation);\n        var pose = await Task.Run(() =\u003E SamCheckpoint.LoadPoseHead(samPath, model, false, cancellation), cancellation);\n        var decoderShape = new SamDecoderShape(SamInitialTokens.Count, shape.Patches);\n        var camera = await Task.Run(() =\u003E new SamPredictionHead(VisionCheckpoint.LoadSamHead(samPath, false, cancellation), false, true), cancellation);\n        var keypoints = await Task.Run(() =\u003E new SamKeypointFeedback(VisionCheckpoint.LoadSamFeedback(samPath, false, cancellation), decoderShape, 32, 32), cancellation);\n        var projection = new SamProjection(intrinsics, affine, crop.CenterX, crop.CenterY, crop.Size, shape);\n        var feedback = new SamDecoderFeedback(decoderShape, pose, camera, keypoints); feedback.Prepare(projection, context);\n        var tokens = new float[decoderShape.TokenElements]; var tokenPositions = new float[tokens.Length]; var decoded = new float[tokens.Length];\n        await Task.Run(() =\u003E new SamInitialTokens(VisionCheckpoint.LoadSamInitialTokens(samPath, false, cancellation))\n            .Run(projection, tokens, tokenPositions, cancellation), cancellation);\n        var decoderWeights = await Task.Run(() =\u003E VisionCheckpoint.LoadSamDecoder(samPath, false, cancellation), cancellation);\n        await GameTask.MainThread(); var decoder = new SamGpuDecoder(decoderWeights, decoderShape); var timer = Stopwatch.StartNew();\n        try\n        {\n            await decoder.RunAsync(tokens, context, tokenPositions, positions, decoded, feedback.Update, cancellation);\n            await Task.Run(() =\u003E feedback.Finish(decoded, cancellation), cancellation);\n        }\n        finally { await GameTask.MainThread(); decoder.Dispose(); }\n        var decodeMilliseconds = timer.Elapsed.TotalMilliseconds;\n        var cropped = new float[140]; var depths = new float[70]; var translation = new float[3]; var imagePoints = new float[140];\n        projection.Run(pose.Keypoints, feedback.CameraParameters, cropped, depths, translation);\n        for (var i = 0; i \u003C 70; i\u002B\u002B)\n        {\n            imagePoints[i * 2] = ((cropped[i * 2] \u002B .5f) * shape.Width - affine[2]) / affine[0];\n            imagePoints[i * 2 \u002B 1] = ((cropped[i * 2 \u002B 1] \u002B .5f) * shape.Height - affine[5]) / affine[4];\n        }\n        var result = new\n        {\n            BodyPassOnly = true,\n            Width = width,\n            Height = height,\n            Box = box,\n            Crop = new { crop.CenterX, crop.CenterY, crop.Size },\n            ImageMilliseconds = imageTimes,\n            DecodeMilliseconds = decodeMilliseconds,\n            ImageKeypoints = imagePoints,\n            KeypointsMetres = pose.Keypoints.ToArray(),\n            Depths = depths,\n            Translation = translation,\n            BodyFeature = decoded.AsSpan(0, decoderShape.Width).ToArray(),\n            ModelParameters = pose.Model.ToArray()\n        };\n        await File.WriteAllTextAsync(resultPath, JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true }), cancellation);\n        return new\n        {\n            Passed = true,\n            BodyPassOnly = true,\n            Box = box,\n            Keypoints = 70,\n            BodyFeatureChannels = decoderShape.Width,\n            ImageMilliseconds = imageTimes,\n            DecodeMilliseconds = decodeMilliseconds,\n            ResultPath = resultPath\n        };\n    }\n\n    static async Task\u003CYoloBox\u003E Detect(byte[] pixels, int width, int height, string path, CancellationToken cancellation)\n    {\n        var network = new YoloNetwork(); var weights = await Task.Run(() =\u003E YoloCheckpoint.Load(path, network, cancellation), cancellation);\n        await GameTask.MainThread(); var detector = new YoloGpuDetector(network, weights);\n        try\n        {\n            var boxes = new YoloBox[YoloNetwork.Predictions]; var count = await detector.DetectAsync(pixels, width, height, boxes, cancellation);\n            if (count \u003C 1) throw new Exception(\u0022SAM frame fixture contains no detected person.\u0022);\n            return boxes[0];\n        }\n        finally { await GameTask.MainThread(); detector.Dispose(); }\n    }\n\n    static async Task\u003Cdouble[]\u003E Encode(string path, DinoShape shape, float[] rgb, float[] rays, float[] context, float[] positions, CancellationToken cancellation)\n    {\n        var backbone = await Task.Run(() =\u003E VisionCheckpoint.LoadSamBackbone(path, cancellation), cancellation);\n        var body = await Task.Run(() =\u003E VisionCheckpoint.LoadSamImageConditioning(path, false, cancellation), cancellation);\n        var hand = await Task.Run(() =\u003E VisionCheckpoint.LoadSamImageConditioning(path, true, cancellation), cancellation);\n        await GameTask.MainThread(); var encoder = new SamGpuImageEncoder(backbone, body, hand, shape);\n        try\n        {\n            var timer = Stopwatch.StartNew(); await encoder.RunAsync(rgb, rays, context, false, cancellation);\n            var first = timer.Elapsed.TotalMilliseconds; var previous = context.ToArray();\n            await GameTask.MainThread(); timer.Restart(); await encoder.RunAsync(rgb, rays, context, false, cancellation);\n            var repeated = timer.Elapsed.TotalMilliseconds;\n            if (!previous.SequenceEqual(context)) throw new Exception(\u0022SAM image encoding did not repeat exactly.\u0022);\n            encoder.CopyPositions(positions); return new[] { first, repeated };\n        }\n        finally { await GameTask.MainThread(); encoder.Dispose(); }\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"Editor/AccountBar.cs","FileName":"AccountBar.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\nusing System.Net.Http;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Editor;\nusing Sandbox;\n\nnamespace HumanoidMocapX.EditorTools;\n\n/// \u003Csummary\u003EThe strip across the top of the X window. With a provider: avatar, name, status pills,\n/// account ID and limits, then icon buttons for the queue, adding videos and sign-out. On a processing\n/// machine: its SSH address. On this computer: the GPU. Before setup: a pointer to settings. Missing\n/// names and pictures show as not provided; account details and setup live in Mocap adjustments \u203A Processing.\u003C/summary\u003E\nsealed class AccountBar : Widget\n{\n    readonly HostingSettings settings;\n    readonly QueueTracker queue;\n    readonly AccountAvatar avatar;\n    readonly Label name, details, problem;\n    readonly Layout pills;\n    readonly Button signIn;\n    readonly BadgeButton queueButton;\n    readonly IconButton add, signOut;\n    CancellationTokenSource pending;\n\n    /// \u003Csummary\u003EProvider mode when \u003Cparamref name=\u0022queue\u0022/\u003E is set, otherwise the processing machine\n    /// or this computer, or a pointer to settings while processing is not \u003Cparamref name=\u0022configured\u0022/\u003E.\u003C/summary\u003E\n    internal AccountBar(Widget parent, HostingSettings settings, SshSettings machine, QueueTracker queue, bool configured, Action openSetup) : base(parent)\n    {\n        this.settings = settings; this.queue = queue;\n        Layout = Layout.Row(); Layout.Margin = new Sandbox.UI.Margin(12, 10, 12, 10); Layout.Spacing = 10;\n        avatar = Layout.Add(new AccountAvatar(this, 34));\n        var text = Layout.AddColumn(1); text.Spacing = 2;\n        var top = text.AddRow(); top.Spacing = 8;\n        name = top.Add(Ui.Bold(new Label(\u0022\u0022, this), 14));\n        pills = top.AddRow(); pills.Spacing = 6;\n        top.AddStretchCell();\n        details = text.Add(Ui.Muted(new Label(\u0022\u0022, this), small: true));\n        problem = Layout.Add(Ui.Error(this));\n        if (!configured)\n        {\n            avatar.ShowIcon(\u0022settings\u0022);\n            name.Text = \u0022Not set up\u0022;\n            details.Text = \u0022Choose where videos are processed: settings (top right) \u203A Processing \u203A Setup.\u0022;\n            return;\n        }\n        if (queue is null \u0026\u0026 machine.Enabled)\n        {\n            avatar.ShowIcon(\u0022dns\u0022);\n            name.Text = \u0022Processing machine\u0022;\n            details.Text = $\u0022{machine.Address} over SSH \u00B7 videos are copied there for processing\u0022;\n            return;\n        }\n        if (queue is null)\n        {\n            avatar.ShowIcon(\u0022memory\u0022);\n            name.Text = \u0022This computer\u0022;\n            var gpu = Sandbox.Engine.SystemInfo.Gpu is { Length: \u003E 0 } gpuName \u0026\u0026 gpuName != \u0022unset\u0022 ? gpuName : \u0022This GPU\u0022;\n            details.Text = $\u0022{gpu} \u00B7 up to {FlowVideoProcessor.LaneCapacity()} frames at once \u00B7 videos never leave this computer\u0022;\n                return;\n        }\n        signIn = Layout.Add(Ui.Primary(\u0022Sign in\u0022, \u0022login\u0022, () =\u003E _ = SignInAsync(openSetup)));\n        queueButton = Layout.Add(new BadgeButton(this, \u0022format_list_bulleted\u0022, OpenQueue, \u0022Queue: your jobs on the provider\u0022));\n        add = Layout.Add(Ui.Icon(this, \u0022playlist_add\u0022, () =\u003E QueuePopup.AddVideos(queue), \u0022Add videos to the queue\u0022));\n        signOut = Layout.Add(Ui.Icon(this, \u0022logout\u0022, () =\u003E _ = SignOutAsync(), \u0022Sign out\u0022));\n        settings.Changed \u002B= Refresh; queue.Changed \u002B= Refresh;\n        Refresh();\n    }\n\n    void OpenQueue()\n    {\n        var popup = new QueuePopup(this, queue);\n        popup.OpenAt(queueButton.ScreenRect.BottomLeft \u002B new Vector2(queueButton.Width - popup.FixedWidth, 6));\n    }\n\n    void Refresh()\n    {\n        if (!this.IsValid()) return;\n        var profile = settings.SignedIn ? settings.Profile : null;\n        var label = EditorCookie.Get(ProcessingSetup.ProviderLabelCookie, \u0022\u0022);\n        signIn.Visible = profile is null; signIn.Text = label.Length \u003E 0 ? \u0022Sign in with \u0022 \u002B label : \u0022Sign in\u0022;\n        queueButton.Visible = add.Visible = signOut.Visible = profile is not null;\n        queueButton.Count = queue.Active;\n        pills.Clear(true);\n        if (profile is null)\n        {\n            name.Text = \u0022Signed out\u0022; details.Text = Host(); avatar.ShowIcon(\u0022person\u0022);\n            return;\n        }\n        var user = profile.User;\n        name.Text = Clip(user.Name ?? user.Username, 32) ?? \u0022Name not provided\u0022;\n        var (status, color) = profile switch\n        {\n            { Admin: true } =\u003E (\u0022Admin\u0022, Ui.Accent),\n            { CanProcess: true } =\u003E (\u0022Whitelisted\u0022, Ui.Accent),\n            { InGuild: false } =\u003E (\u0022Join the Discord server\u0022, Theme.Yellow),\n            _ =\u003E (\u0022Not whitelisted\u0022, Theme.Red)\n        };\n        pills.Add(new Pill(this, status, color));\n        if (profile.Limits is { Priority: true }) pills.Add(new Pill(this, \u0022Priority\u0022, Theme.Yellow));\n        details.Text = $\u0022{Clip(user.Id, 40)} \u00B7 {Host()}\u0022 \u002B (profile.Limits is { } limit ? \u0022 \u00B7 \u0022 \u002B Describe(limit) : \u0022\u0022);\n        details.ToolTip = user.Id \u002B \u0022: your account ID on this provider. Give it to the provider to be whitelisted. Click to copy.\u0022;\n        avatar.ShowAccount(user.Avatar, user.Name ?? user.Username);\n    }\n\n    protected override void OnMouseClick(MouseEvent e)\n    {\n        base.OnMouseClick(e);\n        // The account ID line copies the ID, so users can send it to the provider.\n        if (e.LeftMouseButton \u0026\u0026 details.IsUnderMouse \u0026\u0026 settings.Profile?.User.Id is { } id) EditorUtility.Clipboard.Copy(id);\n    }\n\n    static string Describe(HostLimits limit)\n        =\u003E (limit.MaximumClipSeconds is { } clip ? $\u0022clips up to {HostedCapture.Duration((int)clip)}\u0022 : \u0022clips up to the provider\u0027s limit\u0022)\n            \u002B $\u0022 \u00B7 uploads up to {limit.MaximumUploadBytes / (1024 * 1024)} MiB\u0022;\n\n    string Host()\n    {\n        try { return settings.Endpoint().Host; } catch (ArgumentException) { return \u0022No provider address\u0022; }\n    }\n\n    static string Clip(string text, int length) =\u003E text is { } value \u0026\u0026 value.Length \u003E length ? value[..(length - 1)] \u002B \u0022\u2026\u0022 : text;\n\n    async Task SignInAsync(Action openSetup)\n    {\n        if (pending is not null) return;\n        if (ProcessingSetup.SavedProvider() is not { } provider) { openSetup(); return; }\n        using var cancellation = new CancellationTokenSource(); pending = cancellation; var token = cancellation.Token;\n        Ui.Show(problem, null); signIn.Enabled = false; signIn.Text = \u0022Finish in your browser\u2026\u0022;\n        try { await ProcessingSetup.SignInAsync(settings, provider, token); }\n        catch (Exception failure) when (ProcessingSetup.IsSignInFailure(failure))\n        {\n            await EditorPipeline.SwitchToMainThread();\n            if (!token.IsCancellationRequested) Ui.Show(problem, failure is OperationCanceledException ? \u0022Sign-in timed out. Try again.\u0022 : failure.Message);\n        }\n        finally\n        {\n            await EditorPipeline.SwitchToMainThread();\n            pending = null;\n            if (signIn.IsValid()) { signIn.Enabled = true; Refresh(); }\n        }\n    }\n\n    async Task SignOutAsync()\n    {\n        using var client = new HostSignIn();\n        await client.SignOutAsync(settings);\n    }\n\n    public override void OnDestroyed()\n    {\n        settings.Changed -= Refresh; pending?.Cancel();\n        if (queue is not null) queue.Changed -= Refresh;\n        base.OnDestroyed();\n    }\n\n    protected override void OnPaint()\n    {\n        Paint.SetPen(Ui.CardEdge, 1);\n        Paint.DrawLine(new Vector2(0, Height - .5f), new Vector2(Width, Height - .5f));\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"tests/test_sam_backbone.cs","FileName":"test_sam_backbone.cs","PackageType":"library","CodeKind":"UnitTest","AssetVersionId":439808,"IsPrivate":false,"Code":"using HumanoidMocapX.EditorTools;\nusing HumanoidMocapX.Inference;\n\nstatic class SamBackboneTests\n{\n    internal static void Run()\n    {\n        Dimensions(); Encoder(); Checkpoint();\n        Console.WriteLine(\u0022PASS: 32-layer SAM DINOv3 encoder, SwiGLU gates, per-axis positions, selective checkpoint loading and allocation-free reuse\u0022);\n    }\n\n    static void Dimensions()\n    {\n        var shape = DinoShape.Sam();\n        MotionTests.Equal(512, shape.Width); MotionTests.Equal(512, shape.Height);\n        MotionTests.Equal(1280, shape.Channels); MotionTests.Equal(20, shape.Heads); MotionTests.Equal(32, shape.Depth);\n        MotionTests.Equal(1024, shape.Patches); MotionTests.Equal(1029, shape.Tokens);\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E DinoShape.Sam(511, 512));\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E DinoShape.Sam(channels: 1281));\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E DinoShape.Sam(heads: 3));\n        var positions = OmegaPosition.Factors(2, 3, 5, new float[] { 1 }, true);\n        // Row zero\u0027s Y coordinate is -1/2; column zero\u0027s X coordinate is -2/3.\n        MotionTests.Near(-1, positions[5 * 4], 1e-6);\n        MotionTests.Near(Math.Cos(-4 * Math.PI / 3), positions[5 * 4 \u002B 2], 1e-6);\n    }\n\n    static void Encoder()\n    {\n        var shape = DinoShape.Sam(32, 48, 8, 2); var tensors = OmegaFixture.Sam(shape.Channels, shape.Heads);\n        var encoder = new DinoImageEncoder(new(tensors), shape); var output = new float[shape.Patches * shape.Channels];\n        var image = OmegaVisionTests.Image(shape.ImageElements, 0);\n        for (var pass = 0; pass \u003C 2; pass\u002B\u002B)\n        {\n            if (pass \u003E 0) Array.Reverse(image);\n            encoder.Run(image, output);\n            var expected = OmegaVisionReference.Image(tensors, image, shape.Height, shape.Width, shape.Channels, shape.Heads, true);\n            for (var i = 0; i \u003C output.Length; i\u002B\u002B) MotionTests.Near(expected[i], output[i], 2e-4);\n        }\n        for (var warm = 0; warm \u003C 3; warm\u002B\u002B) encoder.Run(image, output);\n        var before = GC.GetAllocatedBytesForCurrentThread(); encoder.Run(image, output);\n        MotionTests.Equal(0L, GC.GetAllocatedBytesForCurrentThread() - before);\n        using var cancelled = new CancellationTokenSource(); cancelled.Cancel();\n        MotionTests.Throws\u003COperationCanceledException\u003E(() =\u003E encoder.Run(image, output, cancelled.Token));\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E encoder.Run(image, image.AsSpan(0, output.Length)));\n        image[0] = 1.1f; MotionTests.Throws\u003CArgumentException\u003E(() =\u003E encoder.Run(image, output));\n        image[0] = float.NaN; MotionTests.Throws\u003CArgumentException\u003E(() =\u003E encoder.Run(image, output));\n        var block = new OmegaBlock(new(tensors), \u0022backbone.encoder.blocks.0\u0022, 8, 2, false, true);\n        var values = new float[shape.Tokens * shape.Channels];\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E block.Run(values, new(shape.Tokens, 8), new(shape.Tokens, 8, 2, false), default));\n    }\n\n    static void Checkpoint()\n    {\n        var path = Path.Combine(Path.GetTempPath(), \u0022sam-backbone-\u0022 \u002B Guid.NewGuid().ToString(\u0022N\u0022) \u002B \u0022.pt\u0022);\n        try\n        {\n            var tensors = OmegaFixture.Sam(8, 2);\n            tensors.Add(\u0022decoder.unused\u0022, new(\u0022decoder.unused\u0022, new[] { float.NaN }, new[] { 1, 1, 1, 1, 1 }));\n            foreach (var component in new string[] { null, \u0022state_dict\u0022 })\n            {\n                CheckpointFixture.Write(path, tensors, component, \u0022\u0022); var loaded = VisionCheckpoint.LoadSamBackbone(path);\n                foreach (var pair in tensors.Where(pair =\u003E pair.Key.StartsWith(\u0022backbone.encoder.\u0022)))\n                    MotionTests.Check(loaded.Get(pair.Key, pair.Value.Shape).Data.AsSpan().SequenceEqual(pair.Value.Data), \u0022SAM backbone checkpoint changed tensor layout\u0022);\n                _ = new DinoImageEncoder(loaded, DinoShape.Sam(16, 32, 8, 2));\n                using var cancelled = new CancellationTokenSource(); cancelled.Cancel();\n                MotionTests.Throws\u003COperationCanceledException\u003E(() =\u003E VisionCheckpoint.LoadSamBackbone(path, cancelled.Token));\n                File.Delete(path);\n            }\n            tensors[\u0022backbone.encoder.blocks.31.mlp.w3.bias\u0022].Data[0] = float.NaN;\n            CheckpointFixture.Write(path, tensors, \u0022state_dict\u0022, \u0022\u0022);\n            MotionTests.Throws\u003CInvalidDataException\u003E(() =\u003E VisionCheckpoint.LoadSamBackbone(path));\n        }\n        finally { File.Delete(path); }\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"tests/test_capture_inputs.cs","FileName":"test_capture_inputs.cs","PackageType":"library","CodeKind":"UnitTest","AssetVersionId":439808,"IsPrivate":false,"Code":"using HumanoidMocapX.Inference;\n\nstatic class CaptureInputTests\n{\n    internal static void Run()\n    {\n        var person = new YoloBox(10, 20, 110, 220, .8f); var other = new YoloBox(250, 10, 290, 100, .95f);\n        var track = new PersonTrack(5); track.Add([other, person]); track.Add([person with { Left = 12, Right = 112 }, other]);\n        track.Add([]); track.Add([person with { Left = 16, Right = 116 }]); track.Add([person with { Left = 18, Right = 118 }]);\n        var span = track.Complete(); var boxes = span.Boxes;\n        MotionTests.Equal(0, span.First); MotionTests.Equal(5, span.Count); MotionTests.Check(span.Note(2, 5) is null, \u0022A fully visible person needs no note\u0022);\n        for (var i = 0; i \u003C 5; i\u002B\u002B) { MotionTests.Equal(10f \u002B i * 2, boxes[i * 4]); MotionTests.Equal(110f \u002B i * 2, boxes[i * 4 \u002B 2]); }\n        MotionTests.Throws\u003CInvalidOperationException\u003E(() =\u003E track.Add([person]));\n        var nobody = new PersonTrack(2); nobody.Add([]); nobody.Add([]); MotionTests.Throws\u003CInvalidOperationException\u003E(() =\u003E nobody.Complete());\n        var unfinished = new PersonTrack(2); unfinished.Add([person]); MotionTests.Throws\u003CInvalidOperationException\u003E(() =\u003E unfinished.Complete());\n        // The capture starts where the person first appears and ends at their last detection.\n        var late = new PersonTrack(6); late.Add([]); late.Add([]); late.Add([person]); late.Add([]); late.Add([person with { Left = 14, Right = 114 }]); late.Add([]);\n        var visible = late.Complete();\n        MotionTests.Equal(2, visible.First); MotionTests.Equal(3, visible.Count); MotionTests.Equal(12, visible.Boxes.Length);\n        MotionTests.Equal(12f, visible.Boxes[4]); MotionTests.Equal(14f, visible.Boxes[8]); MotionTests.Near(2 / 30d, visible.StartSeconds);\n        MotionTests.Equal(\u0022The person is in view from 1.07 s to 1.17 s of the video, so only that part was captured.\u0022, visible.Note(1, 6));\n        var uncertain = new PersonTrack(2); uncertain.Add([person]);\n        MotionTests.Throws\u003CInvalidOperationException\u003E(() =\u003E uncertain.Add([person, person with { Left = 11, Right = 111 }]));\n        // A person lost for more than half a second ends the capture; a later return is not joined on.\n        var lost = new PersonTrack(18); lost.Add([person]); for (var i = 0; i \u003C 15; i\u002B\u002B) lost.Add([]);\n        lost.Add([other]); lost.Add([person]);\n        var kept = lost.Complete(); MotionTests.Equal(0, kept.First); MotionTests.Equal(1, kept.Count);\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E new PersonTrack(1).Add([person with { Left = float.NaN }]));\n        var reuse = new PersonTrack(20); var input = new[] { person }; for (var i = 0; i \u003C 4; i\u002B\u002B) reuse.Add(input);\n        var before = GC.GetAllocatedBytesForCurrentThread(); reuse.Add(input); MotionTests.Equal(0L, GC.GetAllocatedBytesForCurrentThread() - before);\n        var noise = new float[491 * 501]; var repeated = new float[noise.Length]; FlowNoise.Fill(noise, 0); FlowNoise.Fill(repeated, 0);\n        MotionTests.Check(noise.SequenceEqual(repeated), \u0022Initial noise must repeat for the same seed\u0022);\n        var mean = noise.Average(v =\u003E (double)v); var variance = noise.Average(v =\u003E (double)v * v) - mean * mean;\n        MotionTests.Near(0, mean, .01); MotionTests.Near(1, variance, .02);\n        MotionTests.Check(noise.Min() \u003C -3 \u0026\u0026 noise.Max() \u003E 3 \u0026\u0026 noise.All(float.IsFinite), \u0022Normal noise must cover both tails and remain finite\u0022);\n        FlowNoise.Fill(repeated, 1); MotionTests.Check(!noise.SequenceEqual(repeated), \u0022Different seeds must vary initial noise\u0022);\n        using var stop = new CancellationTokenSource(); stop.Cancel();\n        MotionTests.Throws\u003COperationCanceledException\u003E(() =\u003E FlowNoise.Fill(noise, 0, stop.Token));\n        MotionTests.Throws\u003CArgumentException\u003E(() =\u003E FlowNoise.Fill(new float[490], 0));\n        Console.WriteLine(\u0022PASS: person identity continuity, short-gap interpolation, ambiguous/lost-person rejection, allocation-free tracking and seeded standard-normal latents\u0022);\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"tests/test_ccd_ik.cs","FileName":"test_ccd_ik.cs","PackageType":"library","CodeKind":"UnitTest","AssetVersionId":439808,"IsPrivate":false,"Code":"using System.Numerics;\nusing HumanoidMocapX.Core.Cleanup;\nusing HumanoidMocapX.Core.Maths;\nusing HumanoidMocapX.Core.Skeleton;\n\nstatic class CcdIkTests\n{\n    internal static void Run()\n    {\n        var skeleton = Skeleton.Create(new[]\n        {\n            new BoneDefinition(\u0022root\u0022, null, XForm.Identity),\n            new BoneDefinition(\u0022elbow\u0022, \u0022root\u0022, new XForm(Vector3.UnitX, Quaternion.Identity)),\n            new BoneDefinition(\u0022hand\u0022, \u0022elbow\u0022, new XForm(Vector3.UnitY, Quaternion.Identity)),\n            new BoneDefinition(\u0022finger\u0022, \u0022hand\u0022, new XForm(Vector3.UnitY * .2f, Quaternion.CreateFromAxisAngle(Vector3.UnitX, .4f)))\n        });\n        var rest = skeleton.Bones.Select(b =\u003E b.RestLocal).ToArray();\n        var solver = new CcdIk(skeleton, new[] { 0, 1 }, 2);\n        var pose = (XForm[])rest.Clone();\n        var residual = solver.Solve(pose, new Vector3(.7f, 1.3f, .4f), iterations: 128, tolerance: 1e-5f);\n        MotionTests.Check(residual \u003C 1e-4, $\u0022CCD must reach a reachable target; residual {residual}\u0022);\n        Invariants(rest, pose);\n        pose = (XForm[])rest.Clone();\n        residual = solver.Solve(pose, new Vector3(20, 0, 0), iterations: 128);\n        MotionTests.Near(18, residual, .001);\n        Invariants(rest, pose);\n\n        var locked = (XForm[])rest.Clone();\n        var limits = new LockedJoint(rest);\n        solver.Solve(locked, new Vector3(-1, 1, 0), constrain: limits.Apply);\n        MotionTests.Near(0, MathQ.AngleBetween(rest[0].Rot, locked[0].Rot), 1e-6);\n        MotionTests.Check(limits.Calls \u003E 0, \u0022CCD must enforce the supplied joint constraint\u0022);\n\n        var offsetSolver = new CcdIk(skeleton, new[] { 0 }, 2);\n        var offset = new Vector3(.1f, .3f, 0);\n        var offsetGoal = Vector3.Transform(new Vector3(1, 1, 0) \u002B offset,\n            Quaternion.CreateFromAxisAngle(Vector3.UnitZ, .4f));\n        pose = (XForm[])rest.Clone();\n        MotionTests.Check(offsetSolver.Solve(pose, offsetGoal, tipOffset: offset) \u003C .001f, \u0022CCD tip offset must reach the target\u0022);\n\n        Reject(() =\u003E new CcdIk(skeleton, new[] { 1, 0 }, 2));\n        Reject(() =\u003E new CcdIk(skeleton, new[] { -1 }, 2));\n        Reject(() =\u003E solver.Solve(rest, new Vector3(float.NaN, 0, 0)));\n        Reject(() =\u003E solver.Solve(rest, Vector3.Zero, iterations: 0));\n        Reject(() =\u003E solver.Solve(rest, Vector3.Zero, gain: float.NaN));\n        var invalid = (XForm[])rest.Clone(); invalid[1].Rot = default;\n        Reject(() =\u003E solver.Solve(invalid, Vector3.Zero));\n\n        pose = (XForm[])rest.Clone();\n        for (var i = 0; i \u003C 10; i\u002B\u002B) solver.Solve(pose, new Vector3(.7f, 1.3f, .4f));\n        var before = GC.GetAllocatedBytesForCurrentThread();\n        for (var i = 0; i \u003C 100; i\u002B\u002B) solver.Solve(pose, new Vector3(.7f, 1.3f, .4f));\n        MotionTests.Check(GC.GetAllocatedBytesForCurrentThread() == before, \u0022CCD solve must not allocate\u0022);\n        Console.WriteLine(\u0022PASS: DigitalRune CCD adaptation, reach residuals, constraints, offsets, validation and zero-allocation solve\u0022);\n    }\n\n    static void Invariants(XForm[] before, XForm[] after)\n    {\n        for (var i = 0; i \u003C before.Length; i\u002B\u002B) MotionTests.Near(0, Vector3.Distance(before[i].Pos, after[i].Pos));\n        for (var i = 2; i \u003C before.Length; i\u002B\u002B) MotionTests.Near(0, MathQ.AngleBetween(before[i].Rot, after[i].Rot));\n    }\n\n    static void Reject(Action action)\n    {\n        try { action(); } catch (ArgumentException) { return; }\n        throw new Exception(\u0022CCD accepted an invalid chain or input\u0022);\n    }\n\n    sealed class LockedJoint(XForm[] reference)\n    {\n        internal int Calls;\n        internal void Apply(XForm[] pose, int bone) { Calls\u002B\u002B; if (bone == 0) pose[bone].Rot = reference[bone].Rot; }\n    }\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"Editor/Server/EditorHost.cs","FileName":"EditorHost.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":439808,"IsPrivate":false,"Code":"using System;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Editor;\nusing HumanoidMocapX.EditorTools.Video;\nusing HumanoidMocapX;\nusing HumanoidMocapX.EditorTools;\nusing Sandbox;\n\nnamespace HumanoidMocapHost;\n\n/// \u003Csummary\u003EOpt-in processing host inside the s\u0026amp;box editor. Operator configuration\n/// comes from MOCAP_* environment variables; see docs/editor-host.md.\u003C/summary\u003E\npublic static class EditorHost\n{\n    // The engine exposes static console/event entry points; session state stays here.\n    static readonly SemaphoreSlim Changes = new(1, 1);\n    static EditorHostLifetime active;\n    static CancellationTokenSource starting;\n\n    /// \u003Csummary\u003EVerifies installed Base/Latest weights, then listens on loopback. Requires\n    /// Windows Media Foundation and a GPU budget. Startup failures propagate to the console.\u003C/summary\u003E\n    [ConCmd(\u0022mocap_x_host_start\u0022, ConVarFlags.Protected, Help = \u0022Start the configured in-editor Humanoid Mocap X processing host\u0022)]\n    public static async Task StartAsync()\n    {\n        await Changes.WaitAsync();\n        using var cancellation = new CancellationTokenSource();\n        starting = cancellation;\n        try\n        {\n            if (active is { IsRunning: true }) { Log.Info(\u0022Humanoid Mocap X host is already running.\u0022); return; }\n            if (active is not null) { await active.StopAsync(); active = null; }\n            if (LocalCapture.Availability is { } reason) throw new PlatformNotSupportedException(reason);\n            var config = HostConfiguration.Read(Environment.GetEnvironmentVariable,\n                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), \u0022HumanoidMocapX\u0022));\n            await ModelStore.InstalledAsync(config.Models, FlowModel.Base, message =\u003E Log.Info(message), cancellation.Token);\n            await ModelStore.InstalledAsync(config.Models, FlowModel.Latest, message =\u003E Log.Info(message), cancellation.Token);\n            await GameTask.MainThread(); cancellation.Token.ThrowIfCancellationRequested();\n            if (!Graphics.IsAvailable || Graphics.VideoMemoryBudget == 0 \u0026\u0026 Sandbox.Engine.SystemInfo.GpuMemory == 0)\n                throw new InvalidOperationException(\u0022The host needs an initialized GPU with a reported video-memory budget.\u0022);\n            active = Start(config);\n            Log.Info($\u0022Humanoid Mocap X host listening on http://127.0.0.1:{config.Port}/. Stop with mocap_x_host_stop.\u0022);\n        }\n        finally { starting = null; Changes.Release(); }\n    }\n\n    static EditorHostLifetime Start(HostConfiguration config)\n    {\n        var lanes = config.Lanes == CaptureLanes.Auto ? CaptureLanes.Maximum : config.Lanes;\n        var admission = new GpuAdmission(lanes);\n        admission.Update(Graphics.VideoMemoryBudget, Graphics.VideoMemoryUsed, Sandbox.Engine.SystemInfo.GpuMemory);\n        var storage = new FileJobStorage(config.Data);\n        try\n        {\n            var processor = new CaptureProcessor(storage.CaptureDirectory, config.UploadBytes,\n                (selected, workspace, progress) =\u003E new LocalCapture(new CaptureOptions\n                { Model = selected.Model, CameraInterval = selected.CameraInterval, Lanes = lanes }, config.Models, workspace, progress),\n                ReadDurationAsync);\n            var queue = new CaptureQueue(storage, processor, TimeProvider.System, config.ActivePerOwner,\n                maximumUploadBytes: config.UploadBytes, maximumClipSeconds: config.ClipSeconds,\n                concurrentJobs: config.ConcurrentJobs, canStartJob: admission.CanStart);\n            var session = new HostSession($\u0022http://127.0.0.1:{config.Port}/\u0022, config.Keys, storage, queue, ReportError);\n            return new EditorHostLifetime(session, admission);\n        }\n        catch { storage.Dispose(); throw; }\n    }\n\n    static Task\u003Cdouble\u003E ReadDurationAsync(string video, CancellationToken token) =\u003E Task.Run(() =\u003E\n    {\n        token.ThrowIfCancellationRequested();\n        using var decoder = IVideoDecoder.Open(video);\n        return decoder.Duration;\n    }, token);\n\n    /// \u003Csummary\u003ECancels startup, uploads and active captures, then waits for GPU cleanup.\n    /// Repeated calls are safe; completed job IDs are invalidated by the next start.\u003C/summary\u003E\n    [ConCmd(\u0022mocap_x_host_stop\u0022, ConVarFlags.Protected, Help = \u0022Stop and drain the in-editor Humanoid Mocap X processing host\u0022)]\n    public static async Task StopAsync()\n    {\n        try { starting?.Cancel(); } catch (ObjectDisposedException) { } // Startup just finished.\n        await Changes.WaitAsync();\n        try\n        {\n            await GameTask.MainThread();\n            if (active is not null) { await active.StopAsync(); active = null; }\n        }\n        finally { Changes.Release(); }\n    }\n\n    [EditorEvent.Hotload]\n    static void Hotloaded() =\u003E _ = StopAfterHotloadAsync();\n\n    static async Task StopAfterHotloadAsync()\n    {\n        try { await StopAsync(); }\n        catch (Exception error) { ReportError(error); }\n    }\n\n    static void ReportError(Exception error) =\u003E Log.Error($\u0022Humanoid Mocap X host: {error}\u0022);\n}\n"},{"Ident":"notpointless.chomnr_humanoid_mocap_x","Path":"Editor/Server/HostSession.cs","FileName":"HostSession.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":439808,"IsPrivate":false,"Code":"#nullable enable annotations\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace HumanoidMocapHost;\n\n/// \u003Csummary\u003EOwns one HTTP listener, queue loop and file-store lifetime. Shutdown drains\n/// uploads and GPU captures before disposing their resources.\u003C/summary\u003E\ninternal sealed class HostSession : IAsyncDisposable\n{\n    readonly object gate = new();\n    readonly CancellationTokenSource stopping = new();\n    readonly FileJobStorage storage;\n    readonly CaptureQueue queue;\n    readonly HttpHost http;\n    readonly Task worker;\n    readonly Action\u003CException\u003E reportError;\n    Task? shutdown;\n    internal bool IsStopping { get { lock (gate) return shutdown is not null; } }\n\n    internal HostSession(string prefix, ApiKeys keys, FileJobStorage storage, CaptureQueue queue, Action\u003CException\u003E reportError)\n    {\n        this.storage = storage; this.queue = queue; this.reportError = reportError;\n        try { http = new HttpHost(prefix, keys, queue, reportError); }\n        catch { stopping.Dispose(); queue.Dispose(); storage.Dispose(); throw; }\n        worker = Task.Run(() =\u003E QueueLoop.RunAsync(queue, (id, error) =\u003E reportError(new InvalidOperationException($\u0022Capture {id} failed.\u0022, error)), stopping.Token));\n        _ = ObserveAsync();\n    }\n\n    async Task ObserveAsync()\n    {\n        try { await worker; }\n        catch (Exception error) { reportError(error); }\n        finally\n        {\n            try { await StopAsync(); }\n            catch (Exception error) { reportError(error); }\n        }\n    }\n\n    /// \u003Csummary\u003EIdempotently stops this instance. The returned task completes only after\n    /// cancellation and resource cleanup; callers must await it before starting a replacement.\u003C/summary\u003E\n    internal Task StopAsync()\n    {\n        lock (gate) return shutdown ??= StopCoreAsync();\n    }\n\n    async Task StopCoreAsync()\n    {\n        await stopping.CancelAsync();\n        try { await http.DisposeAsync(); }\n        finally\n        {\n            try { await worker; }\n            finally\n            {\n                try { queue.Dispose(); }\n                finally\n                {\n                    try { storage.DeleteRun(); }\n                    finally { storage.Dispose(); stopping.Dispose(); }\n                }\n            }\n        }\n    }\n\n    public ValueTask DisposeAsync() =\u003E new(StopAsync());\n}\n"}]}