claude-code-arcane 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +54 -6
  3. package/agents/game/ue-blueprint-specialist.md +125 -0
  4. package/agents/game/ue-gas-specialist.md +133 -0
  5. package/agents/game/ue-umg-specialist.md +131 -0
  6. package/dist/cli.js +5 -0
  7. package/docs/SKILLS-CATALOG.md +42 -3
  8. package/docs/USER-GUIDE.md +2 -2
  9. package/hooks/detect-unreal.sh +90 -0
  10. package/package.json +1 -1
  11. package/profiles/unreal-dev.yaml +97 -0
  12. package/rules/gamedev/unreal-code.md +125 -0
  13. package/skills/install-mcp/SKILL.md +135 -46
  14. package/skills/install-mcp/references/unreal-operations.md +55 -0
  15. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  16. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  17. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  18. package/skills/ue-ai-navigation/SKILL.md +526 -0
  19. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  20. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  21. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  22. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  23. package/skills/ue-animation-system/SKILL.md +521 -0
  24. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  25. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  26. package/skills/ue-async-threading/SKILL.md +433 -0
  27. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  28. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  29. package/skills/ue-audio-system/SKILL.md +527 -0
  30. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  31. package/skills/ue-blueprints/SKILL.md +134 -0
  32. package/skills/ue-blueprints/references/communication.md +82 -0
  33. package/skills/ue-character-movement/SKILL.md +475 -0
  34. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  35. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  36. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  37. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  38. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  39. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  40. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  41. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  42. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  43. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  44. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  45. package/skills/ue-editor-tools/SKILL.md +523 -0
  46. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  47. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  48. package/skills/ue-game-features/SKILL.md +477 -0
  49. package/skills/ue-game-features/references/experience-system.md +222 -0
  50. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  51. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  52. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  53. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  54. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  55. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  56. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  57. package/skills/ue-input-system/SKILL.md +394 -0
  58. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  59. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  60. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  61. package/skills/ue-mass-entity/SKILL.md +476 -0
  62. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  63. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  64. package/skills/ue-materials-rendering/SKILL.md +526 -0
  65. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  66. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  67. package/skills/ue-module-build-system/SKILL.md +487 -0
  68. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  69. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  70. package/skills/ue-naming-conventions/SKILL.md +142 -0
  71. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  72. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  73. package/skills/ue-networking-replication/SKILL.md +452 -0
  74. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  75. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  76. package/skills/ue-niagara-effects/SKILL.md +531 -0
  77. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  78. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  79. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  80. package/skills/ue-packaging/SKILL.md +116 -0
  81. package/skills/ue-physics-collision/SKILL.md +423 -0
  82. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  83. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  84. package/skills/ue-procedural-generation/SKILL.md +505 -0
  85. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  86. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  87. package/skills/ue-project-context/SKILL.md +305 -0
  88. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  89. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  90. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  91. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  92. package/skills/ue-state-trees/SKILL.md +489 -0
  93. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  94. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  95. package/skills/ue-testing-debugging/SKILL.md +520 -0
  96. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  97. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  98. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  99. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  100. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  101. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  102. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  103. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,521 @@
