# Niagara VFX System

## Architecture

Niagara is UE5's modular particle/VFX system. A **Niagara System** (NS_) contains one or more **Emitters** (NE_), each with a stack of **Modules** controlling particle behavior. Systems are assets saved to Content/.

Key classes (use `query_ue_api` to inspect):
- `UNiagaraSystem` — the asset (contains emitters, user parameters)
- `UNiagaraComponent` — scene component that plays a system
- `UNiagaraFunctionLibrary` — static C++ helpers for spawning
- `UNiagaraEmitter` — individual emitter within a system
- `UNiagaraDataInterfaceBase` — base for data interfaces

## Creating Niagara Assets via Python

Do NOT hardcode factory class names. Discover them at runtime:

1. Use `query_ue_api('NiagaraSystemFactory')` to find the system factory class.
2. Use `query_ue_api('NiagaraEmitter')` to find emitter-related classes.
3. Use `dir()` on discovered classes to find creation/spawning methods.
4. Create assets using the discovered factory, then save.

## Spawning at Runtime (C++)

These C++ patterns are stable across UE5 versions. Use them in C++ code or teach them to Blueprint users.

```cpp
// One-shot effect (auto-destroys when complete):
UNiagaraFunctionLibrary::SpawnSystemAtLocation(
    GetWorld(), NiagaraSystem, SpawnLocation, FRotator::ZeroRotator,
    FVector(1.f), true,  // bAutoDestroy
    true,  // bAutoActivate
    ENCPoolMethod::AutoRelease);

// Attached effect (follows a component):
UNiagaraComponent* NComp = UNiagaraFunctionLibrary::SpawnSystemAttached(
    NiagaraSystem, MeshComponent, NAME_None,
    FVector::ZeroVector, FRotator::ZeroRotator,
    EAttachLocation::SnapToTarget, true);  // bAutoDestroy
```

## Controlling Parameters at Runtime (C++)

User parameters must be exposed in the Niagara System editor first.

```cpp
NiagaraComp->SetVariableFloat(FName("SpawnRate"), 100.f);
NiagaraComp->SetVariableVec3(FName("Velocity"), FVector(0, 0, 500));
NiagaraComp->SetVariableLinearColor(FName("Color"), FLinearColor::Red);
NiagaraComp->SetVariableBool(FName("Active"), true);
NiagaraComp->SetVariableInt(FName("Count"), 50);

// Activate / Deactivate
NiagaraComp->Activate(true);   // bReset = true to restart from beginning
NiagaraComp->Deactivate();
```

## Emitter Module Stack

Each emitter has an ordered module stack controlling the full particle lifecycle:

1. **Emitter Spawn** — runs once when emitter starts (initialize emitter-level properties)
2. **Emitter Update** — runs per frame on the emitter (Spawn Rate for continuous, Spawn Burst for one-shot)
3. **Particle Spawn** — runs once per new particle (Initialize Particle: position, velocity, lifetime, size, color)
4. **Particle Update** — runs per frame per particle (Gravity Force, Drag, Scale Color/Size over lifetime, Curl Noise Force)
5. **Particle Render** — determines how particles are drawn (Sprite Renderer, Mesh Renderer, Ribbon Renderer)

## Common Effects Recipes

| Effect | Spawn | Movement | Visual | Notes |
|--------|-------|----------|--------|-------|
| Fire | Continuous, moderate rate | Upward velocity | Color curve yellow-orange-red-black, scale down over life | Sprite renderer |
| Smoke | Continuous, low rate | Slow upward drift | Gray color, fade out alpha, large initial size | Sprite renderer |
| Sparks | Burst or continuous | High velocity random direction, gravity | Small size, short lifetime, bright emissive | Sprite renderer |
| Explosion | Burst spawn | Radial velocity outward | Fast scale-down, bright emissive flash, add smoke sub-emitter | Multi-emitter system |
| Blood/Impact | Burst spawn | Radial + downward, gravity | Short life, optional decal spawn on death | Physics-aware |
| Trail/Ribbon | Along movement path | Inherit actor velocity | Fade width over distance | Ribbon renderer |
| Rain | Large spawn area above | Downward velocity | Thin streaks, collision module for splash sub-emitter | GPU sim recommended |
| Dust/Footstep | Burst at foot location | Low radial velocity | Gray, quick alpha fade, small count | Triggered by gameplay |

## Data Interfaces

Data Interfaces let particles read external data at runtime:

- **Skeletal Mesh DI** — sample positions/normals from animated skeleton (mesh-surface effects like burning, dissolve)
- **Static Mesh DI** — sample surfaces of static meshes
- **Collision Query DI** — raycast against scene geometry (particle-world interaction, bouncing)
- **Audio Spectrum DI** — react to audio frequency data (audio-reactive VFX)
- **Landscape DI** — conform particles to terrain height (ground-following effects)
- **Spline DI** — follow spline paths
- **Camera DI** — access camera position/direction (screen-space effects)
- **Array DI** — pass arrays of data from gameplay code to particles

## Naming Conventions

- `NS_` — Niagara Systems: NS_Fire, NS_Smoke, NS_Sparks, NS_Explosion
- `NE_` — Niagara Emitters: NE_Flame, NE_SmokePuff
- `NPC_` — Niagara Parameter Collections
- `NDI_` — Custom Niagara Data Interfaces
- `NM_` — Niagara Modules (custom scratch pad or asset modules)

## Performance Tips

- Use **GPU Sim** for large particle counts (10,000+) — set Sim Target on the emitter
- Use **LOD Distance** settings to reduce particle count/quality at distance
- Limit Spawn Rate to what is visually necessary — more particles is not always better
- Use **pooling** (`ENCPoolMethod::AutoRelease`) for frequently spawned one-shot effects
- Avoid **Collision Query DI** on high-count emitters — raycast per particle is expensive
- Use **Fixed Bounds** on systems with predictable extents to avoid dynamic bounds recalculation
- Prefer **Sprite Renderer** over **Mesh Renderer** for very high particle counts
- Consider **Significance** settings to auto-cull off-screen or distant systems

## Critical Rules

- Niagara plugin must be enabled: add `"Niagara"` to Build.cs `PublicDependencyModuleNames`
- Always verify the system asset exists before spawning (use `load_asset` and check for None)
- For one-shot effects, always set `bAutoDestroy=true` to prevent memory leaks
- User parameters must be exposed in the Niagara System editor before `SetVariable*` calls work at runtime
- Use `query_ue_api` with keyword `NiagaraFunctionLibrary` to discover all available spawning and utility methods
- Use `query_ue_api` with keyword `NiagaraComponent` to discover all `SetVariable*` overloads and activation methods
- When attaching Niagara to Blueprints via Python, use `query_ue_api` to discover the correct component and construction script APIs — do not hardcode class names
