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,115 @@
1
+ # Niagara VFX — Editor-Side Workflow
2
+
3
+ > Adapted from the `unreal-niagara` skill in [awesome-gamedev-agent-skills](https://github.com/gamedev-skills/awesome-gamedev-agent-skills) (Apache-2.0). Cross-skill references were remapped to Arcane slash commands.
4
+
5
+ Build and control real-time visual effects in UE5 with Niagara: understand the
6
+ System/Emitter/Module hierarchy, expose parameters you can drive from gameplay, and spawn
7
+ effects at runtime. Targets **UE 5.8**. (Niagara replaces the legacy Cascade system.)
8
+
9
+ ## When to use
10
+
11
+ - Use when creating a Niagara System (`NS_`) and Emitters (`NE_`), wiring modules in the
12
+ spawn/update stages, exposing **User** parameters to gameplay, or spawning/driving an effect
13
+ (impact, muzzle flash, fire, magic) from Blueprint or C++.
14
+ - Use when the project has Niagara `NS_`/`NE_` assets or references `UNiagaraComponent`.
15
+
16
+ **When *not* to use:** material/shader authoring (the look of a surface, not particles) is a
17
+ separate topic; `shader-programming` covers cross-engine shader concepts. Audio for the effect
18
+ → `audio-design`.
19
+
20
+ ## Core workflow
21
+
22
+ 1. **Understand the hierarchy.** A **Niagara System** (`NS_`) is the effect you place/spawn; it
23
+ contains one or more **Emitters** (`NE_`, often emitter *templates*). Each emitter runs in
24
+ stages: **Emitter Spawn/Update**, **Particle Spawn/Update**, optional **Event Handler**, and
25
+ **Render**.
26
+ 2. **Build behaviour from Modules**, which execute top-to-bottom in each stage (Spawn Rate,
27
+ Add Velocity, Gravity Force, Color over Life, etc.). Order matters — a later module reads the
28
+ values earlier ones wrote.
29
+ 3. **Know the parameter namespaces:** `System`, `Emitter`, `Particle`, and **`User`**. Only
30
+ **User-namespace** parameters are exposed to and settable from Blueprint/C++; the others are
31
+ internal to the simulation.
32
+ 4. **Spawn at runtime** with `UNiagaraFunctionLibrary::SpawnSystemAtLocation` (world position)
33
+ or `SpawnSystemAttached` (follows a component/socket), which return a `UNiagaraComponent`.
34
+ 5. **Drive the effect** by setting its User parameters on the returned component (color, spawn
35
+ rate, a target position) and `Activate`/`Deactivate` it.
36
+ 6. **Verify** in the Niagara editor preview and in-level; check bounds (especially GPU
37
+ emitters), and confirm the effect culls/destroys correctly.
38
+
39
+ ## Patterns
40
+
41
+ ### 1. Spawn a one-shot effect at a world location (C++)
42
+
43
+ ```cpp
44
+ #include "NiagaraFunctionLibrary.h"
45
+ #include "NiagaraComponent.h"
46
+
47
+ // ImpactSystem is a UPROPERTY(EditAnywhere) TObjectPtr<UNiagaraSystem>.
48
+ void AProjectile::SpawnImpact(const FVector& Location, const FRotator& Rotation)
49
+ {
50
+ UNiagaraComponent* FX = UNiagaraFunctionLibrary::SpawnSystemAtLocation(
51
+ GetWorld(), ImpactSystem, Location, Rotation);
52
+ // FX auto-destroys when finished for a one-shot (system marked non-looping).
53
+ }
54
+ ```
55
+
56
+ ### 2. Spawn attached to a socket (muzzle flash that follows the gun)
57
+
58
+ ```cpp
59
+ UNiagaraComponent* Muzzle = UNiagaraFunctionLibrary::SpawnSystemAttached(
60
+ MuzzleSystem, WeaponMesh, FName("MuzzleSocket"),
61
+ FVector::ZeroVector, FRotator::ZeroRotator,
62
+ EAttachLocation::SnapToTarget, /*bAutoDestroy*/ true);
63
+ ```
64
+
65
+ ### 3. Drive an exposed User parameter at runtime
66
+
67
+ ```cpp
68
+ // Only User-namespace parameters can be set from gameplay. Names match the User parameter.
69
+ if (UNiagaraComponent* Fire = UNiagaraFunctionLibrary::SpawnSystemAttached(
70
+ FireSystem, RootComponent, NAME_None, FVector::ZeroVector, FRotator::ZeroRotator,
71
+ EAttachLocation::KeepRelativeOffset, /*bAutoDestroy*/ false))
72
+ {
73
+ Fire->SetVariableFloat(FName("SpawnRate"), 250.f); // User.SpawnRate
74
+ Fire->SetVariableLinearColor(FName("FireColor"), FLinearColor::Red);
75
+ }
76
+ ```
77
+
78
+ ### 4. Blueprint equivalent (node flow)
79
+
80
+ ```text
81
+ Spawn System at Location (System = NS_Impact, Location, Rotation) -> returns Niagara Component
82
+ On the returned component:
83
+ Set Niagara Variable (Float) Name="SpawnRate" Value=250
84
+ Set Niagara Variable (LinearColor) Name="FireColor" Value=Red
85
+ ```
86
+
87
+ ## Pitfalls
88
+
89
+ - **Trying to set a System/Emitter/Particle parameter from gameplay** — it won't take. Expose
90
+ it in the **User** namespace; only User parameters are settable via the component.
91
+ - **Using Cascade tutorials** — Cascade is legacy/deprecated. Niagara is the current system; the
92
+ emitter/module workflow differs.
93
+ - **Effect disappears or doesn't cull right** — fixed/incorrect bounds, especially for **GPU
94
+ Compute** emitters which need explicit Fixed Bounds. Set bounds on the emitter/system.
95
+ - **Looping effect never stops** — spawned with `bAutoDestroy = false` and never
96
+ `Deactivate()`d; manage the returned component's lifetime, or mark the system non-looping for
97
+ one-shots.
98
+ - **GPU sim can't drive gameplay** — GPU particle data isn't readily read back to the CPU;
99
+ collision/events that gameplay must react to should use CPU emitters (or Niagara → gameplay
100
+ via the data interface), not GPU.
101
+ - **Module order bugs** — a Force/Velocity module placed before the one that initializes the
102
+ value reads zero. Mind the top-to-bottom stack order.
103
+
104
+ ## References
105
+
106
+ - Primary docs: "Overview of Niagara Effects"
107
+ (`https://dev.epicgames.com/documentation/en-us/unreal-engine/overview-of-niagara-effects-for-unreal-engine`)
108
+ and the `UNiagaraFunctionLibrary` / `UNiagaraComponent` API. Add the `Niagara` module to
109
+ `*.Build.cs` for C++ access.
110
+
111
+ ## Related skills
112
+
113
+ - `shader-programming` — material/shader concepts for particle materials.
114
+ - `/ue-cpp-foundations` — spawning effects from gameplay code and module setup.
115
+ - `/ue-blueprints` — triggering effects from visual scripts.
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: ue-packaging
3
+ description: "Packaging and cooking — build configurations, cook vs package, Game Default Map, RunUAT BuildCookRun, platform SDKs"
4
+ category: "gamedev"
5
+ argument-hint: "[platform o build config]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Packaging & Cooking
11
+
12
+ Turn a UE5 project into a runnable, distributable build: choose the right build configuration, cook content, set the launch map, and package — from the editor or the command line.
13
+
14
+ Ask before writing: this skill edits `Config/Default*.ini`, packaging settings and CI build scripts. Propose the change and get approval before using Write or Edit.
15
+
16
+ ## Context Check
17
+
18
+ Read `docs/unreal/project-context.md` before proceeding. Confirm:
19
+
20
+ - Engine version and whether the project is Blueprint-only (`DebugGame` is unavailable there)
21
+ - Target platforms and which platform SDKs are actually installed
22
+ - Whether builds run locally, on CI, or both — this decides editor flow vs `RunUAT`
23
+
24
+ ## When to Use
25
+
26
+ - Producing a build (test or release), choosing Development vs Shipping, cooking content, configuring Packaging / Maps & Modes settings, or automating builds with `RunUAT BuildCookRun` for CI.
27
+ - The goal is a packaged player rather than running in-editor.
28
+
29
+ **When not to use:** storefront submission and release process → `/release-checklist`. Editor-time gameplay iteration is not packaging.
30
+
31
+ ## Core Workflow
32
+
33
+ 1. **Set the launch map.** Project Settings → **Maps & Modes** → **Game Default Map** is what a packaged build loads first. Wrong or empty here is the most common "packaged game is black" cause.
34
+ 2. **Pick the build configuration.** **Development** (default; optimized but keeps logging/stats/console for testing) vs **Shipping** (all optimizations, debugging tools stripped — for release). `DebugGame`/`Debug` are for debugging engine/game code and aren't for distribution; `DebugGame` isn't available for Blueprint-only projects.
35
+ 3. **Understand cook vs package.** **Cooking** converts assets to the target platform's format and packs them into `.pak` files. **Packaging** bundles the compiled executable plus cooked content into a standalone, distributable set of files. Packaging runs a cook as part of it.
36
+ 4. **Package from the editor:** the **Platforms** menu → choose the platform → set the Binary Configuration → **Package Project** → pick an output folder.
37
+ 5. **Or build from the command line** with the Unreal Automation Tool (`RunUAT BuildCookRun`) for repeatable and CI builds.
38
+ 6. **Tune Packaging settings** (Project Settings → **Packaging**): which maps and directories to cook, full-rebuild, compression, and whether to build all maps.
39
+ 7. **Verify by running the packaged build**, not just by a successful cook — launch the executable and confirm it loads the right map and runs.
40
+
41
+ ## Patterns
42
+
43
+ ### 1. Editor packaging (the menu path)
44
+
45
+ ```text
46
+ Platforms (toolbar)
47
+ -> Windows
48
+ -> Binary Configuration -> Development | Shipping
49
+ -> Content Management -> Package Project
50
+ -> choose/confirm the staging output folder
51
+ ```
52
+
53
+ ### 2. Command-line build with UAT (CI-friendly)
54
+
55
+ ```bash
56
+ # Cook + build + stage + pak + archive a Shipping Windows build.
57
+ RunUAT BuildCookRun \
58
+ -project="C:/Path/MyGame.uproject" \
59
+ -noP4 -platform=Win64 -clientconfig=Shipping \
60
+ -cook -allmaps -build -stage -pak -archive \
61
+ -archivedirectory="C:/Builds/MyGame"
62
+ ```
63
+
64
+ `RunUAT` lives in `Engine/Build/BatchFiles/` (`RunUAT.bat` on Windows, `RunUAT.sh` on macOS/Linux). Drop `-allmaps` and pass `-map=Map1+Map2` to cook a subset.
65
+
66
+ ### 3. Cook only (no packaging), e.g. to refresh content
67
+
68
+ ```bash
69
+ RunUAT BuildCookRun -project="C:/Path/MyGame.uproject" -noP4 \
70
+ -platform=Win64 -clientconfig=Development -cook -skipstage
71
+ ```
72
+
73
+ ## Common Mistakes
74
+
75
+ - **Packaged build loads a black or empty level** — Game Default Map isn't set, or that map wasn't cooked. Set it in Maps & Modes and ensure it's included in the cook.
76
+ - **Shipping a Development build** — Development keeps logging/console/stats and is slower; ship **Shipping**. Conversely, Shipping strips `UE_LOG` and the console, so debugging a Shipping-only issue needs Development or `Test`.
77
+ - **A referenced map or asset is missing at runtime** — it wasn't cooked. Add it to the Packaging settings' maps/directories to cook, or cook all maps.
78
+ - **Build fails on the platform** — the platform SDK or toolchain isn't installed (Windows build tools, Android SDK/NDK, console SDKs). Install the platform's prerequisites.
79
+ - **Expecting Blueprint Nativization** — it was **removed in UE5**. Don't rely on it for performance; profile and move hot logic to C++ instead.
80
+ - **First cook is very slow** — shaders and all assets cook from scratch, and subsequent cooks are incremental. Don't mistake a slow first cook for a hang.
81
+ - **Cooking secrets into the build** — config files staged into a packaged build are readable. Keep credentials out of `Config/`.
82
+
83
+ ## Reference Files
84
+
85
+ Primary docs: [Packaging Your Project](https://dev.epicgames.com/documentation/en-us/unreal-engine/packaging-your-project), plus the Build Configurations and `BuildCookRun` references.
86
+
87
+ ---
88
+
89
+ ## Related Skills
90
+
91
+ - `/ue-module-build-system` — `Build.cs`/`Target.cs` and module wiring that packaging depends on
92
+ - `/ue-cpp-foundations` — moving hot logic to C++ now that BP nativization is gone
93
+ - `/ue-data-assets-tables` — Asset Manager and Primary Asset types that drive what gets cooked
94
+ - `/ue-testing-debugging` — automation tests that should gate a release build
95
+
96
+ ---
97
+
98
+ ## Checklist
99
+
100
+ Validate before considering the work done:
101
+
102
+ - [ ] Game Default Map is set and included in the cook
103
+ - [ ] Build configuration matches the intent (Shipping for release, Development for testing)
104
+ - [ ] The packaged executable was launched and verified, not just cooked successfully
105
+ - [ ] No credentials or internal config were staged into the build
106
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
107
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
108
+
109
+ **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 produces a broken or unshippable build; fix it before handing the work over.
110
+
111
+ ## Next Steps
112
+
113
+ - `/release-checklist` — full release gate before distribution
114
+ - `/patch-notes` — user-facing notes for the packaged build
115
+ - `/code-review` — architectural and quality review of the change
116
+ - `/commit` — conventional commit once the change is verified
@@ -0,0 +1,423 @@
1
+ ---
2
+ name: ue-physics-collision
3
+ description: "Collision detection, traces, physics simulation, physical interactions, Chaos physics"
4
+ category: "gamedev"
5
+ argument-hint: "[interaction o collision setup]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Physics & Collision
11
+
12
+ You are an expert in Unreal Engine's physics and collision systems, including collision channels, trace queries, collision events, physics bodies, and the Chaos physics engine.
13
+
14
+ Ask before writing: this skill edits collision presets, physics assets and trace code. Propose the change and get approval before using Write or Edit.
15
+
16
+ ---
17
+
18
+ ## Step 1: Read Project Context
19
+
20
+ Read `docs/unreal/project-context.md` to confirm:
21
+ - UE version (Chaos is the default physics backend from UE 5.0; PhysX was deprecated)
22
+ - Which modules need `"PhysicsCore"` and `"Engine"` in their `Build.cs`
23
+ - Whether the project uses skeletal meshes with physics assets, or primarily static mesh collision
24
+ - Dedicated server targets (affects whether physics simulation should run server-side)
25
+
26
+ ---
27
+
28
+ ## Step 2: Identify the Need
29
+
30
+ Ask which area applies if not stated:
31
+ 1. **Collision setup** — channels, profiles, responses on components
32
+ 2. **Trace queries** — line traces, sweeps, overlap queries for gameplay logic
33
+ 3. **Collision events** — OnComponentHit, OnBeginOverlap, OnEndOverlap delegates
34
+ 4. **Physics simulation** — rigid body sim, forces, impulses, damping, constraints
35
+ 5. **Physical materials** — friction, restitution, surface type detection
36
+
37
+ ---
38
+
39
+ ## Collision Channels & Profiles
40
+
41
+ ### ECollisionChannel — built-in channels
42
+
43
+ ```cpp
44
+ ECC_WorldStatic, ECC_WorldDynamic, ECC_Pawn, ECC_PhysicsBody,
45
+ ECC_Vehicle, ECC_Destructible // object channels (what an object IS)
46
+ ECC_Visibility, ECC_Camera // trace channels (used for queries)
47
+ // Custom: ECC_GameTraceChannel1..ECC_GameTraceChannel18
48
+ ```
49
+
50
+ **Responses**: `ECR_Ignore` / `ECR_Overlap` (events, no block) / `ECR_Block` (physical block + events).
51
+
52
+ **Built-in profiles**: `BlockAll`, `BlockAllDynamic`, `OverlapAll`, `OverlapAllDynamic`, `Pawn`, `PhysicsActor`, `NoCollision`.
53
+
54
+ ### Setting Collision in C++
55
+
56
+ ```cpp
57
+ MyMesh->SetCollisionProfileName(TEXT("BlockAll")); // preferred — sets all at once
58
+ MyMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
59
+ // ECollisionEnabled: NoCollision | QueryOnly | PhysicsOnly | QueryAndPhysics
60
+ MyMesh->SetCollisionObjectType(ECC_PhysicsBody);
61
+ MyMesh->SetCollisionResponseToAllChannels(ECR_Block);
62
+ MyMesh->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
63
+ MyMesh->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);
64
+ ```
65
+
66
+ ### Object Type Channels vs Trace Channels
67
+
68
+ **Object type channels** describe what an actor IS (Pawn, WorldDynamic, Vehicle). Every component has exactly one object type. **Trace channels** are used for queries — they define what a trace is LOOKING FOR (Visibility, Camera, Weapon). This distinction determines which query function to use: `ByObjectType` matches the target's object type channel; `ByChannel` uses the querier's trace channel and checks responses. Most gameplay traces use trace channels (`ECC_Visibility`, custom `Weapon`); overlap queries for "find all pawns" use object type (`ECC_Pawn`).
69
+
70
+ ### Custom Channels — DefaultEngine.ini
71
+
72
+ ```ini
73
+ [/Script/Engine.CollisionProfile]
74
+ +DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=True,bStaticObject=False,Name="Weapon")
75
+ +DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="Interactable")
76
+ +Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Interactable",CustomResponses=((Channel="Weapon",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Block)))
77
+ ```
78
+
79
+ `bTraceType=True` = trace channel; `bTraceType=False` = object type channel. They use separate query functions.
80
+
81
+ See `references/collision-channel-setup.md` for full profile examples.
82
+
83
+ ---
84
+
85
+ ## Trace Queries
86
+
87
+ ### FCollisionQueryParams
88
+
89
+ ```cpp
90
+ FCollisionQueryParams Params;
91
+ Params.TraceTag = TEXT("WeaponTrace"); // for profiling/debug
92
+ Params.bTraceComplex = false; // false=simple hull (fast); true=per-poly (expensive)
93
+ Params.bReturnPhysicalMaterial = true; // populates Hit.PhysMaterial
94
+ Params.bReturnFaceIndex = false; // expensive, only when needed
95
+ Params.AddIgnoredActor(this);
96
+ Params.AddIgnoredComponent(MyComp);
97
+ ```
98
+
99
+ ### World-Level Trace Functions (C++) — from `WorldCollision.h` via `UWorld`
100
+
101
+ ```cpp
102
+ FHitResult Hit;
103
+ // By trace channel
104
+ GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Visibility, Params);
105
+ GetWorld()->LineTraceMultiByChannel(Hits, Start, End, ECC_Visibility, Params);
106
+ // By object type
107
+ FCollisionObjectQueryParams ObjParams(ECC_PhysicsBody);
108
+ ObjParams.AddObjectTypesToQuery(ECC_WorldDynamic);
109
+ GetWorld()->LineTraceSingleByObjectType(Hit, Start, End, ObjParams, Params);
110
+ // By profile
111
+ GetWorld()->LineTraceSingleByProfile(Hit, Start, End, TEXT("BlockAll"), Params);
112
+ ```
113
+
114
+ ### Sweep Queries — FCollisionShape (from `CollisionShape.h`)
115
+
116
+ ```cpp
117
+ FCollisionShape Sphere = FCollisionShape::MakeSphere(30.f);
118
+ FCollisionShape Box = FCollisionShape::MakeBox(FVector(50.f, 50.f, 50.f));
119
+ FCollisionShape Capsule = FCollisionShape::MakeCapsule(34.f, 88.f); // radius, half-height
120
+
121
+ GetWorld()->SweepSingleByChannel(Hit, Start, End, FQuat::Identity, ECC_Pawn, Sphere, Params);
122
+ GetWorld()->SweepMultiByChannel(Hits, Start, End, FQuat::Identity, ECC_Pawn, Sphere, Params);
123
+ GetWorld()->SweepSingleByObjectType(Hit, Start, End, FQuat::Identity, ObjParams, Sphere, Params);
124
+ GetWorld()->SweepSingleByProfile(Hit, Start, End, FQuat::Identity, TEXT("Pawn"), Sphere, Params);
125
+ ```
126
+
127
+ ### Overlap Queries
128
+
129
+ ```cpp
130
+ TArray<FOverlapResult> Overlaps;
131
+ GetWorld()->OverlapMultiByObjectType(Overlaps, Center, FQuat::Identity,
132
+ FCollisionObjectQueryParams(ECC_Pawn), FCollisionShape::MakeSphere(500.f), Params);
133
+ for (const FOverlapResult& R : Overlaps) { AActor* A = R.GetActor(); }
134
+
135
+ // By trace channel (uses channel responses, not object type matching):
136
+ GetWorld()->OverlapMultiByChannel(
137
+ Overlaps, Center, FQuat::Identity, ECC_Pawn,
138
+ FCollisionShape::MakeSphere(Radius), QueryParams);
139
+ ```
140
+
141
+ ### FHitResult — Key Fields
142
+
143
+ ```cpp
144
+ Hit.bBlockingHit; // true if blocking
145
+ Hit.ImpactPoint; // world space contact point
146
+ Hit.ImpactNormal; // surface normal
147
+ Hit.Distance; // from Start to impact
148
+ Hit.BoneName; // skeletal mesh bone
149
+ Hit.GetActor();
150
+ Hit.GetComponent();
151
+ // Physical material (requires bReturnPhysicalMaterial=true):
152
+ if (UPhysicalMaterial* M = Hit.PhysMaterial.Get())
153
+ EPhysicalSurface S = UPhysicalMaterial::DetermineSurfaceType(M);
154
+ ```
155
+
156
+ ### Blueprint-Layer Traces (UKismetSystemLibrary)
157
+
158
+ ```cpp
159
+ #include "Kismet/KismetSystemLibrary.h"
160
+ TArray<AActor*> Ignore = { this };
161
+ // LineTrace with debug draw (ETraceTypeQuery maps to ECollisionChannel)
162
+ UKismetSystemLibrary::LineTraceSingle(this, Start, End,
163
+ ETraceTypeQuery::TraceTypeQuery1, false, Ignore, EDrawDebugTrace::ForDuration, Hit, true);
164
+ // SphereTrace
165
+ UKismetSystemLibrary::SphereTraceSingle(this, Start, End, 50.f,
166
+ ETraceTypeQuery::TraceTypeQuery1, false, Ignore, EDrawDebugTrace::ForOneFrame, Hit, true);
167
+ // By profile
168
+ UKismetSystemLibrary::LineTraceSingleByProfile(this, Start, End,
169
+ TEXT("BlockAll"), false, Ignore, EDrawDebugTrace::None, Hit, true);
170
+ ```
171
+
172
+ ### Async Traces
173
+
174
+ ```cpp
175
+ FTraceHandle Handle = GetWorld()->AsyncLineTraceByChannel(
176
+ EAsyncTraceType::Single, Start, End, ECC_Visibility, Params);
177
+ // Read next frame:
178
+ FTraceDatum Datum;
179
+ if (GetWorld()->QueryTraceData(Handle, Datum) && Datum.OutHits.Num() > 0)
180
+ FHitResult& Hit = Datum.OutHits[0];
181
+ ```
182
+
183
+ ### Debug Visualization
184
+
185
+ ```cpp
186
+ #if ENABLE_DRAW_DEBUG
187
+ DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 2.f);
188
+ DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 10.f, 12, FColor::Green, false, 2.f);
189
+ #endif
190
+ ```
191
+
192
+ `DrawDebugLine` / `DrawDebugSphere` are from `DrawDebugHelpers.h`. Wrap in `ENABLE_DRAW_DEBUG` so they compile out in shipping builds. The bool param is `bPersistentLines`; the float param is `LifeTime` in seconds.
193
+
194
+ See `references/trace-patterns.md` for full gameplay patterns (hitscan, melee sweep, AoE, ground detection, async sensors).
195
+
196
+ ---
197
+
198
+ ## Collision Events
199
+
200
+ Delegate declarations from `PrimitiveComponent.h`:
201
+ - `OnComponentHit` — `(HitComp, OtherActor, OtherComp, NormalImpulse, FHitResult)` — physics collision
202
+ - `OnComponentBeginOverlap` — `(OverlappedComp, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult)`
203
+ - `OnComponentEndOverlap` — `(OverlappedComp, OtherActor, OtherComp, OtherBodyIndex)`
204
+
205
+ ```cpp
206
+ // Hit events (physics collision)
207
+ MyMesh->SetNotifyRigidBodyCollision(true); // "Simulation Generates Hit Events"
208
+ MyMesh->OnComponentHit.AddDynamic(this, &AMyActor::OnHit);
209
+
210
+ UFUNCTION()
211
+ void AMyActor::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor,
212
+ UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) {}
213
+
214
+ // Overlap events — SetGenerateOverlapEvents(true) REQUIRED on BOTH components
215
+ MyMesh->SetGenerateOverlapEvents(true);
216
+ MyMesh->OnComponentBeginOverlap.AddDynamic(this, &AMyActor::OnBeginOverlap);
217
+ MyMesh->OnComponentEndOverlap.AddDynamic(this, &AMyActor::OnEndOverlap);
218
+
219
+ UFUNCTION()
220
+ void AMyActor::OnBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
221
+ UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) {}
222
+
223
+ UFUNCTION()
224
+ void AMyActor::OnEndOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
225
+ UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) {}
226
+ ```
227
+
228
+ **Requirements:** Hit: `QueryAndPhysics`, `ECR_Block` on both, `SetNotifyRigidBodyCollision(true)`. Overlap: `ECR_Overlap` on both, `SetGenerateOverlapEvents(true)` on both.
229
+
230
+ ---
231
+
232
+ ## Physics Bodies
233
+
234
+ ```cpp
235
+ // Enable simulation (PrimitiveComponent.h / BodyInstanceCore.h)
236
+ MyMesh->SetSimulatePhysics(true);
237
+ MyMesh->SetEnableGravity(true);
238
+ MyMesh->SetMassOverrideInKg(NAME_None, 50.f, true); // 50 kg
239
+ MyMesh->SetLinearDamping(0.1f);
240
+ MyMesh->SetAngularDamping(0.05f);
241
+ float Mass = MyMesh->GetMass();
242
+
243
+ // Forces and impulses
244
+ MyMesh->AddImpulse(FVector(0,0,1000), NAME_None, false); // bVelChange=true ignores mass
245
+ MyMesh->AddImpulseAtLocation(FVector(500,0,0), HitPoint); // adds torque
246
+ MyMesh->AddForce(FVector(0,0,9800), NAME_None, false); // continuous (per tick)
247
+ MyMesh->AddRadialImpulse(Center, 500.f, 2000.f, RIF_Linear, false);
248
+ MyMesh->SetPhysicsLinearVelocity(FVector(0,0,300)); // use sparingly
249
+ ```
250
+
251
+ **FBodyInstanceCore key flags** (set via UPROPERTY/editor): `bSimulatePhysics`, `bOverrideMass`, `bEnableGravity`, `bAutoWeld`, `bStartAwake`, `bGenerateWakeEvents`, `bUpdateKinematicFromSimulation`.
252
+
253
+ **Collision complexity** (`BodySetupEnums.h`): `CTF_UseDefault`, `CTF_UseSimpleAndComplex`, `CTF_UseSimpleAsComplex`, `CTF_UseComplexAsSimple` (expensive, static only for physics).
254
+
255
+ ### Physics Constraints
256
+
257
+ ```cpp
258
+ UPhysicsConstraintComponent* C = NewObject<UPhysicsConstraintComponent>(this);
259
+ C->SetupAttachment(RootComponent);
260
+ C->SetConstrainedComponents(MeshA, NAME_None, MeshB, NAME_None);
261
+ C->SetAngularSwing1Limit(EAngularConstraintMotion::ACM_Limited, 45.f);
262
+ C->SetAngularTwistLimit(EAngularConstraintMotion::ACM_Free, 0.f);
263
+ C->SetLinearXLimit(ELinearConstraintMotion::LCM_Locked, 0.f);
264
+ C->RegisterComponent();
265
+ ```
266
+
267
+ **Named constraint presets** (set via `ConstraintProfile` or editor Preset dropdown):
268
+
269
+ | Preset | Angular Limits | Linear Limits |
270
+ |---|---|---|
271
+ | Fixed | All locked | All locked |
272
+ | Hinge | One axis free | All locked |
273
+ | Prismatic | All locked | One axis free |
274
+ | Ball-and-Socket | All free | All locked |
275
+
276
+ ---
277
+
278
+ ## Physical Materials (UPhysicalMaterial)
279
+
280
+ From `PhysicalMaterials/PhysicalMaterial.h`:
281
+
282
+ ```cpp
283
+ float Friction; // kinetic (0 = frictionless)
284
+ float StaticFriction; // before sliding starts
285
+ float Restitution; // 0 (no bounce) to 1 (elastic)
286
+ float Density; // g/cm^3 — used to compute mass from shape volume
287
+ EPhysicalSurface SurfaceType; // SurfaceType_Default, SurfaceType1..SurfaceType62
288
+ // FrictionCombineMode / RestitutionCombineMode: Average, Min, Multiply, Max
289
+
290
+ // Runtime override
291
+ MyMesh->SetPhysMaterialOverride(MyPhysMaterial);
292
+
293
+ // Detect surface from trace (requires bReturnPhysicalMaterial=true)
294
+ if (UPhysicalMaterial* M = Hit.PhysMaterial.Get())
295
+ {
296
+ EPhysicalSurface S = UPhysicalMaterial::DetermineSurfaceType(M);
297
+ switch (S) { case SurfaceType1: /* Metal */ break; }
298
+ }
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Chaos Physics (UE5)
304
+
305
+ UE5 uses **Chaos** by default (PhysX removed). Key architecture:
306
+ - `FChaosScene` (`ChaosScene.h`) owns the solver: `StartFrame()`, `SetUpForFrame()`, `EndFrame()`.
307
+ - Physics runs on a dedicated thread; game thread reads results at sync points.
308
+ - **Substepping**: enabled per Project Settings > Physics (`MaxSubsteps`, `MaxSubstepDeltaTime`). Enable when small/fast objects tunnel through thin geometry — substepping divides the physics tick into smaller increments so collisions are not missed.
309
+ - **Async physics**: runs simulation on a separate thread with one-frame latency. Enable via `UPhysicsSettings::bTickPhysicsAsync`. Use `UAsyncPhysicsInputComponent` on components that need physics-thread input callbacks.
310
+
311
+ Key `UPhysicsSettingsCore` fields (`PhysicsSettingsCore.h`):
312
+ ```cpp
313
+ float DefaultGravityZ; // -980 cm/s^2 default
314
+ float BounceThresholdVelocity; // min velocity to bounce
315
+ float MaxAngularVelocity; // rad/s cap
316
+ float MaxDepenetrationVelocity;
317
+ float ContactOffsetMultiplier; // contact shell size
318
+ FChaosSolverConfiguration SolverOptions;
319
+ ```
320
+
321
+ **EPhysicalSurface**: 62 configurable slots (`SurfaceType1..SurfaceType62`) mapped in Project Settings > Physics > Physical Surface.
322
+
323
+ **Geometry Collections (Chaos Destructibles)**: use `UGeometryCollectionComponent`. Fracture thresholds driven by `FPhysicalMaterialStrength` (TensileStrength, CompressionStrength, ShearStrength) and `FPhysicalMaterialDamageModifier` (DamageThresholdMultiplier) on `UPhysicalMaterial`.
324
+
325
+ ---
326
+
327
+ ### Cloth Simulation
328
+
329
+ ```cpp
330
+ // Cloth uses UClothingAssetBase attached to USkeletalMeshComponent
331
+ // Enable in Mesh asset: Clothing → Add Clothing Data
332
+ // C++ access:
333
+ USkeletalMeshComponent* Mesh = GetMesh();
334
+ if (UClothingSimulationInteractor* Cloth = Mesh->GetClothingSimulationInteractor())
335
+ {
336
+ Cloth->PhysicsAssetUpdated(); // re-sync after physics asset change
337
+ Cloth->SetAnimDriveSpringStiffness(10.f); // blend anim ↔ cloth
338
+ }
339
+ ```
340
+
341
+ ### Field System
342
+
343
+ Field System actors apply forces, strain, and anchors to Chaos destruction and cloth:
344
+
345
+ ```cpp
346
+ // Place AFieldSystemActor in level, add field nodes:
347
+ // URadialFalloff — distance-based falloff
348
+ // URadialVector — directional force from center
349
+ // UUniformVector — constant directional force
350
+ // UBoxFalloff — box-shaped field region
351
+
352
+ // Trigger destruction at runtime:
353
+ AFieldSystemActor* FieldActor = GetWorld()->SpawnActor<AFieldSystemActor>();
354
+ URadialFalloff* Falloff = NewObject<URadialFalloff>(FieldActor);
355
+ Falloff->SetRadialFalloff(1000000.f, 0.8f, 1.f, 0.f, 500.f, FVector::ZeroVector, EFieldFalloffType::Field_Falloff_Linear);
356
+ UFieldSystemMetaDataFilter* Meta = NewObject<UFieldSystemMetaDataFilter>(FieldActor);
357
+ Meta->SetMetaDataFilterType(EFieldFilterType::Field_Filter_All, EFieldObjectType::Field_Object_All, EFieldPositionType::Field_Position_CenterOfMass);
358
+ FieldActor->GetFieldSystemComponent()->ApplyPhysicsField(true, EFieldPhysicsType::Field_ExternalClusterStrain, Meta, Falloff);
359
+ ```
360
+
361
+ ---
362
+
363
+ ## Common Mistakes & Anti-Patterns
364
+
365
+ **Wrong collision responses**: Overlap events require `ECR_Overlap` AND `bGenerateOverlapEvents=true` on BOTH components.
366
+
367
+ **Traces every Tick on many actors**: Use async traces or throttle to 5–10 Hz with a timer.
368
+
369
+ **QueryOnly vs PhysicsOnly confusion**: `QueryOnly` = traces only, no physics forces. `PhysicsOnly` = forces only, traces skip it. Use `QueryAndPhysics` for both.
370
+
371
+ **Complex collision in traces**: `bTraceComplex=true` is 4–10x more expensive. Default `false`; only enable for precise terrain interaction.
372
+
373
+ **Missing `SetNotifyRigidBodyCollision`**: `OnComponentHit` will never fire without it — this flag ("Simulation Generates Hit Events") is separate from collision response.
374
+
375
+ **Sweep vs overlap**: Sweep = shape moving along a path (movement, projectile). Overlap = shape at fixed point (AoE, proximity). Don't substitute one for the other.
376
+
377
+ **Physics on dedicated servers**: Disable skeletal ragdolls with `bSimulateSkeletalMeshOnDedicatedServer=false` unless server accuracy is required.
378
+
379
+ ### Multiplayer & Replicated Actor Collision
380
+
381
+ In multiplayer, physics simulation runs on the server. Collision events (`OnComponentHit`, `OnBeginOverlap`) fire on the server only by default — clients do not receive these events unless you replicate them explicitly via RPCs. Clients see physics-simulated actor positions via `FRepMovement` (the replicated transform + velocity struct behind `bReplicateMovement`). Setting `bReplicateMovement = true` on an actor syncs its transform and linear/angular velocity; the underlying physics state itself is not replicated. For client-predicted physics (e.g., projectiles), simulate locally on the client and reconcile with server authority on correction. Cosmetic-only physics — ragdolls, debris, environmental props — can simulate on clients independently without server involvement, since visual fidelity matters more than authority.
382
+
383
+ ---
384
+
385
+ ## Required Module Dependencies
386
+
387
+ ```csharp
388
+ // Build.cs
389
+ PublicDependencyModuleNames.AddRange(new string[] {
390
+ "Core", "CoreUObject",
391
+ "Engine", // UPrimitiveComponent, FHitResult, UWorld trace API
392
+ "PhysicsCore", // UPhysicalMaterial, FCollisionShape, FBodyInstanceCore
393
+ });
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Related Skills
399
+
400
+ - `/ue-actor-component-architecture` — `UPrimitiveComponent` lifecycle, attachment, registration
401
+ - `/ue-ai-navigation` — trace-based sensing and navmesh overlap queries
402
+ - `/ue-gameplay-abilities` — targeting systems built on trace and overlap queries
403
+ - `/ue-cpp-foundations` — delegate binding syntax and UFUNCTION requirements
404
+
405
+ ---
406
+
407
+ ## Checklist
408
+
409
+ Validate before considering the work done:
410
+
411
+ - [ ] Collision channels and presets are defined in config, not hardcoded per actor
412
+ - [ ] Traces use the narrowest channel and shape that answers the question
413
+ - [ ] Complex collision is avoided on anything queried frequently
414
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
415
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
416
+
417
+ **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.
418
+
419
+ ## Next Steps
420
+
421
+ - `/perf-profile` — check physics and trace cost in the profiler
422
+ - `/code-review` — architectural and quality review of the change
423
+ - `/commit` — conventional commit once the change is verified