1
+ ---
2
+ name: ue-animation-system
3
+ description: "AnimInstance, montages, blend spaces, state machines, anim notifies, linked anim graphs"
4
+ category: "gamedev"
5
+ argument-hint: "[character o anim feature]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Animation System
11
+
12
+ You are an expert in Unreal Engine's animation system.
13
+
14
+ Ask before writing: this skill edits AnimInstance classes and animation blueprints. Propose the change and get approval before using Write or Edit.
15
+
16
+ ## Context Check
17
+
18
+ Read `docs/unreal/project-context.md` first. Note which plugins are enabled
19
+ (Control Rig, Motion Matching, Full Body IK), whether GAS is in use, and the
20
+ skeleton/character hierarchy.
21
+
22
+ ## Information to Gather
23
+
24
+ 1. What animation need? (locomotion, ability, cinematic, IK, procedural)
25
+ 2. C++ only, Blueprint only, or mixed?
26
+ 3. Does the character use `ACharacter` with an existing `USkeletalMeshComponent`?
27
+ 4. Is GAS active? (affects montage replication)
28
+ 5. Multiplayer? (determines replication strategy)
29
+ 6. Does the project use modular linked anim layers?
30
+
31
+ ---
32
+
33
+ ## Architecture
34
+
35
+ ```
36
+ ACharacter / AActor
37
+ └── USkeletalMeshComponent
38
+ └── UAnimInstance subclass
39
+ ├── NativeInitializeAnimation() [setup, game thread]
40
+ ├── NativeUpdateAnimation(float dt) [game thread]
41
+ ├── NativeThreadSafeUpdateAnimation(dt) [worker thread]
42
+ ├── FAnimInstanceProxy [worker thread eval]
43
+ └── Montage API / Linked Layers
44
+ ```
45
+
46
+ Animation updates run in two phases. Game thread: `NativeUpdateAnimation` —
47
+ safe to read gameplay state. Worker thread: blend tree evaluation. Write all
48
+ shared state as `UPROPERTY() Transient` members in `NativeUpdateAnimation`;
49
+ read those cached values in `NativeThreadSafeUpdateAnimation`.
50
+
51
+ ---
52
+
53
+ ## AnimInstance
54
+
55
+ ### Subclass Pattern
56
+
57
+ ```cpp
58
+ // MyAnimInstance.h
59
+ UCLASS()
60
+ class MYGAME_API UMyAnimInstance : public UAnimInstance
61
+ {
62
+ GENERATED_BODY()
63
+
64
+ virtual void NativeInitializeAnimation() override;
65
+ virtual void NativeUpdateAnimation(float DeltaSeconds) override;
66
+ virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds) override;
67
+
68
+ protected:
69
+ UPROPERTY(Transient) TObjectPtr<ACharacter> OwningCharacter;
70
+ UPROPERTY(Transient) TObjectPtr<UCharacterMovementComponent> MovementComp;
71
+
72
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
73
+ float Speed = 0.f;
74
+
75
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
76
+ float Direction = 0.f;
77
+
78
+ UPROPERTY(Transient, BlueprintReadOnly, Category="Locomotion")
79
+ bool bIsInAir = false;
80
+ };
81
+ ```
82
+
83
+ ```cpp
84
+ // MyAnimInstance.cpp
85
+ void UMyAnimInstance::NativeInitializeAnimation()
86
+ {
87
+ Super::NativeInitializeAnimation(); // ALWAYS call super
88
+ OwningCharacter = Cast<ACharacter>(TryGetPawnOwner());
89
+ if (OwningCharacter)
90
+ MovementComp = OwningCharacter->GetCharacterMovement();
91
+ }
92
+
93
+ void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
94
+ {
95
+ Super::NativeUpdateAnimation(DeltaSeconds);
96
+ if (!OwningCharacter || !MovementComp) return;
97
+
98
+ const FVector Velocity = MovementComp->Velocity;
99
+ Speed = Velocity.Size2D();
100
+ bIsInAir = MovementComp->IsFalling();
101
+
102
+ if (Speed > 3.f)
103
+ {
104
+ const FRotator ActorRot = OwningCharacter->GetActorRotation();
105
+ const FRotator VelocityRot = Velocity.ToOrientationRotator();
106
+ Direction = UKismetMathLibrary::NormalizedDeltaRotator(
107
+ VelocityRot, ActorRot).Yaw;
108
+ }
109
+ }
110
+
111
+ void UMyAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
112
+ {
113
+ Super::NativeThreadSafeUpdateAnimation(DeltaSeconds);
114
+ // Only read UPROPERTY members written in NativeUpdateAnimation above.
115
+ // Do NOT call any UObject functions not marked BlueprintThreadSafe.
116
+ }
117
+ ```
118
+
119
+ ### FAnimInstanceProxy — Thread-Safe Access
120
+
121
+ Heavy animation logic can run on worker threads via
122
+ `NativeThreadSafeUpdateAnimation`. Access shared data through the proxy:
123
+
124
+ ```cpp
125
+ void UMyAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
126
+ {
127
+ FMyAnimInstanceProxy& Proxy = GetProxyOnAnyThread<FMyAnimInstanceProxy>();
128
+ Proxy.Speed = Proxy.Velocity.Size();
129
+ Proxy.bIsFalling = Proxy.MovementMode == EMovementMode::MOVE_Falling;
130
+ }
131
+ ```
132
+
133
+ ```cpp
134
+ // FAnimInstanceProxy declaration — worker thread data container
135
+ USTRUCT()
136
+ struct FMyAnimInstanceProxy : public FAnimInstanceProxy
137
+ {
138
+ GENERATED_BODY()
139
+ FMyAnimInstanceProxy() = default;
140
+ explicit FMyAnimInstanceProxy(UAnimInstance* Instance) : FAnimInstanceProxy(Instance) {}
141
+
142
+ float Speed = 0.f;
143
+ FVector Velocity = FVector::ZeroVector;
144
+ TEnumAsByte<EMovementMode> MovementMode = MOVE_None;
145
+
146
+ virtual void PreUpdate(UAnimInstance* AnimInstance, float DeltaSeconds) override;
147
+ virtual void Update(float DeltaSeconds) override;
148
+ };
149
+
150
+ // In UMyAnimInstance: override CreateAnimInstanceProxy to return your proxy
151
+ virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override
152
+ { return new FMyAnimInstanceProxy(this); }
153
+ ```
154
+
155
+ The engine copies data between game thread and worker thread at safe sync points.
156
+
157
+ ---
158
+
159
+ ## Montages
160
+
161
+ Source: `AnimMontage.h`, `AnimInstance.h`
162
+
163
+ Key API (`UAnimInstance`):
164
+ ```cpp
165
+ float Montage_Play(UAnimMontage*, float PlayRate=1.f,
166
+ EMontagePlayReturnType=MontageLength, float StartAt=0.f, bool bStopAll=true);
167
+ void Montage_Stop(float BlendOut, const UAnimMontage* Montage=nullptr);
168
+ void Montage_Pause(const UAnimMontage* Montage=nullptr);
169
+ void Montage_Resume(const UAnimMontage* Montage);
170
+ void Montage_JumpToSection(FName Section, const UAnimMontage* Montage=nullptr);
171
+ void Montage_SetNextSection(FName From, FName To, const UAnimMontage* Montage=nullptr);
172
+ bool Montage_IsActive(const UAnimMontage*) const;
173
+ bool Montage_IsPlaying(const UAnimMontage*) const;
174
+ FName Montage_GetCurrentSection(const UAnimMontage* Montage=nullptr) const;
175
+ float Montage_GetPosition(const UAnimMontage*) const;
176
+ ```
177
+
178
+ ### Playing + Delegate Pattern
179
+
180
+ ```cpp
181
+ void UMyComponent::PlayAttackMontage(UAnimMontage* Montage)
182
+ {
183
+ UAnimInstance* AnimInst = GetMesh()->GetAnimInstance();
184
+ if (!AnimInst || !Montage) return;
185
+
186
+ // Play FIRST — Montage_SetEndDelegate calls GetActiveInstanceForMontage()
187
+ // internally, which returns nullptr until Montage_Play creates the instance.
188
+ if (AnimInst->Montage_Play(Montage) <= 0.f) return;
189
+
190
+ FOnMontageEnded EndDelegate;
191
+ EndDelegate.BindUObject(this, &UMyComponent::OnAttackEnded);
192
+ AnimInst->Montage_SetEndDelegate(EndDelegate, Montage);
193
+
194
+ FOnMontageBlendingOutStarted BlendOutDelegate;
195
+ BlendOutDelegate.BindUObject(this, &UMyComponent::OnAttackBlendingOut);
196
+ AnimInst->Montage_SetBlendingOutDelegate(BlendOutDelegate, Montage);
197
+ }
198
+
199
+ void UMyComponent::OnAttackEnded(UAnimMontage* Montage, bool bInterrupted) { }
200
+ void UMyComponent::OnAttackBlendingOut(UAnimMontage* Montage, bool bInterrupted) { }
201
+ ```
202
+
203
+ ### Dynamic Slot Montage
204
+
205
+ ```cpp
206
+ UAnimMontage* DynMontage = AnimInst->PlaySlotAnimationAsDynamicMontage(
207
+ SomeSequence, FName("UpperBody"), 0.25f, 0.25f, 1.f, 1);
208
+ ```
209
+
210
+ ### Multiplayer Replication
211
+
212
+ - **With GAS**: use `UAbilitySystemComponent::PlayMontage()` — GAS handles
213
+ replication via `FGameplayAbilityRepAnimMontage`.
214
+ - **Without GAS**: replicate a montage pointer or a custom rep struct; server
215
+ calls `Montage_Play`, clients play on `OnRep_`.
216
+ - Never call `Montage_Play` independently on all net roles without sync.
217
+
218
+ ### GAS Integration — PlayMontageAndWait
219
+
220
+ ```cpp
221
+ // GAS ability task — PlayMontageAndWait (requires GameplayAbilities module)
222
+ UAbilityTask_PlayMontageAndWait* Task =
223
+ UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(
224
+ this, NAME_None, AttackMontage, 1.f);
225
+ Task->OnCompleted.AddDynamic(this, &UMyAbility::OnMontageCompleted);
226
+ Task->OnInterrupted.AddDynamic(this, &UMyAbility::OnMontageInterrupted);
227
+ Task->ReadyForActivation(); // must call to start the task
228
+ ```
229
+
230
+ ---
231
+
232
+ ## Blend Spaces
233
+
234
+ Blend spaces are data assets sampled in the AnimGraph. Drive them by setting
235
+ `UPROPERTY` members on the AnimInstance that the AnimGraph reads.
236
+
237
+ - **1D** (`UBlendSpace1D`): single axis, typically Speed (0–600).
238
+ Use `FInterpolationParameter` with `InterpolationType=SpringDamper`,
239
+ `InterpolationTime=0.15`, `DampingRatio=1.0`.
240
+ - **2D** (`UBlendSpace`): two axes — Direction (-180 to 180) and Speed (0–600).
241
+ Cardinal direction samples at each speed tier.
242
+ - **Aim Offset** (`UAimOffsetBlendSpace`): additive blend space for Yaw/Pitch
243
+ aiming, placed after the base locomotion pose in the AnimGraph.
244
+
245
+ See `references/locomotion-setup.md` for complete axis configuration and
246
+ sample placement.
247
+
248
+ ---
249
+
250
+ ## State Machines
251
+
252
+ State machines live in the AnimGraph. Bind native C++ logic to transition rules
253
+ and state entry/exit without Blueprint:
254
+
255
+ ```cpp
256
+ // In NativeInitializeAnimation()
257
+ AddNativeTransitionBinding(
258
+ FName("LocomotionSM"), FName("Idle"), FName("Walk/Run"),
259
+ FCanTakeTransition::CreateUObject(this, &UMyAnimInstance::CanStartMoving),
260
+ FName("IdleToMoving"));
261
+
262
+ AddNativeStateEntryBinding(
263
+ FName("LocomotionSM"), FName("Land"),
264
+ FOnGraphStateChanged::CreateUObject(this, &UMyAnimInstance::OnLandEntered));
265
+ ```
266
+
267
+ Query state machine at runtime:
268
+ ```cpp
269
+ const FAnimNode_StateMachine* SM =
270
+ GetStateMachineInstanceFromName(FName("LocomotionSM"));
271
+ float RunWeight = GetInstanceStateWeight(
272
+ GetStateMachineIndex(FName("LocomotionSM")), SM->GetCurrentState());
273
+ ```
274
+
275
+ ### Conduit Nodes
276
+
277
+ Conduits evaluate a single boolean rule and fan out to multiple destination
278
+ states — replacing duplicated transition logic. Add a Conduit in the AnimGraph
279
+ editor; its `CanEnterTransition` runs once and all outgoing transitions share
280
+ the result. Use conduits when three or more states need the same entry condition
281
+ (e.g., "is grounded?"). For simple A-to-B transitions, a direct rule is clearer.
282
+
283
+ ---
284
+
285
+ ## Anim Notifies
286
+
287
+ Source: `AnimNotify.h`, `AnimNotifyState.h`
288
+
289
+ ### UAnimNotify — Point-in-Time
290
+
291
+ ```cpp
292
+ UCLASS(meta=(DisplayName="Footstep"))
293
+ class MYGAME_API UFootstepNotify : public UAnimNotify
294
+ {
295
+ GENERATED_BODY()
296
+ public:
297
+ // Always override the UE5 3-argument signature
298
+ virtual void Notify(USkeletalMeshComponent* MeshComp,
299
+ UAnimSequenceBase* Animation,
300
+ const FAnimNotifyEventReference& EventReference) override;
301
+
302
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Footstep")
303
+ FName FootSocket = FName("foot_l");
304
+ };
305
+ ```
306
+
307
+ ### UAnimNotifyState — Duration (Begin/Tick/End)
308
+
309
+ ```cpp
310
+ UCLASS(meta=(DisplayName="Weapon Collision Window"))
311
+ class MYGAME_API UWeaponCollisionState : public UAnimNotifyState
312
+ {
313
+ GENERATED_BODY()
314
+ public:
315
+ virtual void NotifyBegin(USkeletalMeshComponent*, UAnimSequenceBase*,
316
+ float TotalDuration, const FAnimNotifyEventReference&) override;
317
+ virtual void NotifyEnd(USkeletalMeshComponent*, UAnimSequenceBase*,
318
+ const FAnimNotifyEventReference&) override;
319
+ };
320
+ ```
321
+
322
+ ### BranchingPoint (Synchronous)
323
+
324
+ Set `bIsNativeBranchingPoint = true` in the constructor. Override
325
+ `BranchingPointNotify()` instead of `Notify()`. Fires synchronously during
326
+ `Montage_Advance` — use for section jumps and precise timeline control. All
327
+ other notifies are queued (fire after tick completes, safe for VFX/SFX).
328
+
329
+ ### Named Notify Delegate
330
+
331
+ ```cpp
332
+ AnimInst->OnPlayMontageNotifyBegin.AddDynamic(
333
+ this, &UMyComponent::HandleNotifyBegin);
334
+
335
+ void UMyComponent::HandleNotifyBegin(FName NotifyName,
336
+ const FBranchingPointNotifyPayload& Payload)
337
+ {
338
+ if (NotifyName == FName("EnableHitbox")) ActivateHitDetection();
339
+ }
340
+ ```
341
+
342
+ See `references/anim-notify-reference.md` for built-in notify catalog and more
343
+ custom patterns.
344
+
345
+ ---
346
+
347
+ ## IK and Procedural
348
+
349
+ ### Foot IK with Line Traces (NativeUpdateAnimation — game thread)
350
+
351
+ ```cpp
352
+ FVector UMyAnimInstance::GetFootTarget(FName SocketName) const
353
+ {
354
+ const FVector Foot = GetOwningComponent()->GetSocketLocation(SocketName);
355
+ FHitResult Hit;
356
+ FCollisionQueryParams P(SCENE_QUERY_STAT(FootIK), true);
357
+ P.AddIgnoredActor(OwningCharacter);
358
+ if (GetWorld()->LineTraceSingleByChannel(
359
+ Hit, Foot + FVector(0,0,50), Foot - FVector(0,0,75),
360
+ ECC_Visibility, P))
361
+ return Hit.ImpactPoint;
362
+ return Foot;
363
+ }
364
+ ```
365
+
366
+ Feed results into a Control Rig asset (UE5 recommended) or a
367
+ **Two Bone IK** skeletal control node in the AnimGraph.
368
+
369
+ **Skeletal control nodes** (AnimGraph):
370
+
371
+ | Node | Purpose |
372
+ |---|---|
373
+ | Two Bone IK | Two-joint IK (arm, leg) — effector + joint target |
374
+ | FABRIK | Multi-bone chain IK — tip bone + effector |
375
+ | Look At | Single bone tracks target location with clamp |
376
+ | Copy Bone | Copies transform components between bones |
377
+ | Spline IK | Bones follow a spline curve (spine, tail) |
378
+
379
+ ### Layered Blend Per Bone (Upper/Lower Split)
380
+
381
+ In the AnimGraph:
382
+ 1. Connect state machine output to **Base Pose**.
383
+ 2. Connect `UpperBody` slot output to **Blend Poses 0**.
384
+ 3. Layer Setup: Bone=`spine_01`, Depth=0, MeshPoseBlendFactor=1.0.
385
+
386
+ Attack montages use the `UpperBody` slot; locomotion plays uninterrupted below.
387
+
388
+ ### Aim Offset
389
+
390
+ ```cpp
391
+ // In NativeUpdateAnimation:
392
+ const FRotator Delta = UKismetMathLibrary::NormalizedDeltaRotator(
393
+ OwningCharacter->GetBaseAimRotation(),
394
+ OwningCharacter->GetActorRotation());
395
+ AimYaw = FMath::Clamp(Delta.Yaw, -90.f, 90.f);
396
+ AimPitch = FMath::Clamp(Delta.Pitch, -90.f, 90.f);
397
+ ```
398
+
399
+ Place an Aim Offset node after the base pose in the AnimGraph, feeding
400
+ `AimYaw` and `AimPitch`.
401
+
402
+ ---
403
+
404
+ ## Linked Anim Graphs and Layers
405
+
406
+ Source: `AnimNode_LinkedAnimGraph.h`, `AnimNode_LinkedAnimLayer.h`
407
+
408
+ ### Linked Anim Layer (Recommended)
409
+
410
+ 1. Create a `UAnimLayerInterface` Blueprint with layer function signatures.
411
+ 2. Main AnimInstance has **Linked Anim Layer** nodes referencing the interface.
412
+ 3. Separate AnimInstance subclasses implement the interface per mode.
413
+ 4. Swap at runtime:
414
+
415
+ ```cpp
416
+ // Switch locomotion implementation
417
+ AnimInst->LinkAnimClassLayers(UClimbingLocomotionLayer::StaticClass());
418
+ // Reset all layers to defaults:
419
+ AnimInst->LinkAnimClassLayers(nullptr);
420
+ // Retrieve a linked instance:
421
+ UAnimInstance* Layer =
422
+ AnimInst->GetLinkedAnimLayerInstanceByClass(UClimbingLocomotionLayer::StaticClass());
423
+ ```
424
+
425
+ ### Linked Anim Graph (by Tag)
426
+
427
+ ```cpp
428
+ AnimInst->LinkAnimGraphByTag(FName("CombatGraph"), UMyCombatAnimInstance::StaticClass());
429
+ UAnimInstance* Sub = AnimInst->GetLinkedAnimGraphInstanceByTag(FName("CombatGraph"));
430
+ ```
431
+
432
+ ### Notify Propagation
433
+
434
+ ```cpp
435
+ AnimInst->SetReceiveNotifiesFromLinkedInstances(true);
436
+ AnimInst->SetPropagateNotifiesToLinkedInstances(true);
437
+ // UE5.2+: let linked layers share main instance montage evaluation:
438
+ // AnimInst->SetUseMainInstanceMontageEvaluationData(true);
439
+ ```
440
+
441
+ ---
442
+
443
+ ## Root Motion
444
+
445
+ ```cpp
446
+ // Options: NoRootMotionExtraction, IgnoreRootMotion,
447
+ // RootMotionFromMontagesOnly, RootMotionFromEverything
448
+ RootMotionMode = ERootMotionMode::RootMotionFromMontagesOnly;
449
+
450
+ // Per-montage disable
451
+ FAnimMontageInstance* Inst = AnimInst->GetActiveInstanceForMontage(Montage);
452
+ if (Inst) { Inst->PushDisableRootMotion(); /* ... */ Inst->PopDisableRootMotion(); }
453
+ ```
454
+
455
+ For networked root motion, set the movement component's smoothing mode to
456
+ `ENetworkSmoothingMode::Exponential` and enable
457
+ `bAllowPhysicsRotationDuringAnimRootMotion` if rotation comes from animation.
458
+ The server runs root motion authoritatively; clients predict and correct via
459
+ `FRootMotionMovementParams`.
460
+
461
+ ---
462
+
463
+ ## Common Mistakes
464
+
465
+ | Anti-Pattern | Fix |
466
+ |---|---|
467
+ | Reading gameplay state in `NativeThreadSafeUpdateAnimation` | Cache values as `UPROPERTY Transient` in `NativeUpdateAnimation` (game thread) |
468
+ | Polling `Montage_IsActive` in a loop | Bind `FOnMontageEnded` delegate before calling `Montage_Play` |
469
+ | Two montages sharing the same slot group | Use distinct slot names (`UpperBody`, `LowerBody`) or `bStopAllMontages=false` |
470
+ | Skipping `Super::NativeInitializeAnimation()` | Always call super — it initializes the proxy and skeleton |
471
+ | Calling non-thread-safe UObject methods in thread-safe update | Only read primitive `UPROPERTY` copies; never call `GetOwningActor()` from worker thread |
472
+
473
+ ---
474
+
475
+ ## Build.cs
476
+
477
+ ```csharp
478
+ PublicDependencyModuleNames.AddRange(new string[] {
479
+ "Core", "CoreUObject", "Engine", "AnimGraphRuntime"
480
+ });
481
+ // Optional:
482
+ PrivateDependencyModuleNames.Add("ControlRig"); // Control Rig IK
483
+ PrivateDependencyModuleNames.Add("GameplayAbilities"); // GAS montage tasks
484
+ ```
485
+
486
+ ---
487
+
488
+ ## Related Skills
489
+
490
+ - `/ue-gameplay-abilities` — `PlayMontageAndWait` task, GAS montage replication.
491
+ - `/ue-actor-component-architecture` — SkeletalMeshComponent setup, Character
492
+ - `/ue-naming-conventions` — asset prefixes and Content folder layout for these assets
493
+ hierarchy, component tick ordering.
494
+ - `/ue-cpp-foundations` — delegate binding, `UPROPERTY` specifiers, `TWeakObjectPtr`.
495
+
496
+ ## Reference Files
497
+
498
+ - `references/anim-notify-reference.md` — built-in notify catalog and custom
499
+ notify implementation patterns.
500
+ - `references/locomotion-setup.md` — complete locomotion blend space and state
501
+ machine configuration guide.
502
+
503
+ ---
504
+
505
+ ## Checklist
506
+
507
+ Validate before considering the work done:
508
+
509
+ - [ ] Thread-safe update is used for animation evaluation where possible
510
+ - [ ] Montage sections and notifies are named consistently and documented
511
+ - [ ] No gameplay decisions are made inside the animation graph
512
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
513
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
514
+
515
+ **PASS** — every item holds. **CONCERNS** — the work stands but at least one item is unresolved and worth flagging to the user. **FAIL** — an item is violated in a way that breaks correctness, replication or the frame budget; fix it before handing the work over.
516
+
517
+ ## Next Steps
518
+
519
+ - `/ue-character-movement` — align animation with the movement model
520
+ - `/code-review` — architectural and quality review of the change
521
+ - `/commit` — conventional commit once the change is verified