bevy_director 0.5.0-dev

Unreal-Sequencer-inspired cinematic camera and sequence system for Bevy
Documentation
//! bevy_director: shots, sequences, and a camera you can direct.
//!
//! An Unreal-Sequencer-shaped cinematic layer for Bevy: sequences are RON
//! assets made of shots; shots are camera rigs with eased keys and a
//! lens; playback hands off from your gameplay camera and glides back to
//! it when the take ends. The viewfinder feature adds an in-game capture
//! mode: fly, frame, press K.
//!
//! Quickstart:
//! ```ignore
//! app.add_plugins(DirectorPlugin);
//! // gate your own camera-driving system:
//! //   my_camera_system.run_if(bevy_director::gameplay_camera_free)
//! commands.play_sequence(asset_server.load("sequences/intro.dir.ron"));
//! ```
//!
//! While the director owns the frame, the game should also yield its
//! keyboard, mouse, and cursor grabbing: gate them with [`director_idle`],
//! or bridge [`DirectorState::phase`](player::DirectorState) into your
//! game's state machine. The README's "Integrating with a live game"
//! section walks through the full checklist.

use bevy::{prelude::*, transform::TransformSystems};

pub mod curve;
pub mod eval;
pub mod letterbox;
pub mod loader;
pub mod player;
pub mod sequence;
mod shake;

#[cfg(feature = "editor")]
pub mod editor;
#[cfg(feature = "gizmos")]
pub mod gizmos;
#[cfg(feature = "titles")]
pub mod titles;
#[cfg(feature = "viewfinder")]
pub mod viewfinder;

pub use curve::ArcLengthLut;
#[cfg(feature = "editor")]
pub use editor::{
    DirectorsCutConfig, DirectorsCutGrid, DirectorsCutPlugin, DirectorsCutState, EditorSelection,
    KeyTrack,
};
pub use eval::{
    ActiveActorCue, ActiveText, BakeError, CameraPose, CameraSnapshot, CompiledSequence, DofParams,
    EvalCtx, bake,
};
pub use letterbox::LetterboxSettings;
pub use loader::{SequenceError, SequenceLoader, parse_sequence, to_ron_string};
pub use player::{
    ActiveActorCues, ActiveTexts, CineCamera, ClockSource, DirectorCommands, DirectorPhase,
    DirectorState, FinishReason, HandoffCamera, LoopMode, MarkerReached, PlayOptions, Playback,
    SequenceFinished, SequencePlayer, SequenceStarted, director_active, director_idle,
    gameplay_camera_free,
};
pub use sequence::{
    ActorCue, ActorTrack, Blend, DofMode, Filmback, FocusTrack, FovSpec, Key, KeyInterp, Lens,
    Look, Marker, RailKind, Rig, ScalarKey, ScalarTrack, SequenceAsset, Shake, Shot, TargetRef,
    TextAnchor, TextBlock, TextBlockStyle,
};
#[cfg(feature = "titles")]
pub use titles::{TitleAnchorZone, TitleOverlayRoot, TitlesConfig, TitlesPlugin};
#[cfg(feature = "viewfinder")]
pub use viewfinder::{ViewfinderConfig, ViewfinderPlugin, ViewfinderSession};

pub mod prelude {
    pub use crate::{
        ActiveActorCue, ActiveActorCues, ActiveText, ActiveTexts, ActorCue, ActorTrack, Blend,
        CineCamera, DirectorCommands, DirectorPhase, DirectorPlugin, DirectorState, Filmback,
        FinishReason, FocusTrack, FovSpec, HandoffCamera, Key, Lens, LetterboxSettings, Look,
        Marker, MarkerReached, PlayOptions, RailKind, Rig, ScalarKey, ScalarTrack, SequenceAsset,
        SequenceFinished, SequencePlayer, SequenceStarted, Shake, Shot, TargetRef, TextAnchor,
        TextBlock, TextBlockStyle, gameplay_camera_free,
    };
    #[cfg(feature = "editor")]
    pub use crate::{
        DirectorsCutConfig, DirectorsCutGrid, DirectorsCutPlugin, DirectorsCutState,
        EditorSelection, KeyTrack,
    };
    #[cfg(feature = "titles")]
    pub use crate::{TitlesConfig, TitlesPlugin};
    #[cfg(feature = "viewfinder")]
    pub use crate::{ViewfinderConfig, ViewfinderPlugin, ViewfinderSession};
}

/// The director's PostUpdate passes, chained, before transform
/// propagation: a pose written this frame renders this frame.
#[derive(SystemSet, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum DirectorSet {
    /// Requests, orphan guard, hot reload.
    Control,
    /// Playhead advance, markers, end-of-sequence routing.
    Tick,
    /// Writing the pose onto the camera.
    Apply,
}

/// Core plugin: asset type and loader, messages, the playback state
/// machine. The viewfinder is its own plugin (feature "viewfinder").
pub struct DirectorPlugin;

impl Plugin for DirectorPlugin {
    fn build(&self, app: &mut App) {
        app.init_asset::<SequenceAsset>()
            .register_asset_loader(SequenceLoader)
            .register_type::<SequenceAsset>()
            .init_resource::<DirectorState>()
            .init_resource::<ActiveTexts>()
            .init_resource::<ActiveActorCues>()
            .add_message::<player::DirectorRequest>()
            .add_message::<SequenceStarted>()
            .add_message::<MarkerReached>()
            .add_message::<SequenceFinished>()
            .configure_sets(
                PostUpdate,
                (DirectorSet::Control, DirectorSet::Tick, DirectorSet::Apply)
                    .chain()
                    .before(TransformSystems::Propagate),
            )
            .add_systems(
                PostUpdate,
                (
                    player::handle_requests,
                    player::rebake_on_asset_change,
                    player::guard_orphans,
                )
                    .chain()
                    .in_set(DirectorSet::Control),
            )
            .add_systems(PostUpdate, player::tick_players.in_set(DirectorSet::Tick))
            .add_systems(
                PostUpdate,
                (
                    player::apply_pose,
                    letterbox::sync_letterbox,
                    player::update_active_texts,
                    player::update_active_actor_cues,
                )
                    .chain()
                    .in_set(DirectorSet::Apply),
            );
    }
}