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,505 @@
1
+ ---
2
+ name: ue-procedural-generation
3
+ description: "PCG framework, ProceduralMesh, instanced mesh, runtime generation, noise"
4
+ category: "gamedev"
5
+ argument-hint: "[generator o PCG graph]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # ue-procedural-generation
11
+
12
+ You are an expert in Unreal Engine's procedural generation systems, including the PCG framework, ProceduralMeshComponent, instanced static meshes, noise functions, and spline-based generation.
13
+
14
+ Ask before writing: this skill edits PCG graphs and procedural generation code. Propose the change and get approval before using Write or Edit.
15
+
16
+ ## Context Check
17
+
18
+ Before advising, read `docs/unreal/project-context.md` to determine:
19
+ - Whether the PCG plugin is enabled (plugins list)
20
+ - Target generation type: world layout, terrain, dungeon, vegetation, runtime mesh
21
+ - Performance constraints (mobile, console, Nanite enabled)
22
+ - Multiplayer requirements (server authority vs. deterministic seeding)
23
+
24
+ ## Information Gathering
25
+
26
+ Ask for clarification on:
27
+ 1. **Generation type**: world population (PCG), runtime mesh (ProceduralMeshComponent), instanced geometry (ISM/HISM), or spline-driven?
28
+ 2. **Timing**: editor-time baked result or runtime dynamic generation?
29
+ 3. **Instance count**: hundreds (ISM) or tens of thousands (HISM)?
30
+ 4. **Collision**: does generated geometry need physics collision?
31
+ 5. **Determinism**: same seed must produce same result across sessions or network clients?
32
+
33
+ ---
34
+
35
+ ## 1. PCG Framework (UE 5.2+)
36
+
37
+ Node-based rule-driven world generation. Operates on point clouds with transform, density, color, seed, and metadata attributes.
38
+
39
+ ### Plugin Setup
40
+
41
+ ```csharp
42
+ // Build.cs
43
+ PublicDependencyModuleNames.Add("PCG");
44
+ ```
45
+ ```json
46
+ // .uproject Plugins array
47
+ { "Name": "PCG", "Enabled": true }
48
+ ```
49
+
50
+ ### Core Classes
51
+
52
+ | Class | Header | Purpose |
53
+ |---|---|---|
54
+ | `UPCGComponent` | `PCGComponent.h` | Actor component driving generation |
55
+ | `UPCGGraph` | `PCGGraph.h` | Asset: nodes + edges |
56
+ | `UPCGGraphInstance` | `PCGGraph.h` | Graph instance with parameter overrides |
57
+ | `UPCGPointData` | `Data/PCGPointData.h` | Point cloud between nodes |
58
+ | `UPCGSettings` | `PCGSettings.h` | Node settings base class |
59
+ | `UPCGBlueprintBaseElement` | `Elements/Blueprint/PCGBlueprintBaseElement.h` | Custom Blueprint node base |
60
+
61
+ ### UPCGComponent Key API (from `PCGComponent.h`)
62
+
63
+ ```cpp
64
+ // Assign graph (NetMulticast)
65
+ void SetGraph(UPCGGraphInterface* InGraph);
66
+
67
+ // Trigger generation (NetMulticast, Reliable) — use for multiplayer
68
+ void Generate(bool bForce);
69
+
70
+ // Local non-replicated generation
71
+ void GenerateLocal(bool bForce);
72
+
73
+ // Cleanup
74
+ void Cleanup(bool bRemoveComponents);
75
+ void CleanupLocal(bool bRemoveComponents);
76
+
77
+ // Notify to re-evaluate after Blueprint property change
78
+ void NotifyPropertiesChangedFromBlueprint();
79
+
80
+ // Read generated output
81
+ const FPCGDataCollection& GetGeneratedGraphOutput() const;
82
+ ```
83
+
84
+ Generation triggers (`EPCGComponentGenerationTrigger`):
85
+ - `GenerateOnLoad` — one-shot on BeginPlay
86
+ - `GenerateOnDemand` — explicit `Generate()` call only
87
+ - `GenerateAtRuntime` — budget-scheduled by `UPCGSubsystem`
88
+
89
+ ### UPCGGraph Node API (from `PCGGraph.h`)
90
+
91
+ ```cpp
92
+ // Add node by settings class
93
+ UPCGNode* AddNodeOfType(TSubclassOf<UPCGSettings> InSettingsClass, UPCGSettings*& DefaultNodeSettings);
94
+
95
+ // Connect two nodes
96
+ UPCGNode* AddEdge(UPCGNode* From, const FName& FromPinLabel, UPCGNode* To, const FName& ToPinLabel);
97
+
98
+ // Graph parameters (typed template)
99
+ template<typename T>
100
+ TValueOrError<T, EPropertyBagResult> GetGraphParameter(const FName PropertyName) const;
101
+
102
+ template<typename T>
103
+ EPropertyBagResult SetGraphParameter(const FName PropertyName, const T& Value);
104
+ ```
105
+
106
+ ### Custom Blueprint PCG Node
107
+
108
+ Derive from `UPCGBlueprintBaseElement`:
109
+
110
+ ```cpp
111
+ UCLASS(BlueprintType, Blueprintable)
112
+ class UMyPCGNode : public UPCGBlueprintBaseElement
113
+ {
114
+ GENERATED_BODY()
115
+ public:
116
+ UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PCG|Execution")
117
+ void Execute(const FPCGDataCollection& Input, FPCGDataCollection& Output);
118
+ };
119
+
120
+ // In Execute:
121
+ FRandomStream Stream = GetRandomStreamWithContext(GetContextHandle()); // deterministic seed
122
+
123
+ for (const FPCGTaggedData& In : Input.GetInputsByPin(PCGPinConstants::DefaultInputLabel))
124
+ {
125
+ const UPCGPointData* InPts = Cast<UPCGPointData>(In.Data);
126
+ if (!InPts) continue;
127
+
128
+ UPCGPointData* OutPts = NewObject<UPCGPointData>();
129
+ for (const FPCGPoint& Pt : InPts->GetPoints())
130
+ {
131
+ FPCGPoint NewPt = Pt;
132
+ NewPt.Density = Stream.FRandRange(0.5f, 1.0f);
133
+ OutPts->GetMutablePoints().Add(NewPt);
134
+ }
135
+ Output.TaggedData.Emplace_GetRef().Data = OutPts;
136
+ }
137
+ ```
138
+
139
+ Key `UPCGBlueprintBaseElement` properties:
140
+ - `bIsCacheable = false` — when node spawns actors or components
141
+ - `bRequiresGameThread = true` — for actor spawn, component add
142
+ - `CustomInputPins` / `CustomOutputPins` — extra typed pins
143
+
144
+ ### PCG Determinism
145
+
146
+ PCG graphs are deterministic by default — the same seed produces identical output. Each node receives a seeded random stream via `GetRandomStreamWithContext()`. To vary output across instances, set the PCG component's `Seed` property. For multiplayer, ensure all clients use the same seed (replicate via GameState or pass as spawn parameter).
147
+
148
+ ```cpp
149
+ // Set PCG seed at runtime for deterministic variation
150
+ UPCGComponent* PCG = FindComponentByClass<UPCGComponent>();
151
+ PCG->Seed = MyDeterministicSeedValue;
152
+ PCG->Generate(); // Regenerate with new seed
153
+ ```
154
+
155
+ ### PCG Data Types
156
+
157
+ | Type | Contains | Use for |
158
+ |---|---|---|
159
+ | `FPCGPoint` / Point Data | Position, rotation, scale, density, color | Scatter placement, foliage, instance positioning |
160
+ | `UPCGSplineData` | Spline points + tangents | Roads, rivers, paths, boundary definitions |
161
+ | `UPCGLandscapeData` | Height + layer weight sampling | Terrain-aware placement, biome queries |
162
+ | `UPCGVolumeData` | 3D bounds | Volume-based filtering and generation |
163
+
164
+ Point data is the most common — most PCG nodes consume and produce point collections. Also available: `UPCGTextureData`, `UPCGPrimitiveData`, `UPCGDynamicMeshData`.
165
+
166
+ See `references/pcg-node-reference.md` for all node types, settings fields, and pin labels.
167
+
168
+ ---
169
+
170
+ ## 2. ProceduralMeshComponent
171
+
172
+ ```csharp
173
+ // Build.cs
174
+ PublicDependencyModuleNames.Add("ProceduralMeshComponent");
175
+ ```
176
+
177
+ ### Core API
178
+
179
+ ```cpp
180
+ // Create section: vertices, triangles (CCW = front), normals, UVs, colors, tangents
181
+ void CreateMeshSection(int32 SectionIndex,
182
+ const TArray<FVector>& Vertices, const TArray<int32>& Triangles,
183
+ const TArray<FVector>& Normals, const TArray<FVector2D>& UV0,
184
+ const TArray<FColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents,
185
+ bool bCreateCollision);
186
+
187
+ // Updates vertex positions (incl. collision if enabled). Cannot change topology.
188
+ void UpdateMeshSection(int32 SectionIndex,
189
+ const TArray<FVector>& Vertices, const TArray<FVector>& Normals,
190
+ const TArray<FVector2D>& UV0, const TArray<FColor>& VertexColors,
191
+ const TArray<FProcMeshTangent>& Tangents);
192
+
193
+ void ClearMeshSection(int32 SectionIndex);
194
+ void ClearAllMeshSections();
195
+ void SetMeshSectionVisible(int32 SectionIndex, bool bNewVisibility);
196
+ void SetMaterial(int32 ElementIndex, UMaterialInterface* Material);
197
+ ```
198
+
199
+ ### Terrain Grid Example
200
+
201
+ ```cpp
202
+ void ATerrainActor::Build(int32 Grid, float Cell)
203
+ {
204
+ TArray<FVector> Verts; TArray<int32> Tris; TArray<FVector> Norms;
205
+ TArray<FVector2D> UVs; TArray<FColor> Colors; TArray<FProcMeshTangent> Tangs;
206
+
207
+ for (int32 Y = 0; Y <= Grid; Y++)
208
+ for (int32 X = 0; X <= Grid; X++)
209
+ {
210
+ float Z = SampleOctaveNoise(X * Cell, Y * Cell, 4, 0.5f, 2.f, 80.f);
211
+ Verts.Add(FVector(X * Cell, Y * Cell, Z));
212
+ Norms.Add(FVector::UpVector);
213
+ UVs.Add(FVector2D((float)X / Grid, (float)Y / Grid));
214
+ }
215
+ for (int32 Y = 0; Y < Grid; Y++)
216
+ for (int32 X = 0; X < Grid; X++)
217
+ {
218
+ int32 BL = Y*(Grid+1)+X, BR=BL+1, TL=BL+(Grid+1), TR=TL+1;
219
+ Tris.Add(BL); Tris.Add(TL); Tris.Add(TR);
220
+ Tris.Add(BL); Tris.Add(TR); Tris.Add(BR);
221
+ }
222
+ ProceduralMesh->CreateMeshSection(0, Verts, Tris, Norms,
223
+ UVs, Colors, Tangs, /*bCreateCollision=*/true);
224
+ }
225
+ ```
226
+
227
+ ### Performance Notes
228
+
229
+ - One draw call per `CreateMeshSection`. Keep vertex count < 65K per section.
230
+ - `UpdateMeshSection` updates vertex positions and collision (if enabled) but cannot change topology — call `CreateMeshSection` for new triangles.
231
+ - ProceduralMesh does **not** support Nanite.
232
+ - Compute vertex data on background thread; call `CreateMeshSection` on game thread only.
233
+
234
+ ### Async Mesh Generation
235
+
236
+ Generate vertices on a background thread, then apply on the game thread:
237
+
238
+ ```cpp
239
+ // Background task — compute vertices
240
+ class FMeshGenTask : public FNonAbandonableTask
241
+ {
242
+ public:
243
+ TArray<FVector> Vertices;
244
+ TArray<int32> Triangles;
245
+ void DoWork() { /* Marching cubes, noise sampling, etc. */ }
246
+ FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(FMeshGenTask, STATGROUP_ThreadPoolAsyncTasks); }
247
+ };
248
+
249
+ // Launch and poll
250
+ // Use FAsyncTask (not FAutoDeleteAsyncTask) when polling IsDone() is needed.
251
+ // FAutoDeleteAsyncTask deletes itself on completion — calling IsDone() afterward is a use-after-free.
252
+ auto* Task = new FAsyncTask<FMeshGenTask>();
253
+ Task->StartBackgroundTask();
254
+ // Poll safely: if (Task->IsDone()) { /* use Task->GetTask().Vertices */ delete Task; }
255
+ ```
256
+
257
+ ### Collision on Procedural Meshes
258
+
259
+ Set `UProceduralMeshComponent::bUseComplexAsSimpleCollision = true` to use the rendered triangles directly for collision. This is accurate but expensive — only use for static geometry. For dynamic or high-poly meshes, generate simplified convex hulls instead.
260
+
261
+ ---
262
+
263
+ ## 3. Instanced Static Meshes (ISM / HISM)
264
+
265
+ | Feature | ISM (`InstancedStaticMeshComponent.h`) | HISM (`HierarchicalInstancedStaticMeshComponent.h`) |
266
+ |---|---|---|
267
+ | Best for | < 1,000 dynamic instances | > 1,000 mostly static |
268
+ | Culling | Distance only | Hierarchical BVH + distance |
269
+ | LOD | GPU selection | Built-in transitions |
270
+ | Remove cost | O(n) | async BVH rebuild |
271
+
272
+ ### Key ISM API (from `InstancedStaticMeshComponent.h`)
273
+
274
+ ```cpp
275
+ virtual int32 AddInstance(const FTransform& T, bool bWorldSpace = false);
276
+ virtual TArray<int32> AddInstances(const TArray<FTransform>& Ts,
277
+ bool bShouldReturnIndices, bool bWorldSpace = false, bool bUpdateNavigation = true);
278
+ virtual bool UpdateInstanceTransform(int32 Idx, const FTransform& NewT,
279
+ bool bWorldSpace = false, bool bMarkRenderStateDirty = false, bool bTeleport = false);
280
+ virtual bool BatchUpdateInstancesTransforms(int32 StartIdx, const TArray<FTransform>& NewTs,
281
+ bool bWorldSpace = false, bool bMarkRenderStateDirty = false, bool bTeleport = false);
282
+ bool GetInstanceTransform(int32 Idx, FTransform& OutT, bool bWorldSpace = false) const;
283
+ virtual bool RemoveInstance(int32 InstanceIndex); // O(n) for ISM; triggers async BVH rebuild for HISM
284
+ virtual void PreAllocateInstancesMemory(int32 AddedCount);
285
+ int32 GetNumInstances() const;
286
+
287
+ // Per-instance custom float data (read in materials via PerInstanceCustomData)
288
+ virtual void SetNumCustomDataFloats(int32 N);
289
+ virtual bool SetCustomDataValue(int32 Idx, int32 DataIdx, float Value,
290
+ bool bMarkRenderStateDirty = false);
291
+ virtual bool SetCustomData(int32 Idx, TArrayView<const float> Floats,
292
+ bool bMarkRenderStateDirty = false);
293
+ ```
294
+
295
+ Culling properties: `InstanceStartCullDistance`, `InstanceEndCullDistance`, `InstanceLODDistanceScale`, `bUseGpuLodSelection`.
296
+
297
+ ### Vegetation Scatter (HISM + Terrain Trace)
298
+
299
+ ```cpp
300
+ HISM->SetStaticMesh(TreeMesh);
301
+ HISM->SetNumCustomDataFloats(1);
302
+ HISM->PreAllocateInstancesMemory(Count);
303
+ FRandomStream Rand(Seed);
304
+ TArray<FTransform> Transforms; Transforms.Reserve(Count);
305
+
306
+ for (int32 i = 0; i < Count; i++)
307
+ {
308
+ FVector Loc(Rand.FRandRange(Min.X, Max.X), Rand.FRandRange(Min.Y, Max.Y), 0);
309
+ FHitResult Hit;
310
+ if (GetWorld()->LineTraceSingleByChannel(Hit,
311
+ Loc + FVector(0,0,5000), Loc - FVector(0,0,5000), ECC_WorldStatic))
312
+ Loc.Z = Hit.Location.Z;
313
+
314
+ Transforms.Add(FTransform(
315
+ FRotator(0, Rand.FRandRange(0,360), 0), Loc,
316
+ FVector(Rand.FRandRange(0.8f, 1.3f))));
317
+ }
318
+
319
+ TArray<int32> Indices = HISM->AddInstances(Transforms, true, true);
320
+ for (int32 i = 0; i < Indices.Num(); i++)
321
+ HISM->SetCustomDataValue(Indices[i], 0, Rand.FRand(), false);
322
+ HISM->MarkRenderStateDirty();
323
+ ```
324
+
325
+ ### Foliage System
326
+
327
+ The editor's Foliage paint mode uses `AInstancedFoliageActor` which internally wraps `UHierarchicalInstancedStaticMeshComponent`. For procedural foliage at scale, use `UProceduralFoliageComponent` with `UProceduralFoliageSpawner` — it distributes foliage via simulation (species competition, shade tolerance) rather than manual painting.
328
+
329
+ **Per-instance collision**: Enable `bUseDefaultCollision` on the ISM component. Each instance inherits the static mesh's collision. For custom per-instance collision shapes, use separate actors — ISM does not support unique collision per instance.
330
+
331
+ **Platform limits**: HISM GPU buffer caps vary by platform (~1M on desktop, ~100K on mobile). Monitor with `stat Foliage`. Split large populations across multiple HISM components.
332
+
333
+ ---
334
+
335
+ ## 4. Noise and Math
336
+
337
+ ```cpp
338
+ // Built-in Perlin (all output in [-1, 1])
339
+ float N1 = FMath::PerlinNoise1D(X * Freq);
340
+ float N2 = FMath::PerlinNoise2D(FVector2D(X, Y) * Freq);
341
+ float N3 = FMath::PerlinNoise3D(FVector(X, Y, Z) * Freq);
342
+
343
+ // Octave noise
344
+ float OctaveNoise(float X, float Y, int32 Oct, float Persist, float Lacu, float Scale)
345
+ {
346
+ float V=0, A=1, F=1.f/Scale, Max=0;
347
+ for (int32 i=0; i<Oct; i++) {
348
+ V += FMath::PerlinNoise2D(FVector2D(X,Y)*F) * A;
349
+ Max += A; A *= Persist; F *= Lacu;
350
+ }
351
+ return V / Max;
352
+ }
353
+
354
+ // Seeded deterministic random
355
+ FRandomStream Stream(Seed);
356
+ float R = Stream.FRandRange(Min, Max);
357
+ int32 I = Stream.RandRange(MinI, MaxI);
358
+ FVector Dir = Stream.VRand();
359
+ ```
360
+
361
+ **Height/density maps**: Sample `UTexture2D` pixel data via `FTexturePlatformData` to drive terrain height or placement density. Lock with `BulkData.Lock(LOCK_READ_ONLY)`, read, then unlock.
362
+
363
+ **Poisson disc sampling** (minimum-separation scatter for natural placement) — full Bridson algorithm implementation in `references/procedural-mesh-patterns.md`.
364
+
365
+ ---
366
+
367
+ ## 5. Spline Components
368
+
369
+ ### USplineComponent API (from `SplineComponent.h`)
370
+
371
+ ```cpp
372
+ // Build spline (always batch with bUpdateSpline=false, call UpdateSpline() once after)
373
+ void AddSplinePoint(const FVector& Pos, ESplineCoordinateSpace::Type Space, bool bUpdate=true);
374
+ void SetSplinePoints(const TArray<FVector>& Pts, ESplineCoordinateSpace::Type Space, bool bUpdate=true);
375
+ void ClearSplinePoints(bool bUpdate=true);
376
+ virtual void UpdateSpline(); // Rebuild reparameterization table
377
+
378
+ // Query by arc-length distance
379
+ FVector GetLocationAtDistanceAlongSpline(float Dist, ESplineCoordinateSpace::Type Space) const;
380
+ FVector GetDirectionAtDistanceAlongSpline(float Dist, ESplineCoordinateSpace::Type Space) const;
381
+ FVector GetRightVectorAtDistanceAlongSpline(float Dist, ESplineCoordinateSpace::Type Space) const;
382
+ FRotator GetRotationAtDistanceAlongSpline(float Dist, ESplineCoordinateSpace::Type Space) const;
383
+ FTransform GetTransformAtDistanceAlongSpline(float Dist, ESplineCoordinateSpace::Type Space, bool bUseScale=false) const;
384
+ float GetSplineLength() const;
385
+
386
+ // Point editing
387
+ int32 GetNumberOfSplinePoints() const;
388
+ void SetSplinePointType(int32 Idx, ESplinePointType::Type Type, bool bUpdate=true);
389
+ void SetClosedLoop(bool bClosed, bool bUpdate=true);
390
+ void SetTangentsAtSplinePoint(int32 Idx, const FVector& Arrive, const FVector& Leave,
391
+ ESplineCoordinateSpace::Type Space, bool bUpdate=true);
392
+ ```
393
+
394
+ Point types: `Linear`, `Curve`, `Constant`, `CurveClamped`, `CurveCustomTangent`.
395
+
396
+ `FindInputKeyClosestToWorldLocation(WorldLocation)` — returns the spline key nearest to a world position (useful for snapping actors to splines).
397
+
398
+ **Runtime modification**: Call `AddSplinePoint()`, `RemoveSplinePoint()`, or `SetLocationAtSplinePoint()` then `UpdateSpline()` to rebuild. Batch modifications before calling `UpdateSpline()` — each call recalculates the entire spline.
399
+
400
+ ### Spline Placement Example
401
+
402
+ ```cpp
403
+ // Place instances evenly along spline
404
+ float Len = Spline->GetSplineLength();
405
+ for (float D = 0.f; D <= Len; D += Spacing)
406
+ {
407
+ FTransform T = Spline->GetTransformAtDistanceAlongSpline(D, ESplineCoordinateSpace::World);
408
+ HISM->AddInstance(T, /*bWorldSpace=*/true);
409
+ }
410
+ ```
411
+
412
+ ### USplineMeshComponent (Mesh Deformation)
413
+
414
+ ```cpp
415
+ #include "Components/SplineMeshComponent.h"
416
+ USplineMeshComponent* SM = NewObject<USplineMeshComponent>(this);
417
+ SM->SetStaticMesh(PipeMesh);
418
+ SM->RegisterComponent();
419
+
420
+ FVector SP, ST, EP, ET;
421
+ Spline->GetLocationAndTangentAtSplinePoint(Seg, SP, ST, ESplineCoordinateSpace::Local);
422
+ Spline->GetLocationAndTangentAtSplinePoint(Seg+1, EP, ET, ESplineCoordinateSpace::Local);
423
+ SM->SetStartAndEnd(SP, ST, EP, ET, /*bUpdateMesh=*/true);
424
+ SM->SetForwardAxis(ESplineMeshAxis::X);
425
+ ```
426
+
427
+ ---
428
+
429
+ ## 6. Runtime Mesh Generation Patterns
430
+
431
+ See `references/procedural-mesh-patterns.md` for full implementations:
432
+ - **Marching Cubes** — isosurface from 3D density scalar field
433
+ - **Dungeon BSP** — BSP partition into rooms, L-corridor carving, tile-to-mesh
434
+ - **L-System** — string rewriting + turtle interpreter to HISM branches
435
+ - **Wave Function Collapse** — constraint-propagation tile grid layout
436
+ - **Async mesh generation** — background thread vertex computation, game thread `CreateMeshSection`
437
+ - **Spline road extrusion** — cross-section profile swept along `USplineComponent`
438
+
439
+ ```cpp
440
+ // Marching Cubes result → ProceduralMesh
441
+ ProceduralMesh->CreateMeshSection(0, MarchVerts, MarchTris, MarchNormals,
442
+ MarchUVs, {}, {}, /*bCreateCollision=*/true);
443
+ ```
444
+
445
+ ---
446
+
447
+ ## Common Mistakes and Anti-Patterns
448
+
449
+ **PCG**
450
+ - Calling `GenerateLocal()` in `Tick` — generation is not free; use `GenerateOnDemand` and regenerate only on data change.
451
+ - Using `GenerateLocal()` in multiplayer — it is NOT replicated; use `Generate(bForce)` (NetMulticast).
452
+ - Heavy custom nodes with `bIsCacheable = true` — only cache if output depends solely on inputs + seed.
453
+ - Graphs with `bIsEditorOnly = true` fail to cook into packaged builds.
454
+
455
+ **ProceduralMeshComponent**
456
+ - Passing `bCreateCollision=false` to `CreateMeshSection` — characters fall through the mesh.
457
+ - Calling `UpdateMeshSection` expecting topology to change — vertex count must match; use `CreateMeshSection` for new triangles.
458
+ - Using ProceduralMesh for Nanite-scale terrain — not supported; use Landscape or PCG + ISM.
459
+ - Wrong triangle winding (CW instead of CCW) — polygons are invisible due to back-face culling.
460
+
461
+ **ISM / HISM**
462
+ - Using ISM above ~500 instances — switch to HISM for BVH culling.
463
+ - Setting `bMarkRenderStateDirty=true` on every `UpdateInstanceTransform` in a loop — only set `true` on the last call.
464
+ - Skipping `PreAllocateInstancesMemory` before bulk add — repeated realloc degrades performance.
465
+
466
+ **Splines**
467
+ - Calling `AddSplinePoint(bUpdateSpline=true)` in a loop — rebuilds reparameterization table every call; use `false` and call `UpdateSpline()` once.
468
+ - Using spline input key (not distance) for even spacing — key is NOT proportional to arc length.
469
+
470
+ **Multiplayer**
471
+ - Procedural content must be deterministic (same seed) or server-authoritative.
472
+ - `GenerateLocal()` does not replicate; `Generate(bool)` is `NetMulticast, Reliable`.
473
+
474
+ ---
475
+
476
+ ## Related Skills
477
+
478
+ - `/ue-actor-component-architecture` — component lifecycle, registration, replication
479
+ - `/ue-physics-collision` — collision profiles, complex vs. simple on generated geometry
480
+ - `/ue-cpp-foundations` — `NewObject`, `TSubclassOf`, `TArray`, memory management
481
+
482
+ ## Reference Files
483
+
484
+ - `references/pcg-node-reference.md` — all PCG node types, pin labels, settings fields, determinism checklist
485
+ - `references/procedural-mesh-patterns.md` — quad grid, marching cubes, dungeon BSP, L-system, WFC, spline road
486
+
487
+ ---
488
+
489
+ ## Checklist
490
+
491
+ Validate before considering the work done:
492
+
493
+ - [ ] Generation is deterministic from a seed and reproducible
494
+ - [ ] Instanced meshes are used for repeated geometry rather than individual actors
495
+ - [ ] Runtime generation is budgeted and spread across frames
496
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
497
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
498
+
499
+ **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.
500
+
501
+ ## Next Steps
502
+
503
+ - `/ue-world-level-streaming` — integrate generated content with streaming
504
+ - `/code-review` — architectural and quality review of the change
505
+ - `/commit` — conventional commit once the change is verified