claude-code-arcane 2.2.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 (144) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +104 -55
  3. package/agents/career/career-strategist.md +88 -0
  4. package/agents/career/cv-reviewer.md +81 -0
  5. package/agents/career/hiring-manager.md +68 -0
  6. package/agents/career/mock-interviewer.md +76 -0
  7. package/agents/freelance/client-screener.md +84 -0
  8. package/agents/freelance/discovery-call.md +65 -0
  9. package/agents/freelance/pipeline-strategist.md +99 -0
  10. package/agents/freelance/proposal-reviewer.md +82 -0
  11. package/agents/game/ue-blueprint-specialist.md +125 -0
  12. package/agents/game/ue-gas-specialist.md +133 -0
  13. package/agents/game/ue-umg-specialist.md +131 -0
  14. package/dist/cli.js +57 -13
  15. package/docs/RELEASE-SETUP.md +1 -1
  16. package/docs/SKILLS-CATALOG.md +67 -4
  17. package/docs/USER-GUIDE.md +77 -72
  18. package/docs/agent-hierarchy.md +21 -1
  19. package/docs/presentations/build_arcane_deck.py +2 -2
  20. package/docs/presentations/build_arcane_deck_12.py +2 -2
  21. package/hooks/detect-unreal.sh +90 -0
  22. package/package.json +2 -2
  23. package/profiles/freelance.yaml +43 -0
  24. package/profiles/job-hunt.yaml +5 -2
  25. package/profiles/unreal-dev.yaml +97 -0
  26. package/rules/drafter-reviewer.md +16 -3
  27. package/rules/freelance-guardrails.md +53 -0
  28. package/rules/gamedev/unreal-code.md +125 -0
  29. package/skills/career-registry/SKILL.md +95 -0
  30. package/skills/career-registry/scripts/career_registry.py +488 -0
  31. package/skills/client-screen/SKILL.md +83 -0
  32. package/skills/client-screen/references/red-flags.md +95 -0
  33. package/skills/cover-letter/SKILL.md +4 -3
  34. package/skills/cv-tailor/SKILL.md +11 -2
  35. package/skills/freelance-deliver/SKILL.md +90 -0
  36. package/skills/freelance-hunt/SKILL.md +126 -0
  37. package/skills/freelance-hunt/references/templates/Connects.md +39 -0
  38. package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
  39. package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
  40. package/skills/freelance-kickoff/SKILL.md +94 -0
  41. package/skills/freelance-pipeline/SKILL.md +109 -0
  42. package/skills/freelance-pipeline/scripts/import_history.py +425 -0
  43. package/skills/freelance-profile/SKILL.md +93 -0
  44. package/skills/freelance-proposal/SKILL.md +112 -0
  45. package/skills/freelance-scan/SKILL.md +196 -0
  46. package/skills/freelance-scan/references/dedup.md +35 -0
  47. package/skills/freelance-scan/references/platforms.md +167 -0
  48. package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
  49. package/skills/install-mcp/SKILL.md +135 -46
  50. package/skills/install-mcp/references/unreal-operations.md +55 -0
  51. package/skills/interview-prep/SKILL.md +11 -3
  52. package/skills/job-aplicar/SKILL.md +5 -1
  53. package/skills/job-hunt/SKILL.md +17 -0
  54. package/skills/job-outcome/SKILL.md +15 -1
  55. package/skills/job-upskill/SKILL.md +10 -2
  56. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  57. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  58. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  59. package/skills/ue-ai-navigation/SKILL.md +526 -0
  60. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  61. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  62. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  63. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  64. package/skills/ue-animation-system/SKILL.md +521 -0
  65. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  66. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  67. package/skills/ue-async-threading/SKILL.md +433 -0
  68. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  69. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  70. package/skills/ue-audio-system/SKILL.md +527 -0
  71. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  72. package/skills/ue-blueprints/SKILL.md +134 -0
  73. package/skills/ue-blueprints/references/communication.md +82 -0
  74. package/skills/ue-character-movement/SKILL.md +475 -0
  75. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  76. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  77. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  78. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  79. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  80. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  81. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  82. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  83. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  84. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  85. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  86. package/skills/ue-editor-tools/SKILL.md +523 -0
  87. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  88. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  89. package/skills/ue-game-features/SKILL.md +477 -0
  90. package/skills/ue-game-features/references/experience-system.md +222 -0
  91. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  92. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  93. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  94. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  95. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  96. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  97. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  98. package/skills/ue-input-system/SKILL.md +394 -0
  99. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  100. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  101. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  102. package/skills/ue-mass-entity/SKILL.md +476 -0
  103. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  104. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  105. package/skills/ue-materials-rendering/SKILL.md +526 -0
  106. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  107. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  108. package/skills/ue-module-build-system/SKILL.md +487 -0
  109. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  110. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  111. package/skills/ue-naming-conventions/SKILL.md +142 -0
  112. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  113. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  114. package/skills/ue-networking-replication/SKILL.md +452 -0
  115. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  116. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  117. package/skills/ue-niagara-effects/SKILL.md +531 -0
  118. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  119. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  120. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  121. package/skills/ue-packaging/SKILL.md +116 -0
  122. package/skills/ue-physics-collision/SKILL.md +423 -0
  123. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  124. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  125. package/skills/ue-procedural-generation/SKILL.md +505 -0
  126. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  127. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  128. package/skills/ue-project-context/SKILL.md +305 -0
  129. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  130. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  131. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  132. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  133. package/skills/ue-state-trees/SKILL.md +489 -0
  134. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  135. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  136. package/skills/ue-testing-debugging/SKILL.md +520 -0
  137. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  138. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  139. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  140. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  141. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  142. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  143. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  144. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,527 @@
