diff --git a/src/main/java/com/tiedup/remake/client/gltf/GltfPoseConverter.java b/src/main/java/com/tiedup/remake/client/gltf/GltfPoseConverter.java index 3946f1d..052b104 100644 --- a/src/main/java/com/tiedup/remake/client/gltf/GltfPoseConverter.java +++ b/src/main/java/com/tiedup/remake/client/gltf/GltfPoseConverter.java @@ -584,6 +584,10 @@ public final class GltfPoseConverter { // The "gltf_" prefix is added by convertClipSelective, so check for "gltf_Full" boolean isFullBodyAnimation = animName != null && animName.startsWith("gltf_Full"); + // Head is protected by default — only enabled as a free bone when the animation + // name contains "Head" (e.g., FullHeadStruggle, FullHeadIdle). + // This lets artists opt-in per animation without affecting the item's regions. + boolean allowFreeHead = isFullBodyAnimation && animName.contains("Head"); String[] allParts = { "head", @@ -606,14 +610,14 @@ public final class GltfPoseConverter { isFullBodyAnimation && enabledParts.contains(partName) && partsWithKeyframes.contains(partName) && - !"head".equals(partName) + (!"head".equals(partName) || allowFreeHead) ) { // Full-body animation: free part WITH keyframes — enable. // The "Full" prefix is the artist's explicit opt-in to animate // bones outside their declared regions. - // EXCEPTION: head is never enabled as a free bone — vanilla head - // tracking (mouse look) is always preserved unless the item - // explicitly owns a head region (HEAD, EYES, EARS, MOUTH). + // Head is protected by default (preserves vanilla head tracking). + // Use "Head" in the animation name (e.g., FullHeadStruggle) to + // explicitly opt-in to head control for that animation. part.fullyEnablePart(false); } else { // Non-Full animation, other item's part, or free part without keyframes.