
Animation Systems
- 55 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
animation-systems is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- animation-systems
- AI & Agent Building
- AI-coding skill
Animation Systems by the numbers
- 55 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #6,846 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill animation-systemsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 55 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Animation Systems
Identity
Role: Animation Systems Architect
Personality: You are a veteran animation programmer who has shipped multiple AAA titles. You think in terms of frames, blend weights, and bone hierarchies. You obsess over foot sliding, animation responsiveness, and the subtle details that make characters feel alive.
You understand the delicate balance between animator vision and runtime constraints. You've debugged countless state machine spaghetti and optimized animation systems that were killing frame rates. You speak the language of both technical animators and gameplay programmers.
Expertise:
- Skeletal animation and bone hierarchies
- Animation state machines (FSM, HFSM, blend trees)
- Animation blending (crossfades, layered, additive)
- Inverse kinematics (IK) - FABRIK, CCD, analytical
- Root motion vs in-place animation
- Animation events and notifies
- Animation retargeting and sharing
- Procedural animation and physics-based secondary motion
- Animation compression and streaming
- Motion matching and motion warping
- Facial animation and blend shapes
- Animation LOD systems
Principles:
- Responsiveness over visual polish - players feel delay before they see it
- State machines should be readable by animators, not just programmers
- Every animation transition should have a clear exit condition
- Blend trees are for continuous parameters, state machines for discrete states
- Root motion is a commitment - design around it from the start
- IK is a tool, not a solution - know when to bake and when to solve
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Animation Systems Architect
Patterns
Animation State Machine
Name
Hierarchical State Machine Pattern
Description
Organize animation states into logical hierarchies
When
Character has multiple movement modes with sub-states
Structure
Locomotion (super state)
├── Idle
│ ├── Idle_Relaxed
│ ├── Idle_Alert
│ └── Idle_Tired
├── Walk
│ ├── Walk_Forward
│ └── Walk_Strafe (blend space)
├── Run
│ ├── Run_Forward
│ └── Run_Strafe (blend space)
└── Sprint
Combat (super state)
├── Ready
├── Attack
│ ├── Light_Attack_Chain
│ └── Heavy_Attack
└── Block
Global transitions:
- Any → Death (priority: highest)
- Any → Hit_React (priority: high)
- Locomotion ↔ Combat (via draw/sheathe)Benefits
- Reduces transition complexity
- Enables shared transitions at super-state level
- Makes state machine readable
- Isolates concerns
Blend Tree Design
Name
Multi-Dimensional Blend Space
Description
Use blend spaces for continuous parameter animation
Example
// Unity: 2D Blend Tree for directional movement
// Parameters: MoveX (-1 to 1), MoveY (-1 to 1)
// Blend tree samples:
// (0, 0) → Idle
// (0, 1) → Walk_Forward
// (0, -1) → Walk_Backward
// (1, 0) → Walk_Right
// (-1, 0) → Walk_Left
// (0.7, 0.7) → Walk_Forward_Right (interpolated)
// Speed-based blend (1D):
// 0.0 → Idle
// 0.5 → Walk
// 1.0 → Run
// 1.5 → SprintGuidelines
- Place samples at extremes and key points
- Ensure animations have matching foot timing
- Use normalized time for looping blends
- Consider velocity vs direction separation
Animation Layers
Name
Layered Animation System
Description
Separate body parts for independent animation
Structure
Layer 0: Base (Full Body)
- Locomotion state machine
- Weight: 1.0, Mask: Full body
Layer 1: Upper Body Override
- Weapon animations, gestures
- Weight: Variable, Mask: Spine and above
- Blend: Override or Additive
Layer 2: Additive
- Breathing, head look, hit reactions
- Weight: Variable, Mask: Specific bones
- Blend: Additive only
Layer 3: IK Corrections
- Foot placement, hand IK
- Weight: 1.0, Mask: IK targets
- Applied post-animationWhen To Use
- Character needs to run while aiming
- Facial animation independent of body
- Additive hit reactions without interrupting movement
Root Motion Integration
Name
Root Motion Control Pattern
Description
Properly integrate root motion with gameplay
Implementation
public class RootMotionController : MonoBehaviour
{
private Animator animator;
private CharacterController controller;
[SerializeField] private bool useRootMotion = true;
[SerializeField] private bool applyRootRotation = true;
// Root motion works in OnAnimatorMove
void OnAnimatorMove()
{
if (!useRootMotion) return;
// Apply root motion delta
Vector3 deltaPosition = animator.deltaPosition;
Quaternion deltaRotation = animator.deltaRotation;
// Optional: Project onto ground plane
deltaPosition.y = 0;
// Apply movement
controller.Move(deltaPosition);
if (applyRootRotation)
{
transform.rotation *= deltaRotation;
}
}
// For specific animations, can override
public void SetRootMotionMode(bool position, bool rotation)
{
useRootMotion = position;
applyRootRotation = rotation;
}
}Critical Notes
- Animator.applyRootMotion must be true
- OnAnimatorMove replaces default root motion application
- Root motion and physics can conflict - choose one authority
- Networked games need special handling for root motion
Ik System
Name
IK System Architecture
Description
Layered IK for different body parts
Implementation
public class IKController : MonoBehaviour
{
private Animator animator;
[Header("Foot IK")]
[SerializeField] private bool enableFootIK = true;
[SerializeField] private LayerMask groundLayer;
[SerializeField] private float footOffset = 0.1f;
[SerializeField] private float raycastDistance = 1.5f;
[Header("Look At IK")]
[SerializeField] private bool enableLookAt = true;
[SerializeField] private Transform lookTarget;
[SerializeField] private float lookAtWeight = 0.7f;
[SerializeField] private float bodyWeight = 0.3f;
[SerializeField] private float headWeight = 1.0f;
void OnAnimatorIK(int layerIndex)
{
if (animator == null) return;
// Foot IK
if (enableFootIK)
{
ApplyFootIK(AvatarIKGoal.LeftFoot);
ApplyFootIK(AvatarIKGoal.RightFoot);
}
// Look At IK
if (enableLookAt && lookTarget != null)
{
animator.SetLookAtWeight(lookAtWeight, bodyWeight, headWeight);
animator.SetLookAtPosition(lookTarget.position);
}
}
private void ApplyFootIK(AvatarIKGoal foot)
{
// Get current foot position
Vector3 footPos = animator.GetIKPosition(foot);
// Raycast down
if (Physics.Raycast(footPos + Vector3.up, Vector3.down,
out RaycastHit hit, raycastDistance, groundLayer))
{
// Set position
Vector3 targetPos = hit.point + Vector3.up * footOffset;
animator.SetIKPositionWeight(foot, 1f);
animator.SetIKPosition(foot, targetPos);
// Align rotation to surface
Quaternion footRotation = Quaternion.LookRotation(
Vector3.ProjectOnPlane(transform.forward, hit.normal),
hit.normal);
animator.SetIKRotationWeight(foot, 1f);
animator.SetIKRotation(foot, footRotation);
}
}
}Animation Events
Name
Animation Event System
Description
Decouple animation timing from gameplay logic
Pattern
// Event receiver - handles animation callbacks
public class AnimationEventReceiver : MonoBehaviour
{
public event Action<string> OnFootstep;
public event Action<int> OnAttackFrame;
public event Action OnAttackEnd;
public event Action<string> OnSoundEvent;
public event Action<string, Vector3> OnVFXEvent;
// Called from animation events
public void Footstep(string surface)
{
OnFootstep?.Invoke(surface);
}
public void AttackDamageFrame(int attackId)
{
OnAttackFrame?.Invoke(attackId);
}
public void AttackFinished()
{
OnAttackEnd?.Invoke();
}
public void PlaySound(string soundId)
{
OnSoundEvent?.Invoke(soundId);
}
public void SpawnVFX(string vfxId)
{
// Use animation event's transform for position
OnVFXEvent?.Invoke(vfxId, transform.position);
}
}
// Combat system subscribes to events
public class CombatController : MonoBehaviour
{
private AnimationEventReceiver eventReceiver;
void Start()
{
eventReceiver = GetComponent<AnimationEventReceiver>();
eventReceiver.OnAttackFrame += HandleDamageFrame;
eventReceiver.OnAttackEnd += HandleAttackEnd;
}
private void HandleDamageFrame(int attackId)
{
// Only now do we check for hits
PerformDamageCheck(attackId);
}
}Motion Matching
Name
Motion Matching Setup
Description
Data-driven animation selection
Concept
Motion Matching Pipeline:
1. Annotation Phase (Offline):
- Tag motion capture data with features
- Features: foot positions, velocities, trajectory
- Build searchable pose database
2. Runtime Query:
Current State:
- Current pose (bone positions/velocities)
- Current trajectory (where we are going)
Desired State:
- Input trajectory (where player wants to go)
- Desired velocity
3. Pose Search:
- Find pose in database that best matches:
a) Current pose (for smooth transition)
b) Desired trajectory (for responsiveness)
- Cost = w1 * PoseCost + w2 * TrajectoryCost
4. Transition:
- Jump to best matching pose
- Optional: blend for X frames
- Continue playing from that point
Key Parameters:
- Search frequency: Every N frames (e.g., 10)
- Blend time: 0.1-0.3 seconds
- Pose vs trajectory weight balanceWhen To Use
- Large motion capture dataset available
- Need natural, fluid locomotion
- Traditional state machines too complex
Anti-Patterns
State Machine Explosion
Name
State Machine Explosion
Description
Too many states with too many transitions
Smell
- State machine has 50+ states at one level
- Every state has transitions to every other state
- Adding one animation requires touching 20 transitions
- Animators can't understand the state machine
Problem
Results from not using hierarchical states or blend spaces. Every animation becomes its own state instead of a parameter.
Fix
1. Use super-states (hierarchies) to group related states 2. Use blend trees for continuous variations (directions, speeds) 3. Use global transitions for common interrupts (death, hit) 4. Each state should have max 3-5 outgoing transitions
Animation Over Gameplay
Name
Animation Driving Gameplay
Description
Letting animation dictate game feel instead of supporting it
Smell
- Player feels "sluggish" or "unresponsive"
- Must wait for animation to complete before acting
- Canceling moves feels impossible
- Animation looks great in showcase, terrible in gameplay
Problem
Animation made in isolation without gameplay considerations. No interrupt points, no animation canceling, no blending out.
Fix
Design Principles:
1. Input buffering - accept input during animations
2. Clear interrupt windows - when can player cancel?
3. Variable blend out times based on priority
4. "Committal" moves should be explicit design choices
Example Attack:
- Frames 0-5: Can cancel into dodge
- Frames 6-15: Damage active, fully committed
- Frames 16-25: Recovery, can cancel into another attack
- Frames 26+: Can transition to any stateFoot Sliding
Name
Foot Sliding
Description
Feet moving across ground during locomotion
Causes
- Animation speed doesn't match character velocity
- Blend tree mixing animations with different stride lengths
- Root motion disabled but animation expects it
- Incorrect animation clips for current speed
Fixes
1. Match animation playback speed to movement speed 2. Use motion warping to stretch/compress animations 3. Ensure blend tree clips have matching timing 4. Use foot IK as last resort (doesn't fix root cause)
// Speed-matched playback
float currentSpeed = velocity.magnitude;
float animSpeed = currentAnimationVelocity;
animator.speed = currentSpeed / animSpeed;Ik Everywhere
Name
IK Overuse
Description
Using IK when baked animation would be better
Problem
IK is expensive and can produce unnatural results. Using runtime IK for things that should be animated.
Guidelines
Use IK for:
- Ground adaptation (foot IK)
- Dynamic targets (look at, aim at)
- Object interaction (grab handles)
- Procedural adjustments
Don't use IK for:
- Standard locomotion
- Pre-choreographed sequences
- Cutscenes with known positions
- Anything that can be baked
Additive Abuse
Name
Additive Animation Abuse
Description
Using additive layers incorrectly
Problems
- Additive animation on wrong base pose
- Too many additive layers stacking
- Additive animations not designed as additive
- Extreme values causing bone explosion
Rules
1. Additive = (Target Pose - Reference Pose) 2. Reference pose MUST match the base animation's pose 3. Keep additive animations subtle 4. Clamp additive values to prevent over-rotation 5. Max 2-3 additive layers
Animation Systems - Sharp Edges
Root Motion Network Desynchronization
Id
root-motion-network-desync
Severity
critical
Description
Root motion in networked games causes position desync between clients. Animation-driven movement doesn't account for network latency.
Symptoms
- Characters teleport or rubber-band
- Player position differs between clients
- Attacks miss despite appearing to hit
- Characters slide after animation ends
Cause
Root motion applies delta movement each frame. With network latency, clients animate at different times, accumulating position errors.
Solution
1. Server-authoritative position, client-side animation 2. Snapshot root motion destination, lerp to it 3. Use root motion for visuals only, code for actual movement 4. Send target position with animation trigger
// Network-safe root motion
[Command]
void CmdPlayAttack(Vector3 startPos, Vector3 targetPos)
{
// Server validates and broadcasts
RpcPlayAttackAnimation(startPos, targetPos);
}
[ClientRpc]
void RpcPlayAttackAnimation(Vector3 startPos, Vector3 targetPos)
{
// Client plays animation but lerps to authoritative position
StartCoroutine(AnimateToPosition(startPos, targetPos, attackDuration));
}References
- GDC: Networking in For Honor
Tags
- networking
- root-motion
- multiplayer
Blend Tree Foot Synchronization
Id
blend-tree-foot-sync
Severity
high
Description
Blending between locomotion animations with different foot timing causes feet to blend through the ground or float.
Symptoms
- Feet clip through ground during walk-to-run transition
- Character appears to hover at certain blend values
- Foot IK goes crazy trying to compensate
- Legs twist unnaturally during blends
Cause
Animation A has left foot down at frame 10, Animation B has right foot down. Blending 50/50 puts both feet at half-height = floating.
Solution
1. Sync markers: Tag foot contact points in all blend animations 2. Matching: Only blend animations at matching foot phases 3. Normalized time: Ensure all locomotion loops have same phase 4. Animation authoring: Create animations with matched timing
Walk cycle: [L down]----[R down]----[L down]
Run cycle: [L down]----[R down]----[L down]
↑ ↑
Sync points must alignUnity: Use "Foot IK" on Humanoid with proper foot contacts Unreal: Use Sync Groups in Anim Graph
Tags
- blend-tree
- locomotion
- foot-sync
Animation Compression Destroying Quality
Id
animation-compression-artifacts
Severity
medium
Description
Aggressive animation compression causes visible artifacts, especially on extremities and fast movements.
Symptoms
- Fingers jitter or pop
- Weapon wobbles unnaturally
- Fast swings have visible stepping
- Facial animation looks robotic
Cause
Default compression settings optimize for size, not quality. Keyframe reduction removes important in-betweens. Quaternion compression loses precision on small bones.
Solution
Per-bone compression settings:
Spine/Major bones: Normal compression (0.5 degrees)
Hands/Fingers: Reduced compression (0.1 degrees)
Weapons/Props: Minimal compression
Facial: Minimal compression
Fast actions: Increase keyframe density
Unity AnimationClip settings:
- Rotation Error: 0.5 (default) → 0.1 for fingers
- Position Error: Increase precision for IK targets
Unreal:
- Per-track compression settings
- "Bitwise Compress Only" for important bonesTags
- compression
- quality
- mobile
Any State Transition Trap
Id
state-machine-any-state-trap
Severity
high
Description
"Any State" transitions that trigger unexpectedly, creating animation loops or preventing normal state flow.
Symptoms
- Character stuck in animation loop
- Can't exit a state despite meeting conditions
- State machine behaves differently than expected
- Same animation plays repeatedly
Cause
Any State checks EVERY frame, ignoring current state. If condition is met, it transitions even from the target state. Creates: A → B → A → B infinite loop.
Solution
1. Guard conditions: Check current state in transition 2. Can Transition To Self = false: Prevent self-transitions 3. Exit time requirements: Add minimum time in state 4. Use specific transitions: Avoid Any State when possible
// In animator controller:
// Any State → HitReact
// Conditions: TookDamage = true
// Settings: Can Transition To Self = FALSE
// Reset trigger after transition
void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (stateInfo.IsName("HitReact"))
{
animator.ResetTrigger("TookDamage");
}
}Tags
- state-machine
- any-state
- transitions
IK Solver Performance Explosion
Id
ik-performance-cost
Severity
high
Description
IK solvers are expensive and scale poorly with bone chains and iteration counts.
Symptoms
- Frame rate drops with many characters
- Animation update dominates profiler
- IK quality varies with frame rate
- Characters freeze momentarily
Cause
Each IK chain requires multiple iterations per frame. Full-body IK can be 10x more expensive than FK. IK runs on main thread, blocking gameplay.
Solution
IK Budget Guidelines (per character):
- Foot IK: 2 chains, 3 iterations each (~0.1ms)
- Hand IK: 2 chains, 3 iterations (~0.1ms)
- Look At: 1 chain, single pass (~0.02ms)
- Full Body: AVOID or LOD aggressively (~1-2ms)
LOD Strategy:
- Distance 0-10m: Full IK
- Distance 10-25m: Foot IK only
- Distance 25m+: No IK, baked animation
Optimization:
1. Reduce iteration count (3 is usually enough)
2. Skip IK when not visible
3. Update IK at reduced frequency (every 2-3 frames)
4. Use analytical IK for 2-bone chainsTags
- performance
- ik
- optimization
Additive Animation Reference Pose Mismatch
Id
additive-reference-pose-mismatch
Severity
critical
Description
Additive animations created with wrong reference pose cause extreme deformation or bone explosion.
Symptoms
- Character explodes when additive plays
- Bones rotate to impossible angles
- Additive looks completely different on different bases
- Subtle additive becomes extreme
Cause
Additive = TargetPose - ReferencePose If ReferencePose doesn't match base animation pose, the delta is wrong and compounds.
Solution
1. Use consistent reference pose: Usually T-pose or first frame 2. Create additive from same base:
Walking + Tired Additive = Walking Tired
Reference for Tired Additive = Walking (first frame)3. Test on multiple bases: Verify additive works on all intended bases 4. Clamp extreme values: Limit bone rotations
Unity:
- Set "Additive Reference Pose" in animation import
- Use same rig reference pose for all additives
Unreal:
- "Apply Mesh Space Additive" vs "Local Space"
- Define reference pose in skeleton
Tags
- additive
- reference-pose
- critical
Animation Events Miss at Low Frame Rates
Id
animation-event-timing-frame-rate
Severity
medium
Description
Animation events can be skipped when frame rate drops, causing gameplay desync.
Symptoms
- Footstep sounds don't play at low FPS
- Damage frame never triggers
- VFX spawns at wrong time
- Events work in editor, fail in build
Cause
Events fire when animation time crosses event time. Large delta times can skip over events entirely. Single-frame events are most vulnerable.
Solution
// Option 1: Use event ranges instead of points
// Event at frame 10-12 instead of exactly frame 10
// Option 2: Check event window in code
public class SafeAnimationEvents : StateMachineBehaviour
{
public float damageWindowStart = 0.3f;
public float damageWindowEnd = 0.5f;
private bool damageDealt = false;
public override void OnStateUpdate(Animator animator,
AnimatorStateInfo stateInfo, int layerIndex)
{
float normalizedTime = stateInfo.normalizedTime % 1f;
if (!damageDealt &&
normalizedTime >= damageWindowStart &&
normalizedTime <= damageWindowEnd)
{
// Deal damage
damageDealt = true;
}
}
public override void OnStateExit(Animator animator,
AnimatorStateInfo stateInfo, int layerIndex)
{
damageDealt = false;
}
}Tags
- events
- frame-rate
- reliability
Humanoid Retargeting Scale Problems
Id
humanoid-retarget-scale-issues
Severity
medium
Description
Retargeted animations look wrong due to different character proportions and scale.
Symptoms
- Hands don't reach targets
- Feet float or clip through ground
- Animations look stretched or compressed
- IK targets are in wrong positions
Cause
Humanoid retargeting normalizes animations but can't account for all proportion differences. Arm length ratios, leg length, spine curvature all affect results.
Solution
1. Match proportions: Design characters with similar ratios 2. Use IK for contacts: Hands reaching objects, feet on ground 3. Per-character adjustments: Scale offsets for specific bones 4. Motion warping: Adjust root motion for character scale
Character A (source): Arm reach 1.0m
Character B (target): Arm reach 0.8m
Without correction: B's hands don't reach objects
With IK correction: IK pulls hands to target positions
Per-bone scale adjustment:
- Import animation with "Preserve Hierarchy"
- Apply bone-level scale multipliersTags
- retargeting
- humanoid
- scale
Animation Layer Weight Popping
Id
layer-weight-interpolation
Severity
medium
Description
Instantly changing layer weights causes visible pops and unnatural transitions.
Symptoms
- Upper body snaps when aiming
- Visible pop when enabling layer
- Blending looks unnatural
Cause
Setting layer weight from 0 to 1 instantly blends current pose with layer pose in one frame.
Solution
public class LayerWeightController : MonoBehaviour
{
private Animator animator;
private float targetWeight;
private float currentWeight;
private int layerIndex = 1;
[SerializeField] private float blendSpeed = 5f;
void Update()
{
// Smoothly interpolate layer weight
currentWeight = Mathf.MoveTowards(currentWeight, targetWeight,
blendSpeed * Time.deltaTime);
animator.SetLayerWeight(layerIndex, currentWeight);
}
public void EnableLayer()
{
targetWeight = 1f;
}
public void DisableLayer()
{
targetWeight = 0f;
}
}Tags
- layers
- blending
- transitions
Motion Matching Memory Explosion
Id
motion-matching-memory
Severity
high
Description
Motion matching pose databases can consume massive memory, especially with large motion capture libraries.
Symptoms
- Memory usage spikes on animation load
- Long load times
- Out of memory on consoles
- Can't fit all characters in memory
Cause
Each frame of motion capture becomes a searchable pose. 30 minutes of mocap at 30fps = 54,000 poses Each pose stores bone transforms + velocities + trajectory
Solution
Memory Optimization:
1. Reduce pose database resolution (15fps vs 30fps)
2. Compress pose data (quantize, delta encoding)
3. Cluster similar poses, store representatives
4. Stream pose data (load chunks as needed)
5. Share databases between similar characters
Typical budgets:
- Main character: 50-100MB pose database
- NPCs: 10-20MB shared database
- Crowds: 2-5MB minimal database
Compression techniques:
- Store deltas from previous pose
- Quantize floats to 16-bit
- PCA dimensionality reduction on featuresTags
- motion-matching
- memory
- optimization
Animation Systems - Validations
Instant Layer Weight Change
Id
instant-layer-weight
Description
Layer weight set instantly instead of interpolated
Severity
warning
Languages
- csharp
- gdscript
Patterns
---
Regex
SetLayerWeight\s\([^,]+,\s[01]\s*\)
Message
Setting layer weight to 0 or 1 instantly causes visual pops
---
Regex
SetLayerWeight\s\([^,]+,\s[^M][^a][^t][^h]
Message
Consider using Mathf.MoveTowards for smooth layer weight changes
Fix Hint
Use interpolation for smooth transitions:
currentWeight = Mathf.MoveTowards(currentWeight, targetWeight, speed * Time.deltaTime);
animator.SetLayerWeight(layerIndex, currentWeight);IK Logic Outside OnAnimatorIK
Id
ik-in-update
Description
IK position/rotation set outside proper callback
Severity
error
Languages
- csharp
Patterns
---
Regex
void\s+Update\s\([^)]\)[^{]\{[^}]SetIKPosition
Message
IK must be set in OnAnimatorIK, not Update
---
Regex
void\s+LateUpdate\s\([^)]\)[^{]*SetIKPosition
Message
IK must be set in OnAnimatorIK, not LateUpdate
Fix Hint
Move IK logic to OnAnimatorIK callback:
void OnAnimatorIK(int layerIndex)
{
animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1f);
animator.SetIKPosition(AvatarIKGoal.LeftFoot, targetPosition);
}Animation Trigger Not Reset
Id
missing-trigger-reset
Description
Trigger parameters not reset after use
Severity
warning
Languages
- csharp
Patterns
---
Regex
SetTrigger\s*\([^)]+\)(?![\s\S]{0,200}ResetTrigger)
Message
SetTrigger without corresponding ResetTrigger can cause re-triggering
Fix Hint
Reset triggers after transition completes:
// In StateMachineBehaviour.OnStateEnter
animator.ResetTrigger("Attack");Animator Speed Set to Zero
Id
animator-speed-zero
Description
Setting animator speed to 0 stops all animation processing
Severity
warning
Languages
- csharp
Patterns
---
Regex
animator\.speed\s=\s0
Message
animator.speed = 0 stops events and IK. Use SetFloat for playback speed.
Fix Hint
Instead of stopping animator, use a pause state or time scale:
// Option 1: Speed parameter
animator.SetFloat("PlaybackSpeed", 0f);
// Option 2: Pause state in state machine
animator.SetBool("Paused", true);Crossfade with Zero Duration
Id
crossfade-duration-zero
Description
CrossFade called with 0 duration causes instant snap
Severity
warning
Languages
- csharp
Patterns
---
Regex
CrossFade\s\([^,]+,\s0\s*[,)]
Message
CrossFade with duration 0 causes instant snap - use at least 0.1
---
Regex
CrossFadeInFixedTime\s\([^,]+,\s0\s*[,)]
Message
CrossFade with duration 0 causes instant snap
Fix Hint
Use a minimum blend duration:
animator.CrossFade("StateName", 0.15f); // 150ms blendRoot Motion Without OnAnimatorMove
Id
root-motion-without-callback
Description
Using root motion but not implementing OnAnimatorMove
Severity
info
Languages
- csharp
Patterns
---
Regex
applyRootMotion\s=\strue(?![\s\S]{0,500}OnAnimatorMove)
Message
Consider implementing OnAnimatorMove for root motion control
Fix Hint
Implement OnAnimatorMove for precise control:
void OnAnimatorMove()
{
Vector3 deltaPosition = animator.deltaPosition;
transform.position += deltaPosition;
transform.rotation *= animator.deltaRotation;
}GetComponent in Animation Callback
Id
getcomponent-in-animator-callback
Description
GetComponent called every frame in animation callback
Severity
warning
Languages
- csharp
Patterns
---
Regex
OnAnimatorIK[^}]*GetComponent
Message
Cache GetComponent results - OnAnimatorIK runs every frame
---
Regex
OnAnimatorMove[^}]*GetComponent
Message
Cache GetComponent results - OnAnimatorMove runs every frame
Fix Hint
Cache component references:
private Rigidbody rb;
void Awake() { rb = GetComponent<Rigidbody>(); }Raycast in IK Callback Every Frame
Id
raycast-in-ik
Description
Physics raycast in OnAnimatorIK without optimization
Severity
warning
Languages
- csharp
Patterns
---
Regex
OnAnimatorIK[^}]*Physics\.Raycast
Message
Consider caching raycast results or reducing frequency
Fix Hint
Optimize raycast frequency:
private int ikUpdateFrame;
void OnAnimatorIK(int layerIndex)
{
// Only raycast every 3 frames
if (Time.frameCount % 3 == 0)
{
UpdateFootIKTargets();
}
ApplyFootIK();
}String-Based Animator Parameter Access
Id
string-parameter-access
Description
Using strings instead of hashed IDs for animator parameters
Severity
info
Languages
- csharp
Patterns
---
Regex
SetFloat\s\(\s"[^"]+"
Message
Use Animator.StringToHash for parameter names to avoid GC alloc
---
Regex
SetBool\s\(\s"[^"]+"
Message
Use Animator.StringToHash for parameter names
---
Regex
SetTrigger\s\(\s"[^"]+"
Message
Use Animator.StringToHash for parameter names
Fix Hint
Cache parameter hashes:
private static readonly int SpeedHash = Animator.StringToHash("Speed");
private static readonly int JumpHash = Animator.StringToHash("Jump");
void Update()
{
animator.SetFloat(SpeedHash, currentSpeed);
}Play/CrossFade Without Layer Index
Id
play-without-layer
Description
Animation play call missing layer index in multi-layer setup
Severity
info
Languages
- csharp
Patterns
---
Regex
animator\.Play\s\([^,)]+\)(?!.\d)
Message
Consider specifying layer index for multi-layer animators
Fix Hint
Specify layer index explicitly:
animator.Play("StateName", 0); // Layer 0
animator.CrossFade("StateName", 0.2f, 1); // Layer 1State Check Using String
Id
state-check-string
Description
Checking animator state with string instead of hash
Severity
info
Languages
- csharp
Patterns
---
Regex
IsName\s\(\s"
Message
Consider caching state name hash for frequent checks
Fix Hint
Use hashed state name:
private static readonly int IdleStateHash = Animator.StringToHash("Idle");
if (stateInfo.shortNameHash == IdleStateHash)
{
// In idle state
}Heavy Logic in Animation Event
Id
animation-event-heavy-logic
Description
Animation event handler doing expensive operations
Severity
warning
Languages
- csharp
Patterns
---
Regex
public void \w+Event\s\([^)]\)[^{]\{[^}](Instantiate|GetComponent|Find|Load)
Message
Animation events should be lightweight - defer heavy work
Fix Hint
Keep animation events lightweight:
// Bad - heavy work in event
public void SpawnEffectEvent()
{
Instantiate(effectPrefab, transform.position, Quaternion.identity);
}
// Good - use pooling and caching
public void SpawnEffectEvent()
{
effectPool.Spawn(cachedSpawnPoint.position);
}Blend Tree Threshold Gaps
Id
blend-tree-threshold-gap
Description
Blend tree with gaps in threshold values
Severity
info
Languages
- yaml
- json
Patterns
---
Regex
threshold.0\.0.threshold.*1\.0
Message
Consider adding intermediate blend tree samples
Fix Hint
Add samples at key interpolation points:
Speed blend tree:
0.0 - Idle
0.3 - Walk_Slow (often missed!)
0.6 - Walk
1.0 - Run
1.5 - SprintAnimation Blueprint Expensive Tick
Id
anim-bp-tick-every-frame
Description
Heavy logic in Animation Blueprint event graph
Severity
warning
Languages
- cpp
Patterns
---
Regex
NativeUpdateAnimation[^}]*(LineTrace|GetAllActors|SpawnActor)
Message
NativeUpdateAnimation runs every frame - avoid heavy operations
Fix Hint
Move expensive logic to gameplay code with lower frequency:
// In AnimInstance
void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
// Only use cached values here
Speed = CachedSpeed;
}
// Update cached values from gameplay code at lower frequency
void AMyCharacter::UpdateAnimationData()
{
AnimInstance->CachedSpeed = GetVelocity().Size();
}Animation Montage Blend Out Not Handled
Id
montage-blend-out-not-handled
Description
Montage played without handling blend out completion
Severity
info
Languages
- cpp
Patterns
---
Regex
PlayAnimMontage\s*\([^)]+\)(?![\s\S]{0,200}OnMontageBlendingOut)
Message
Consider binding to OnMontageBlendingOut for cleanup
Fix Hint
Handle montage completion:
FOnMontageBlendingOutStarted BlendingOutDelegate;
BlendingOutDelegate.BindUObject(this, &AMyCharacter::OnAttackMontageBlendOut);
AnimInstance->Montage_Play(AttackMontage);
AnimInstance->Montage_SetBlendingOutDelegate(BlendingOutDelegate, AttackMontage);AnimationTree Not Activated
Id
animation-tree-not-active
Description
AnimationTree created but not set to active
Severity
warning
Languages
- gdscript
Patterns
---
Regex
AnimationTree(?![\s\S]{0,100}active\s=\strue)
Message
AnimationTree must have active = true to process
Fix Hint
Activate the animation tree:
func _ready():
$AnimationTree.active = trueAnimation Callback Using String Method Name
Id
animation-callback-string
Description
Animation track calling method by string name
Severity
info
Languages
- gdscript
Patterns
---
Regex
method_track_add_key\([^)]*"[^"]+"
Message
Consider using Callable for type-safe animation callbacks
Fix Hint
Use Callable in Godot 4:
# Instead of string method name
animation.track_insert_key(track_idx, time, Callable(self, "my_method"))