1
+ ---
2
+ name: ue-audio-system
3
+ description: "UAudioComponent, SoundCue, MetaSound, attenuation, concurrency, audio analysis"
4
+ category: "gamedev"
5
+ argument-hint: "[sound o audio system]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Audio System
11
+
12
+ You are an expert in Unreal Engine's audio systems, covering UAudioComponent, sound asset types,
13
+ spatial attenuation, concurrency management, submix routing, MetaSounds, and runtime audio analysis.
14
+
15
+ Ask before writing: this skill edits audio components, MetaSound and Sound Cue assets. Propose the change and get approval before using Write or Edit.
16
+
17
+ ## Context Check
18
+
19
+ Before implementing audio, read `docs/unreal/project-context.md` for:
20
+
21
+ - **Audio plugins** enabled (Resonance Audio, Steam Audio, Wwise, FMOD, MetaSound plugin version)
22
+ - **Target platforms** — mobile has strict voice limits; consoles differ from PC
23
+ - **Dedicated server** flag — audio must be skipped server-side or it will crash/log errors
24
+ - **VR flag** — VR projects require binaural spatialization settings
25
+
26
+ ## Information Gathering
27
+
28
+ Ask about:
29
+
30
+ 1. One-shot SFX, looping ambient, music, UI feedback, or dialogue?
31
+ 2. Spatialized (follows actor) or global 2D?
32
+ 3. Concurrency concern (gunshots, footsteps, explosions)?
33
+ 4. Runtime control needed (fade, pause, parameter changes)?
34
+ 5. MetaSound procedural or pre-authored SoundCue/SoundWave?
35
+
36
+ ---
37
+
38
+ ## Sound Asset Hierarchy
39
+
40
+ ```
41
+ USoundBase // abstract base (SoundBase.h)
42
+ ├── USoundWave // raw PCM/compressed audio asset
43
+ ├── USoundCue // node-graph: random, modulator, mixer, attenuator nodes
44
+ └── UMetaSoundSource // procedural audio graph (MetaSound plugin)
45
+ ```
46
+
47
+ **USoundWave** — Import .wav/.ogg/.flac. Set `SoundClassObject` and `AttenuationSettings` on asset.
48
+
49
+ **USoundCue** — Node graph combining multiple waves. Key nodes:
50
+ `USoundNodeRandom`, `USoundNodeModulator`, `USoundNodeMixer`, `USoundNodeAttenuation`,
51
+ `USoundNodeLooping`, `USoundNodeDelay`, `USoundNodeDistanceCrossFade`.
52
+
53
+ **UMetaSoundSource** — Procedural audio graph. Declare typed inputs (float, bool, int32, trigger).
54
+ Set parameters at runtime via `UAudioComponent::SetFloatParameter`, `SetBoolParameter`, `SetIntParameter`.
55
+
56
+ ### Streaming Long Audio
57
+
58
+ For music and ambient tracks exceeding ~30 seconds, set `USoundWave::LoadingBehavior`:
59
+ `ESoundWaveLoadingBehavior::ForceInline` for short SFX, `RetainOnLoad` for music loaded at level start.
60
+ Long files should use `LoadOnDemand` to avoid loading the full waveform into memory.
61
+ In the editor: SoundWave asset → Details → Loading → Loading Behavior.
62
+
63
+ ---
64
+
65
+ ## Playing Sounds from C++
66
+
67
+ ### Fire-and-Forget
68
+
69
+ ```cpp
70
+ #include "Kismet/GameplayStatics.h"
71
+
72
+ // 2D — not spatialized (UI, music)
73
+ UGameplayStatics::PlaySound2D(
74
+ this, ImpactSound, 1.0f /*Vol*/, 1.0f /*Pitch*/, 0.0f /*StartTime*/,
75
+ ConcurrencySettings, OwningActor
76
+ );
77
+
78
+ // 3D — spatialized, requires AttenuationSettings on the sound asset
79
+ UGameplayStatics::PlaySoundAtLocation(
80
+ this, GunShotSound, GetActorLocation(), FRotator::ZeroRotator,
81
+ 1.0f, 1.0f, 0.0f,
82
+ AttenuationOverride, // USoundAttenuation* (nullptr = use asset default)
83
+ ConcurrencyOverride, // USoundConcurrency* (nullptr = use asset default)
84
+ this // OwningActor for per-owner concurrency
85
+ );
86
+ ```
87
+
88
+ ### Spawn with Handle
89
+
90
+ ```cpp
91
+ // Returns UAudioComponent* — auto-destroyed when sound finishes if bAutoDestroy=true
92
+ UAudioComponent* Comp = UGameplayStatics::SpawnSoundAtLocation(
93
+ this, ExplosionSound, Location, FRotator::ZeroRotator,
94
+ 1.0f, 1.0f, 0.0f, AttenuationSettings, nullptr, /*bAutoDestroy=*/true
95
+ );
96
+
97
+ // Attach to a moving component (vehicle engine)
98
+ UAudioComponent* EngineAudio = UGameplayStatics::SpawnSoundAttached(
99
+ EngineLoopSound, GetMesh(), NAME_None,
100
+ FVector::ZeroVector, FRotator::ZeroRotator,
101
+ EAttachLocation::SnapToTargetIncludingScale,
102
+ /*bStopWhenAttachedToDestroyed=*/true,
103
+ 1.0f, 1.0f, 0.0f, AttenuationSettings, nullptr,
104
+ /*bAutoDestroy=*/false // keep alive for looping
105
+ );
106
+ ```
107
+
108
+ ### UAudioComponent as Permanent Actor Component
109
+
110
+ ```cpp
111
+ // In constructor:
112
+ AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("AudioComponent"));
113
+ AudioComponent->SetupAttachment(RootComponent);
114
+ AudioComponent->bAutoActivate = false;
115
+ AudioComponent->bStopWhenOwnerDestroyed = true;
116
+ ```
117
+
118
+ ### Playback Control
119
+
120
+ ```cpp
121
+ AudioComponent->SetSound(EngineLoopSound);
122
+ AudioComponent->Play(/*StartTime=*/0.0f);
123
+ AudioComponent->Stop();
124
+ AudioComponent->SetPaused(true);
125
+ AudioComponent->FadeIn(0.5f, 1.0f, 0.0f, EAudioFaderCurve::Linear);
126
+ AudioComponent->FadeOut(1.0f, 0.0f, EAudioFaderCurve::Linear);
127
+ AudioComponent->SetVolumeMultiplier(0.5f);
128
+ AudioComponent->SetPitchMultiplier(1.2f);
129
+
130
+ // Query play state (EAudioComponentPlayState: Playing, Stopped, Paused, FadingIn, FadingOut)
131
+ EAudioComponentPlayState State = AudioComponent->GetPlayState();
132
+ ```
133
+
134
+ ### Delegates (AudioComponent.h)
135
+
136
+ ```cpp
137
+ // Declared in AudioComponent.h:
138
+ // DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnAudioFinished)
139
+ // DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAudioPlaybackPercent, const USoundWave*, PlayingSoundWave, const float, PlaybackPercent)
140
+ // DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAudioPlayStateChanged, EAudioComponentPlayState, PlayState)
141
+
142
+ AudioComponent->OnAudioFinished.AddDynamic(this, &AMyActor::OnSoundFinished);
143
+ AudioComponent->OnAudioPlaybackPercent.AddDynamic(this, &AMyActor::OnPlaybackPercent);
144
+ AudioComponent->OnAudioPlayStateChanged.AddDynamic(this, &AMyActor::OnPlayStateChanged);
145
+
146
+ // Native (non-UObject) binding — no GC overhead:
147
+ // DECLARE_MULTICAST_DELEGATE_OneParam(FOnAudioFinishedNative, UAudioComponent*)
148
+ // DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnAudioPlaybackPercentNative, const UAudioComponent*, const USoundWave*, const float)
149
+ AudioComponent->OnAudioFinishedNative.AddUObject(this, &AMyActor::OnSoundFinishedNative);
150
+ AudioComponent->OnAudioPlaybackPercentNative.AddUObject(this, &AMyActor::OnPlaybackPercentNative);
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Sound Attenuation (SoundAttenuation.h)
156
+
157
+ Defined in `USoundAttenuation` assets (wrapping `FSoundAttenuationSettings`).
158
+ Assign via `USoundBase::AttenuationSettings` or pass as override to play functions.
159
+
160
+ **Attenuation shapes** (`EAttenuationShape`): `Sphere` (default, omnidirectional), `Capsule` (elongated sources), `Box` (room-shaped), `Cone` (directional like spotlights).
161
+
162
+ **Distance model** (`EAttenuationDistanceModel`): `Linear`, `Logarithmic` (realistic), `NaturalSound` (perception-matched, recommended), `Inverse`, `LogReverse`, `Custom` (curve-driven).
163
+
164
+ ```cpp
165
+ // Key FSoundAttenuationSettings fields:
166
+ uint8 bAttenuate : 1; // enable distance-based volume falloff
167
+ uint8 bSpatialize : 1; // enable 3D spatialization
168
+ // SpatializationAlgorithm: SPATIALIZATION_Default (panning), SPATIALIZATION_HRTF (binaural plugin)
169
+
170
+ uint8 bAttenuateWithLPF : 1; // air absorption (distance-based lowpass)
171
+ float LPFRadiusMin; // LPF starts at this distance (cm)
172
+ float LPFRadiusMax; // LPF fully applied at this distance
173
+ float LPFFrequencyAtMin; // Hz at min distance (e.g. 20000.f = bypass)
174
+ float LPFFrequencyAtMax; // Hz at max distance (e.g. 800.f = muffled)
175
+
176
+ uint8 bEnableListenerFocus : 1;
177
+ float FocusAzimuth; // in-focus cone half-angle (degrees)
178
+ float NonFocusAzimuth; // non-focus cone half-angle (degrees)
179
+ float FocusDistanceScale; // < 1.0 makes focused sound seem closer
180
+ float NonFocusVolumeAttenuation;
181
+
182
+ uint8 bEnableOcclusion : 1;
183
+ TEnumAsByte<ECollisionChannel> OcclusionTraceChannel; // e.g. ECC_Visibility
184
+ float OcclusionLowPassFilterFrequency; // Hz when fully occluded
185
+ float OcclusionVolumeAttenuation; // 0..1 volume scale when occluded
186
+ float OcclusionInterpolationTime; // seconds to interpolate
187
+
188
+ uint8 bEnableReverbSend : 1;
189
+ EReverbSendMethod ReverbSendMethod; // Linear, CustomCurve, Manual
190
+ float ReverbWetLevelMin;
191
+ float ReverbWetLevelMax;
192
+ float ReverbDistanceMin;
193
+ float ReverbDistanceMax;
194
+
195
+ uint8 bEnablePriorityAttenuation : 1; // reduce priority of distant sounds
196
+ float PriorityAttenuationMin;
197
+ float PriorityAttenuationMax;
198
+
199
+ // Override attenuation inline on a UAudioComponent:
200
+ AudioComponent->bOverrideAttenuation = true;
201
+ AudioComponent->AttenuationOverrides.bAttenuate = true;
202
+ AudioComponent->AttenuationOverrides.bSpatialize = true;
203
+ AudioComponent->AttenuationOverrides.FalloffDistance = 3000.f;
204
+ ```
205
+
206
+ ### Audio LOD
207
+
208
+ Distant sounds can skip processing. Use `bAttenuateWithLPF = true` with `LPFRadiusMin`/`LPFRadiusMax`
209
+ to low-pass-filter far sounds before full attenuation drops them. Set `bEnableSendToAudioLink = false`
210
+ for background ambience that does not need external routing. `USoundBase::Priority` (0.0–100.0, default 1.0, higher =
211
+ more important) determines which voices survive when hitting the max channel count set in Audio Settings.
212
+
213
+ ---
214
+
215
+ ## Concurrency (SoundConcurrency.h)
216
+
217
+ `USoundConcurrency` controls simultaneous voice count. Assign via
218
+ `USoundBase::ConcurrencySet` (`TSet<USoundConcurrency*>`) or `ConcurrencyOverrides`
219
+ (inline `FSoundConcurrencySettings` when `bOverrideConcurrency = true`).
220
+
221
+ ```cpp
222
+ // FSoundConcurrencySettings key fields:
223
+ int32 MaxCount; // max simultaneous voices in this group
224
+ // USoundBase::Priority (0.0–100.0, default 1.0) determines which voices survive at MaxCount
225
+ uint8 bLimitToOwner : 1; // limit per owning actor if true
226
+ TEnumAsByte<EMaxConcurrentResolutionRule::Type> ResolutionRule;
227
+ // PreventNew | StopOldest | StopFarthestThenPreventNew | StopFarthestThenOldest
228
+ // StopLowestPriority | StopQuietest | StopLowestPriorityThenPreventNew
229
+ float RetriggerTime; // minimum seconds between plays in this group
230
+ float VoiceStealReleaseTime; // fade duration (s) for evicted sounds
231
+ EConcurrencyVolumeScaleMode VolumeScaleMode; // Default | Distance | Priority
232
+ float VolumeScaleAttackTime;
233
+ float VolumeScaleReleaseTime;
234
+ ```
235
+
236
+ ---
237
+
238
+ ## Submixes and Sound Classes (SoundSubmix.h)
239
+
240
+ ```
241
+ USoundSubmixBase (abstract)
242
+ USoundSubmixWithParentBase
243
+ USoundSubmix // standard submix with effects chain
244
+ USoundfieldSubmix // ambisonics / soundfield
245
+ UEndpointSubmix // external endpoint (haptics, extra device)
246
+ ```
247
+
248
+ Typical tree: Master > {Music, SFX, Voice, Ambient}. Music submix uses `bMuteWhenBackgrounded = true`.
249
+
250
+ ```cpp
251
+ // Runtime volume control:
252
+ MusicSubmix->SetSubmixOutputVolume(this, 0.5f); // linear gain multiplier
253
+ MusicSubmix->SetSubmixWetLevel(this, 1.0f);
254
+ MusicSubmix->SetSubmixDryLevel(this, 0.0f);
255
+
256
+ // Dynamic parenting:
257
+ MyChildSubmix->DynamicConnect(this, MasterSubmix);
258
+ MyChildSubmix->DynamicDisconnect(this);
259
+ ```
260
+
261
+ `USoundSubmix::SubmixEffectChain` holds `USoundEffectSubmixPreset` assets
262
+ (reverb `USubmixEffectReverbPreset`, EQ `USubmixEffectEQPreset`, dynamics).
263
+
264
+ ### Submix Effect Chain
265
+
266
+ ```cpp
267
+ // Add reverb to a submix at runtime
268
+ USoundSubmix* ReverbSubmix = LoadObject<USoundSubmix>(nullptr,
269
+ TEXT("/Game/Audio/Submixes/ReverbSubmix"));
270
+ USubmixEffectReverbPreset* Preset = NewObject<USubmixEffectReverbPreset>();
271
+ Preset->Settings.Density = 0.85f;
272
+ Preset->Settings.Diffusion = 0.8f;
273
+ Preset->Settings.DecayTime = 2.5f;
274
+ ReverbSubmix->SubmixEffectChain.Add(Preset);
275
+ ```
276
+
277
+ **Sound classes** define volume/pitch hierarchy parallel to submixes. Assign via `USoundBase::SoundClassObject`.
278
+
279
+ ```cpp
280
+ // Sound Mix modifiers — layer temporary volume/pitch adjustments by sound class:
281
+ UGameplayStatics::SetBaseSoundMix(this, DefaultMix); // set the base mix (usually once)
282
+ UGameplayStatics::PushSoundMixModifier(this, CombatMix); // push a modifier (stacks)
283
+ // ... later, when leaving combat:
284
+ UGameplayStatics::PopSoundMixModifier(this, CombatMix); // remove the modifier layer
285
+ // ClearSoundMixModifiers removes all pushed modifiers at once
286
+ UGameplayStatics::ClearSoundMixModifiers(this);
287
+ ```
288
+
289
+ `USoundMix` assets define per-`USoundClass` volume and pitch adjustments. Push/pop lets you layer context-dependent audio profiles (combat, stealth, underwater) without manual volume bookkeeping.
290
+
291
+ ---
292
+
293
+ ## MetaSounds
294
+
295
+ `UMetaSoundSource` derives from `USoundBase` — plays anywhere a `USoundBase` is accepted.
296
+
297
+ ```cpp
298
+ // UAudioComponent implements ISoundParameterControllerInterface:
299
+ MetaComp->SetFloatParameter(FName("Pitch"), 1.5f);
300
+ MetaComp->SetBoolParameter(FName("IsUnderwater"), true);
301
+ MetaComp->SetIntParameter(FName("SurfaceType"), 2);
302
+ MetaComp->SetTriggerParameter(FName("OnImpact")); // impulse trigger input
303
+ MetaComp->ResetParameters();
304
+ ```
305
+
306
+ | Criterion | SoundCue | MetaSound |
307
+ |---|---|---|
308
+ | Runtime parameters | Limited (wave params) | Typed inputs, full parameter system |
309
+ | Procedural audio | No | Yes (oscillators, noise, DSP filters) |
310
+ | Reactive to gameplay | Via parameter nodes | Native — bind any float/bool/trigger |
311
+ | Use when | Randomized pre-authored sounds | Adaptive music, procedural SFX, state-driven audio |
312
+
313
+ ---
314
+
315
+ ## Submix Spectrum Analysis and Envelope Following (SoundSubmix.h)
316
+
317
+ ```cpp
318
+ // Envelope following:
319
+ SFXSubmix->StartEnvelopeFollowing(this);
320
+ FOnSubmixEnvelopeBP Env;
321
+ Env.BindDynamic(this, &AMyActor::OnSubmixEnvelope);
322
+ SFXSubmix->AddEnvelopeFollowerDelegate(this, Env);
323
+ SFXSubmix->StopEnvelopeFollowing(this);
324
+ // Callback: void OnSubmixEnvelope(const TArray<float>& Envelope);
325
+
326
+ // Spectrum analysis:
327
+ SFXSubmix->StartSpectralAnalysis(this,
328
+ EFFTSize::Medium, EFFTPeakInterpolationMethod::Linear,
329
+ EFFTWindowType::Hann, 0.0f, EAudioSpectrumType::MagnitudeSpectrum
330
+ );
331
+
332
+ TArray<FSoundSubmixSpectralAnalysisBandSettings> Bands;
333
+ FSoundSubmixSpectralAnalysisBandSettings LowBand;
334
+ LowBand.BandFrequency = 80.f; LowBand.AttackTimeMsec = 10.f; LowBand.ReleaseTimeMsec = 100.f;
335
+ Bands.Add(LowBand);
336
+
337
+ FOnSubmixSpectralAnalysisBP Spectral;
338
+ Spectral.BindDynamic(this, &AMyActor::OnSpectralAnalysis);
339
+ SFXSubmix->AddSpectralAnalysisDelegate(
340
+ this, Bands, Spectral,
341
+ 30.f /*UpdateRateHz*/, -40.f /*DecibelFloor*/, true /*Normalize*/, false /*AutoRange*/
342
+ );
343
+ SFXSubmix->StopSpectralAnalysis(this);
344
+ // Callback: void OnSpectralAnalysis(const TArray<float>& Magnitudes);
345
+ ```
346
+
347
+ ---
348
+
349
+ ## Module Dependencies
350
+
351
+ ```csharp
352
+ // In .Build.cs:
353
+ PublicDependencyModuleNames.AddRange(new string[] { "Engine", "AudioMixer" });
354
+ PublicDependencyModuleNames.Add("MetasoundEngine"); // for MetaSound parameters
355
+ PublicDependencyModuleNames.Add("MetasoundFrontend");
356
+ ```
357
+
358
+ ```cpp
359
+ #include "Components/AudioComponent.h"
360
+ #include "Kismet/GameplayStatics.h"
361
+ #include "Sound/SoundBase.h"
362
+ #include "Sound/SoundCue.h"
363
+ #include "Sound/SoundWave.h"
364
+ #include "Sound/SoundAttenuation.h"
365
+ #include "Sound/SoundConcurrency.h"
366
+ #include "Sound/SoundSubmix.h"
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Audio Analysis
372
+
373
+ ### Submix Spectrum and Envelope
374
+
375
+ See the existing submix analysis section above for real-time analysis via `USoundSubmix`.
376
+
377
+ ### Non-Real-Time Analysis (NRT)
378
+
379
+ `UAudioAnalyzerNRT` is the abstract base class for offline analyzers. `ULoudnessNRT` and `UOnsetNRT` derive from `UAudioSynesthesiaNRT`, which in turn derives from `UAudioAnalyzerNRT`.
380
+
381
+ For offline audio analysis (e.g., beat detection for rhythmic gameplay), use the Audio Synesthesia plugin:
382
+
383
+ ```cpp
384
+ // Build.cs: "AudioSynesthesia"
385
+ #include "AudioSynesthesiaModule.h"
386
+
387
+ // Create an analyzer — LoudnessNRT analyzes an entire sound asset offline
388
+ ULoudnessNRT* Analyzer = NewObject<ULoudnessNRT>();
389
+ ULoudnessNRTSettings* Settings = NewObject<ULoudnessNRTSettings>();
390
+ Settings->AnalysisPeriod = 0.01f; // 10ms windows
391
+
392
+ Analyzer->Settings = Settings;
393
+ Analyzer->Sound = MySoundWave;
394
+ Analyzer->AnalyzeAudio(); // WITH_EDITOR only; call from editor utility or cook-time code
395
+
396
+ // Query results at specific timestamps
397
+ float Loudness;
398
+ Analyzer->GetLoudnessAtTime(1.5f, Loudness);
399
+
400
+ // For beat detection, use OnsetNRT:
401
+ UOnsetNRT* OnsetAnalyzer = NewObject<UOnsetNRT>();
402
+ OnsetAnalyzer->Sound = MySoundWave;
403
+ OnsetAnalyzer->AnalyzeAudio(); // WITH_EDITOR only
404
+ TArray<float> OnsetTimestamps;
405
+ TArray<float> OnsetStrengths;
406
+ OnsetAnalyzer->GetNormalizedChannelOnsetsBetweenTimes(
407
+ 0.f, Duration, 0, OnsetTimestamps, OnsetStrengths);
408
+ ```
409
+
410
+ **Why NRT**: Pre-analyze tracks to generate beat maps, loudness curves, or onset markers. Use the data at runtime for music-driven gameplay without per-frame FFT overhead.
411
+
412
+ ---
413
+
414
+ ## Common Mistakes and Anti-Patterns
415
+
416
+ **Spawning a new AudioComponent every fire event**
417
+ ```cpp
418
+ // WRONG — leaks a component instance per call
419
+ UAudioComponent* Comp = NewObject<UAudioComponent>(this);
420
+ Comp->SetSound(FireSound); Comp->Play();
421
+
422
+ // CORRECT — fire-and-forget for one-shots
423
+ UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation());
424
+ // CORRECT — cache a single component for repeated/looping sounds
425
+ if (!CachedFireAudio) { CachedFireAudio = UGameplayStatics::SpawnSoundAttached(..., /*bAutoDestroy=*/false); }
426
+ CachedFireAudio->Play();
427
+ ```
428
+
429
+ **Playing 3D sounds without attenuation**
430
+ ```cpp
431
+ // WRONG — full volume at any distance
432
+ UGameplayStatics::PlaySoundAtLocation(this, FootstepSound, Location);
433
+ // CORRECT — pass or assign USoundAttenuation with sphere falloff tuned to gameplay scale
434
+ ```
435
+
436
+ **Ignoring concurrency on high-frequency sounds**
437
+ ```cpp
438
+ // WRONG — 20 simultaneous explosions with default concurrency
439
+ UGameplayStatics::PlaySoundAtLocation(this, ExplosionSound, Location);
440
+ // CORRECT — pass USoundConcurrency: MaxCount=4, ResolutionRule=StopFarthestThenOldest
441
+ ```
442
+
443
+ **Playing audio on a dedicated server**
444
+ ```cpp
445
+ // WRONG — FAudioDevice not initialized on server, causes crash/log spam
446
+ void AWeapon::Fire() { UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation()); }
447
+ // CORRECT
448
+ void AWeapon::Fire() {
449
+ if (GetNetMode() != NM_DedicatedServer) {
450
+ UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation());
451
+ }
452
+ }
453
+ ```
454
+
455
+ **Forgetting to unbind delegates before destruction**
456
+ ```cpp
457
+ // In EndPlay:
458
+ if (AudioComponent) { AudioComponent->OnAudioFinished.RemoveAll(this); AudioComponent->Stop(); }
459
+ ```
460
+
461
+ **Using PlaySound2D for in-world sounds**
462
+ ```cpp
463
+ // WRONG — no attenuation or spatialization
464
+ UGameplayStatics::PlaySound2D(this, GunShot);
465
+ // CORRECT
466
+ UGameplayStatics::PlaySoundAtLocation(this, GunShot, GetActorLocation());
467
+ ```
468
+
469
+ ---
470
+
471
+ ## Platform and Edge Case Considerations
472
+
473
+ - **Mobile** — 16–32 voice limit. Use aggressive concurrency. Prefer resident loading for SFX. Disable HRTF unless the platform supports it.
474
+ - **Dedicated servers** — Guard all audio calls with `GetNetMode() != NM_DedicatedServer`.
475
+ - **Streaming audio** — Set `LoadingBehavior = LoadOnDemand` on long music SoundWave assets. Never load minutes of music resident.
476
+ - **App focus loss** — Set `bMuteWhenBackgrounded = true` on music/SFX submixes. For custom handling:
477
+
478
+ ### Focus Loss Handling
479
+
480
+ ```cpp
481
+ // In your GameInstance or AudioManager
482
+ FCoreDelegates::ApplicationWillDeactivateDelegate.AddUObject(
483
+ this, &UMyAudioManager::OnAppDeactivate);
484
+
485
+ void UMyAudioManager::OnAppDeactivate()
486
+ {
487
+ FAudioDeviceHandle Device = GEngine->GetMainAudioDevice();
488
+ if (Device.IsValid()) { Device->SetTransientPrimaryVolume(0.f); }
489
+ }
490
+ ```
491
+
492
+ - **VR** — Enable `bSpatialize = true` and `SpatializationAlgorithm = SPATIALIZATION_HRTF` on all 3D attenuation assets.
493
+ - **Audio LOD** — Use `bEnablePriorityAttenuation` to reduce priority of distant sounds before voice-budget culling.
494
+
495
+ ---
496
+
497
+ ## Related Skills
498
+
499
+ - `/ue-actor-component-architecture` — UAudioComponent lifetime, attachment, and replication patterns
500
+ - `/ue-niagara-effects` — synchronizing audio events with particle system callbacks
501
+ - `/ue-cpp-foundations` — delegate binding patterns, UPROPERTY and UFUNCTION macros
502
+ - `/ue-naming-conventions` — asset prefixes and Content folder layout for these assets
503
+
504
+ ## Reference Files
505
+
506
+ - `references/audio-setup-patterns.md` — attenuation, concurrency and submix setup patterns
507
+
508
+ ---
509
+
510
+ ## Checklist
511
+
512
+ Validate before considering the work done:
513
+
514
+ - [ ] Concurrency and priority are configured so voice count stays bounded
515
+ - [ ] Attenuation settings are shared through assets rather than tuned per instance
516
+ - [ ] Sounds are not started every frame or on every overlap event
517
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
518
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
519
+
520
+ **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.
521
+
522
+ ## Next Steps
523
+
524
+ - `/audio-mix` — place the new sounds in the bus hierarchy (install the `audio` profile: `arcane add +audio`)
525
+ - `/audio-audit` — check voice count, memory and loudness (same profile)
526
+ - `/code-review` — architectural and quality review of the change
527
+ - `/commit` — conventional commit once the change is verified