1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! GPU-accelerated particle system.
//!
//! Provides real-time particle effects simulated on the GPU:
//!
//! - [`ParticleEmitter`]: Configurable emitter with shape, velocity, color, and lifetime
//! - [`EmitterShape`]: Point, sphere, cone, or box emission volumes
//! - [`EmitterType`]: Effect presets (Firework, Fire, Smoke, Sparks, Trail)
//! - [`ColorGradient`]: Color and alpha over particle lifetime
//!
//! Particles are rendered as camera-facing billboards with additive blending
//! for emissive effects or alpha blending for smoke.
//!
//! # Using Built-in Presets
//!
//! [`ParticleEmitter`] provides many ready-to-use effect presets:
//!
//! ```ignore
//! // Continuous fire effect
//! let emitter = ParticleEmitter::fire(Vec3::new(0.0, 0.0, 0.0));
//!
//! // Rising smoke plume
//! let emitter = ParticleEmitter::smoke(Vec3::new(0.0, 1.0, 0.0));
//!
//! // Spark fountain
//! let emitter = ParticleEmitter::sparks(Vec3::zeros());
//!
//! // One-shot firework explosion (red, 300 particles)
//! let emitter = ParticleEmitter::firework_explosion(
//! Vec3::new(0.0, 10.0, 0.0),
//! Vec3::new(1.0, 0.2, 0.2), // color
//! 300, // particle count
//! );
//! ```
//!
//! # Spawning Particle Emitters
//!
//! ```ignore
//! let entity = world.spawn_entities(
//! PARTICLE_EMITTER | LOCAL_TRANSFORM | GLOBAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY,
//! 1
//! )[0];
//! world.core.set_particle_emitter(entity, ParticleEmitter::fire(Vec3::zeros()));
//! world.core.set_local_transform(entity, LocalTransform {
//! translation: Vec3::new(5.0, 0.0, 0.0),
//! ..Default::default()
//! });
//! ```
//!
//! # Firework Presets
//!
//! | Preset | Description |
//! |--------|-------------|
//! | `firework_shell()` | Rising shell with trailing sparks |
//! | `firework_explosion()` | Spherical burst |
//! | `firework_willow()` | Long-lived drooping trails |
//! | `firework_chrysanthemum()` | Dense spherical burst with slow drag |
//! | `firework_ring()` | Flat ring expansion |
//! | `firework_glitter()` | Twinkling scattered particles |
//! | `firework_crackle()` | Fast crackling sparks |
//! | `palm_explosion()` | Upward-biased palm tree shape |
//! | `flash_burst()` | Brief bright flash |
//! | `strobe_effect()` | Sustained bright particles |
//!
//! # Color Gradients
//!
//! Control particle color over lifetime with [`ColorGradient`]:
//!
//! ```ignore
//! // Custom gradient: white -> orange -> red -> transparent
//! let gradient = ColorGradient {
//! colors: vec![
//! (0.0, Vec4::new(1.0, 1.0, 1.0, 1.0)),
//! (0.3, Vec4::new(1.0, 0.5, 0.0, 1.0)),
//! (0.7, Vec4::new(1.0, 0.2, 0.0, 0.5)),
//! (1.0, Vec4::new(0.5, 0.0, 0.0, 0.0)),
//! ],
//! };
//!
//! // Or use built-in gradients
//! let fire_colors = ColorGradient::fire();
//! let smoke_colors = ColorGradient::smoke();
//! ```
//!
//! # Emitter Properties
//!
//! | Property | Unit | Description |
//! |----------|------|-------------|
//! | `spawn_rate` | particles/sec | Continuous emission rate (0 for burst-only) |
//! | `burst_count` | count | Immediate spawn count |
//! | `particle_lifetime_min/max` | seconds | Random lifetime range |
//! | `initial_velocity_min/max` | m/s | Random speed range |
//! | `velocity_spread` | radians | Cone angle from direction |
//! | `gravity` | m/s² | Acceleration vector |
//! | `drag` | 0-1 | Velocity damping per frame |
//! | `size_start/end` | world units | Particle scale over lifetime |
//! | `emissive_strength` | multiplier | HDR bloom intensity |
//! | `one_shot` | bool | Disable after first burst |
//!
//! [`ParticleEmitter`]: components::ParticleEmitter
//! [`EmitterShape`]: components::EmitterShape
//! [`EmitterType`]: components::EmitterType
//! [`ColorGradient`]: components::ColorGradient