# 6. Particle Pitfalls
Part of [[Particle Systems and Layered Effects]]. Requires Unity 6.3 LTS+ and URP. Previous: [[5.VFX Graph Comparison and Performance]].
| Symptom | Cause | Fix |
|---|---|---|
| Particles are pink/magenta | Built-in pipeline material (`Particles/Standard Unlit`) in a URP project | Use `Universal Render Pipeline/Particles/Unlit` or `Lit`. **Edit > Rendering > Materials > Convert** for old assets |
| Soft particles do nothing | Depth Texture disabled | Enable **Depth Texture** on the URP Asset (or the Camera) |
| Heat haze shows nothing / black | Opaque Texture off, or wrong surface type | Enable **Opaque Texture**; make the graph Transparent |
| Fire emits sideways | Shapes emit along local **+Z** | Rotate the emitter (or `FX_Root`) to `(-90, 0, 0)` |
| Smoke stays attached to a moving can | Simulation Space **Local** | Set **World** |
| Scaling the prefab doesn't scale the effect | Scaling Mode Local/Shape | **Hierarchy** |
| Layers flicker in front of each other | Transparent sorting by distance | Same Sorting Layer, distinct **Order in Layer**; Sorting Fudge |
| Additive flames invisible in daylight | Additive adds to an already bright background | Add an alpha-blended "body" layer, or darker texture |
| `ps.main.startColor = ...` won't compile | Modifying a member of a returned struct | `var main = ps.main; main.startColor = ...;` |
| Setting `startSize` destroyed my curve | Assigning a float replaces the MinMaxCurve | Use `startSizeMultiplier` |
| `OnParticleCollision` never called | Send Collision Messages off, Type Planes, or script on the wrong object | Type **World**, tick **Send Collision Messages**, script on the system or the hit collider |
| Collisions miss thin geometry | Medium/Low quality voxel cache | High quality for that system, or thicker colliders, or Radius Scale |
| Sparks hit their own effect | Collides With includes the FX layer | Exclude it from the mask |
| Sub emitter emits nothing | Sub emitter isn't a child of the parent; or its own emission is 0 with no Burst | Parent it, give it a Burst |
| Sub emitter plays on its own at start | Its Play On Awake / Looping on | Turn both off; sub emitters are driven by the parent |
| Splash count explodes | Collision sub-emitter on every drop, chains | Emit Probability, shallow chains, Lifetime Loss 1 |
| `OnParticleSystemStopped` never fires | Stop Action isn't Callback, system is Looping, or script isn't on the system's GameObject | Set Callback, call `Stop()` for loops, move the script |
| Pooled effect replays old particles | Not cleared before replay | `Clear(true)` then `Play(true)` |
| Pooled effect shows at wrong place for a frame | Activated before moving | Set the transform, then Play (as in `PlayAt`) |
| Fire looks "empty" for the first second | No prewarm | Looping + **Prewarm** |
| Big frame drop when a fire starts | Prewarm on a long Duration, or first-use instantiation | Short Duration, pool Prewarm |
| Effect disappears when the camera looks away from the base | Bounds too small / culled | Check Show Bounds; Culling Mode; larger shape |
| GC spikes from scripts | `new List` / arrays each call, `GetParticles` allocations | Cache buffers (see `EmberPopper`, `ParticleImpactSpawner`) |
| Frame rate tanks on Quest near smoke | Overdraw | Fewer, smaller puffs; Max Particle Size; Camera Fading |