nightshade 0.47.0

A cross-platform data-oriented game engine.
Documentation
//! Visual-effect component definitions.
//!
//! These components ride the engine's existing GPU renderers. [`Beam`],
//! [`LightningBolt`], and [`Trail`] drive an entity's [`Lines`] buffer.
//! [`VfxAnimator`] animates a mesh entity's transform and material over time.
//!
//! [`Lines`]: crate::ecs::lines::components::Lines

use freecs::Entity;
use nalgebra_glm::Vec3;

/// A glowing volumetric beam between two world-space points, rendered as a
/// bundle of parallel HDR lines so bloom widens it into a soft shaft.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, enum2schema::Schema)]
pub struct Beam {
    pub start: Vec3,
    pub end: Vec3,
    /// Linear HDR color. Values above 1.0 bloom.
    pub color: Vec3,
    pub intensity: f32,
    pub alpha: f32,
    /// Perpendicular spread of the strand bundle in world units.
    pub width: f32,
    /// Number of parallel strands forming the beam body.
    pub strands: u32,
    /// Brightness modulation amount in 0..1.
    pub flicker: f32,
    pub flicker_speed: f32,
    pub age: f32,
}

impl Default for Beam {
    fn default() -> Self {
        Self {
            start: Vec3::zeros(),
            end: Vec3::new(0.0, 1.0, 0.0),
            color: Vec3::new(2.0, 2.0, 2.0),
            intensity: 3.0,
            alpha: 1.0,
            width: 0.12,
            strands: 5,
            flicker: 0.0,
            flicker_speed: 30.0,
            age: 0.0,
        }
    }
}

/// A procedural lightning arc between two points, regenerated on an interval
/// via midpoint displacement with optional forking branches.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, enum2schema::Schema)]
pub struct LightningBolt {
    pub start: Vec3,
    pub end: Vec3,
    pub color: Vec3,
    pub intensity: f32,
    pub alpha: f32,
    /// Number of segments along the main arc.
    pub segments: u32,
    /// Lateral displacement amount in world units.
    pub jaggedness: f32,
    pub branch_count: u32,
    pub branch_spread: f32,
    /// Seconds between path regenerations.
    pub regen_interval: f32,
    pub timer: f32,
    pub seed: u32,
}

impl Default for LightningBolt {
    fn default() -> Self {
        Self {
            start: Vec3::zeros(),
            end: Vec3::new(0.0, 4.0, 0.0),
            color: Vec3::new(1.4, 1.7, 3.0),
            intensity: 4.0,
            alpha: 1.0,
            segments: 18,
            jaggedness: 0.45,
            branch_count: 4,
            branch_spread: 0.8,
            regen_interval: 0.06,
            timer: 0.0,
            seed: 1,
        }
    }
}

/// A fading ribbon traced by a point orbiting a center, rendered as a fading
/// HDR polyline. Self-contained motion makes it a standalone showcase effect.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, enum2schema::Schema)]
pub struct Trail {
    pub center: Vec3,
    pub radius: f32,
    pub axis: Vec3,
    /// Angular speed in radians per second.
    pub speed: f32,
    pub color: Vec3,
    pub intensity: f32,
    pub alpha: f32,
    pub max_points: u32,
    pub points: Vec<Vec3>,
    pub age: f32,
}

/// Drives a mesh entity's transform and emissive material over its lifetime.
///
/// Covers expanding shockwaves (scale ramp plus alpha fade plus self-despawn),
/// spinning portals and vortices, and pulsing energy shields.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, enum2schema::Schema)]
pub struct VfxAnimator {
    pub age: f32,
    /// Total lifetime in seconds. Values at or below zero loop forever.
    pub lifetime: f32,
    pub despawn_on_end: bool,
    pub start_scale: Vec3,
    pub end_scale: Vec3,
    pub spin_axis: Vec3,
    pub spin_speed: f32,
    /// Emissive and base color at full intensity.
    pub peak_color: Vec3,
    pub emissive_strength: f32,
    pub base_alpha: f32,
    /// Multiply alpha by (1 - progress) over the lifetime.
    pub fade_alpha: bool,
    pub pulse_amplitude: f32,
    pub pulse_frequency: f32,
    /// Center the entity orbits around. Active when `orbit_radius` is positive.
    pub orbit_center: Vec3,
    pub orbit_radius: f32,
    pub orbit_axis: Vec3,
    /// Orbit angular speed in radians per second.
    pub orbit_speed: f32,
}

impl Default for VfxAnimator {
    fn default() -> Self {
        Self {
            age: 0.0,
            lifetime: 0.0,
            despawn_on_end: false,
            start_scale: Vec3::new(1.0, 1.0, 1.0),
            end_scale: Vec3::new(1.0, 1.0, 1.0),
            spin_axis: Vec3::new(0.0, 1.0, 0.0),
            spin_speed: 0.0,
            peak_color: Vec3::new(1.0, 1.0, 1.0),
            emissive_strength: 3.0,
            base_alpha: 1.0,
            fade_alpha: false,
            pulse_amplitude: 0.0,
            pulse_frequency: 0.0,
            orbit_center: Vec3::new(0.0, 0.0, 0.0),
            orbit_radius: 0.0,
            orbit_axis: Vec3::new(0.0, 1.0, 0.0),
            orbit_speed: 0.0,
        }
    }
}

/// Entities spawned for a single effect, returned by
/// [`spawn_vfx`](crate::ecs::vfx::presets::spawn_vfx) so the whole effect can
/// be torn down with [`despawn_vfx`](crate::ecs::vfx::presets::despawn_vfx).
#[derive(Debug, Clone, Default)]
pub struct VfxHandle {
    pub entities: Vec<Entity>,
}