Skip to main content

motion_canvas_rs/
project.rs

1use crate::core::scene::BaseScene;
2use crate::core::scene::Scene2D;
3use peniko::Color;
4use std::path::PathBuf;
5
6const DEFAULT_FPS: u32 = 60;
7const DEFAULT_WIDTH: u32 = 800;
8const DEFAULT_HEIGHT: u32 = 600;
9const DEFAULT_TITLE: &str = "motion-canvas-rs";
10const DEFAULT_OUTPUT_PATH: &str = "output";
11const DEFAULT_BACKGROUND_COLOR: Color = Color::rgb8(0x1a, 0x1a, 0x1a);
12const DEFAULT_USE_CACHE: bool = true;
13const DEFAULT_USE_GPU: bool = true;
14const DEFAULT_USE_FFMPEG: bool = false;
15const DEFAULT_CACHE_WRITE_INTERVAL: u32 = 500;
16
17/// The central configuration and state for a motion canvas animation.
18///
19/// `Project` stores all metadata about the animation, including dimensions,
20/// frame rate, and export settings. It also owns the [`BaseScene`] which
21/// contains the actual animation nodes.
22pub struct Project {
23    /// Target width of the animation.
24    pub width: u32,
25    /// Target height of the animation.
26    pub height: u32,
27    /// Frames per second.
28    pub fps: u32,
29    /// Human-readable title of the project.
30    pub title: String,
31    /// The root scene orchestration node.
32    pub scene: BaseScene,
33    /// Directory where exported frames and videos will be saved.
34    pub output_path: PathBuf,
35    /// Whether to use frame-level caching during export.
36    pub use_cache: bool,
37    /// Whether to automatically attempt FFmpeg encoding after export.
38    pub use_ffmpeg: bool,
39    /// Whether to use GPU acceleration for rendering.
40    pub use_gpu: bool,
41    /// Background clear color for the animation.
42    pub background_color: Color,
43    /// If true, the playback window will close automatically when the animation ends.
44    pub close_on_finish: bool,
45    /// The current playback/export time.
46    pub current_time: std::time::Duration,
47    /// Playback state (paused or playing).
48    pub paused: bool,
49    /// Playback speed multiplier.
50    pub speed: f32,
51    /// The master playback timeline state.
52    pub timeline: crate::core::Timeline,
53    /// The number of frames between incremental cache manifest writes to disk.
54    pub cache_write_interval: u32,
55}
56
57impl Project {
58    /// Creates a new project with the given dimensions and default settings.
59    pub fn new(width: u32, height: u32) -> Self {
60        Self {
61            width,
62            height,
63            fps: DEFAULT_FPS,
64            title: DEFAULT_TITLE.to_string(),
65            scene: BaseScene::new(),
66            output_path: PathBuf::from(DEFAULT_OUTPUT_PATH),
67            use_cache: DEFAULT_USE_CACHE,
68            use_ffmpeg: DEFAULT_USE_FFMPEG,
69            use_gpu: DEFAULT_USE_GPU,
70            background_color: DEFAULT_BACKGROUND_COLOR,
71            close_on_finish: false,
72            current_time: std::time::Duration::ZERO,
73            paused: false,
74            speed: 1.0,
75            timeline: crate::core::Timeline::new(),
76            cache_write_interval: DEFAULT_CACHE_WRITE_INTERVAL,
77        }
78    }
79}
80
81impl Default for Project {
82    fn default() -> Self {
83        Self::new(DEFAULT_WIDTH, DEFAULT_HEIGHT)
84    }
85}
86
87impl Project {
88    /// Sets the target frames per second.
89    pub fn with_fps(mut self, fps: u32) -> Self {
90        self.fps = fps;
91        self
92    }
93
94    /// Sets the width and height of the animation.
95    pub fn with_dimensions(mut self, width: u32, height: u32) -> Self {
96        self.width = width;
97        self.height = height;
98        self
99    }
100
101    /// Sets the project title.
102    pub fn with_title(mut self, title: &str) -> Self {
103        self.title = title.to_string();
104        self
105    }
106
107    /// Sets the output directory for exports.
108    pub fn with_output_path(mut self, path: &str) -> Self {
109        self.output_path = PathBuf::from(path);
110        self
111    }
112
113    /// Enables or disables frame-level caching.
114    pub fn with_cache(mut self, use_cache: bool) -> Self {
115        self.use_cache = use_cache;
116        self
117    }
118
119    /// Sets the cache manifest write interval (number of frames).
120    pub fn with_cache_write_interval(mut self, interval: u32) -> Self {
121        self.cache_write_interval = interval;
122        self
123    }
124
125    /// Enables or disables automatic FFmpeg encoding.
126    pub fn with_ffmpeg(mut self, use_ffmpeg: bool) -> Self {
127        self.use_ffmpeg = use_ffmpeg;
128        self
129    }
130
131    /// Enables or disables GPU acceleration.
132    pub fn with_gpu(mut self, use_gpu: bool) -> Self {
133        self.use_gpu = use_gpu;
134        self
135    }
136
137    /// Sets the background clear color.
138    pub fn with_background(mut self, color: Color) -> Self {
139        self.background_color = color;
140        self
141    }
142
143    /// Sets whether the window should close automatically on finish.
144    pub fn with_close_on_finish(mut self, close: bool) -> Self {
145        self.close_on_finish = close;
146        self
147    }
148
149    /// Convenience method to enable automatic window closing on finish.
150    pub fn close_on_finish(self) -> Self {
151        self.with_close_on_finish(true)
152    }
153
154    /// Resets the scene and advances it to the specified target time.
155    ///
156    /// This is used for seeking in the interactive preview.
157    pub fn seek_to(&mut self, target_time: std::time::Duration) {
158        self.scene.reset();
159        self.current_time = std::time::Duration::ZERO;
160        let dt = std::time::Duration::from_secs_f32(1.0 / self.fps as f32);
161        while self.current_time < target_time {
162            self.scene.update(dt);
163            self.current_time += dt;
164        }
165    }
166
167    /// Returns the sanitized filename for a specific frame index.
168    pub fn get_frame_name(&self, frame_index: u32) -> String {
169        let sanitized = crate::assets::sanitize_title(&self.title);
170        format!("{}_{:04}.png", sanitized, frame_index)
171    }
172}