Dynamic, event-driven screen space effects for Bevy games.
Unlike static post-processing, effects in this library are spawned as entities with lifetimes—they animate and despawn automatically, perfect for impacts, abilities, damage feedback, and environmental effects.
Bevy 0.18 | Rust 2024 Edition
- Entity-based effects - Spawn effects as ECS entities, not permanent pipeline passes
- Automatic lifetime management - Effects fade in/out and despawn on their own
- Configurable easing - Linear, ease in/out, elastic, bounce animations
- 12 built-in effects across three categories
- Modular feature flags - Only compile what you need
use bevy::prelude::*;
use bevy_screen_effects::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(ScreenEffectsPlugin)
.add_systems(Update, spawn_effects)
.run();
}
fn spawn_effects(mut commands: Commands, input: Res<ButtonInput<KeyCode>>) {
if input.just_pressed(KeyCode::Space) {
// Spawn a shockwave at screen center - it animates and despawns automatically
commands.spawn(ShockwaveBundle {
shockwave: Shockwave::at(0.5, 0.5).with_intensity(0.3),
lifetime: EffectLifetime::new(0.5),
..default()
});
}
}Add to your Cargo.toml:
[dependencies]
bevy_screen_effects = "0.1"All features are enabled by default. Disable unused categories to reduce compile time:
[dependencies]
bevy_screen_effects = { version = "0.1", default-features = false, features = ["distortion", "feedback"] }| Feature | Effects |
|---|---|
distortion |
Shockwave, Radial Blur, Raindrops, Heat Haze |
glitch |
RGB Split, Scanline Glitch, Block Displacement, Static Noise, EMP |
feedback |
Damage Vignette, Screen Flash, Speed Lines |
Expanding ring of distortion from a point. Perfect for explosions and impacts.
// Screen-space shockwave (normalized coordinates 0-1)
commands.spawn(ShockwaveBundle {
shockwave: Shockwave::at(0.5, 0.5)
.with_intensity(0.25)
.with_ring_width(0.1)
.with_chromatic(true),
lifetime: EffectLifetime::new(0.5),
..default()
});World-space shockwave that tracks camera movement. The effect stays anchored to a 3D position as the camera moves.
commands.spawn(WorldShockwaveBundle {
shockwave: WorldShockwave::at(Vec3::new(10.0, 0.0, 5.0))
.with_intensity(0.3)
.with_chromatic(true),
lifetime: EffectLifetime::new(0.6),
..default()
});Motion blur radiating from a center point.
commands.spawn(RadialBlurBundle {
radial_blur: RadialBlur {
center: Vec2::new(0.5, 0.5),
intensity: 0.1,
samples: 8,
},
lifetime: EffectLifetime::new(0.3),
..default()
});Procedural raindrops with refraction. Includes presets for different intensities.
// Use a preset
commands.spawn(RaindropsBundle {
raindrops: Raindrops::storm(),
lifetime: EffectLifetime::new(5.0),
..default()
});
// Or customize
commands.spawn(RaindropsBundle {
raindrops: Raindrops::default()
.with_density(0.7)
.with_drop_size(0.04)
.with_speed(0.5),
lifetime: EffectLifetime::new(10.0),
..default()
});Presets: light(), heavy(), storm(), drizzle()
Wavy distortion for heat shimmer, underwater, or dream sequences.
commands.spawn(HeatHazeBundle {
heat_haze: HeatHaze {
amplitude: 0.01,
frequency: 20.0,
speed: 2.0,
direction: Vec2::Y,
},
lifetime: EffectLifetime::new(3.0),
..default()
});Chromatic aberration / channel separation.
commands.spawn(RgbSplitBundle {
rgb_split: RgbSplit::horizontal(0.015),
lifetime: EffectLifetime::new(0.2),
..default()
});Presets: horizontal(amount), diagonal(amount)
Horizontal line artifacts with displacement.
commands.spawn(ScanlineGlitchBundle {
scanline: ScanlineGlitch {
density: 0.1,
displacement: 0.05,
line_height: 2.0,
flicker_speed: 30.0,
},
lifetime: EffectLifetime::new(0.5),
..default()
});Datamosh / video compression artifacts.
commands.spawn(BlockDisplacementBundle {
block: BlockDisplacement {
block_size: Vec2::new(0.1, 0.05),
max_displacement: 0.1,
probability: 0.3,
update_rate: 15.0,
},
lifetime: EffectLifetime::new(0.4),
..default()
});Visual grain and interference.
commands.spawn(StaticNoiseBundle {
noise: StaticNoise {
grain_size: 1.0,
color_amount: 0.0, // 0 = mono, 1 = color
blend_mode: 0.3, // 0 = additive, 1 = replace
},
lifetime: EffectLifetime::new(0.3),
..default()
});Complex electromagnetic pulse with multiple layered sub-effects.
// Use a preset
commands.spawn(EmpInterferenceBundle {
emp: EmpInterference::heavy(),
lifetime: EffectLifetime::new(1.0),
..default()
});
// Or customize
commands.spawn(EmpInterferenceBundle {
emp: EmpInterference::default()
.with_flicker(30.0, 0.3)
.with_bands(8.0, 0.4, 2.0)
.with_static(0.2, 0.1)
.with_chromatic(0.01),
lifetime: EffectLifetime::new(1.5),
..default()
});Presets: light(), heavy(), critical(), radio_static()
Pulsing colored vignette at screen edges.
commands.spawn(DamageVignetteBundle {
vignette: DamageVignette {
color: Color::srgba(0.8, 0.0, 0.0, 0.6),
size: 0.4,
softness: 0.3,
pulse_frequency: 8.0,
},
lifetime: EffectLifetime::new(0.8),
..default()
});Presets: with_color(color), healing() (green), shield() (blue, no pulse)
Full-screen color flash for impacts and transitions.
commands.spawn(ScreenFlashBundle {
flash: ScreenFlash::white(),
lifetime: EffectLifetime::new(0.15).with_fade_out(0.15),
..default()
});Presets: white(), impact(), with_color(color)
Manga/anime-style radial motion lines.
commands.spawn(SpeedLinesBundle {
speed_lines: SpeedLines::centered()
.with_line_count(32)
.with_thickness(0.002)
.with_length(0.5),
lifetime: EffectLifetime::new(0.5),
..default()
});Every effect uses EffectLifetime to control its duration and animation:
EffectLifetime::new(1.0) // 1 second duration
.with_fade_in(0.1) // 0.1s fade in
.with_fade_out(0.3) // 0.3s fade out
.with_easing(EasingFunction::EaseOut) // Easing curveEasing Functions:
Linear- Constant rateEaseIn- Slow start, fast endEaseOut- Fast start, slow endEaseInOut- Slow start and endElastic- Overshoot then settleBounce- Bounces at the end
Spawn multiple effects simultaneously for complex visuals:
fn big_impact(commands: &mut Commands, position: Vec2) {
// Shockwave
commands.spawn(ShockwaveBundle {
shockwave: Shockwave::at(position.x, position.y).with_intensity(0.4),
lifetime: EffectLifetime::new(0.6),
..default()
});
// Screen flash
commands.spawn(ScreenFlashBundle {
flash: ScreenFlash::impact(),
lifetime: EffectLifetime::new(0.1),
..default()
});
// Brief glitch
commands.spawn(RgbSplitBundle {
rgb_split: RgbSplit::horizontal(0.02),
lifetime: EffectLifetime::new(0.15),
..default()
});
}cargo run --example showcaseControls:
- 1 or Left Click - Shockwave at cursor
- 2 - Radial blur
- 3 - RGB split
- 4 - Combined glitch (scanline + block + static)
- 5 - Damage vignette
- 6 - Screen flash
- 7 - Raindrops
- 8 - EMP interference
- 9 - World shockwave (at sphere, tracks camera)
- Space - Shockwave at center
MIT OR Apache-2.0