summaryrefslogtreecommitdiff
path: root/rust/crates/scene
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-07-28 20:14:51 +0200
committercashmere <cashmere@autistici.org>2026-07-28 20:14:51 +0200
commit32438ce25f69de99d2523b98237f62cfa90890d7 (patch)
tree3a712c347dec0889bdea3328b4c817c2d9392b27 /rust/crates/scene
parentf5a82152394fde4d8f740f664ab7737b82861618 (diff)
downloadopencut-32438ce25f69de99d2523b98237f62cfa90890d7.tar.gz
feat: port domain crates to Rust (session 1 complete)
All green: cargo test --workspace (~300 tests, 0 failures). - timeline (45): placement, resize/ripple, split, snap, retime, audio separation, scene helpers - animation (73): bezier solver, channel sampling, keyframe ops, split/clamp/clone, param definitions - commands (9): Command trait, BatchCommand, history, 19 concrete commands, freeze-frame port 1:1 - audio (22): audible collection, range mixing, mastering limiter, rms/peak buckets - text (19): cosmic-text layout/measure/raster, backgrounds, decorations - graphics (52): full CSS gradient parser, tiny-skia raster, 4 shape definitions - effect-defs (16): blur definition, registry, pass resolution - mask-defs (19): all 9 mask renderers via tiny-skia - renderer (6): node model + scene builder port - desktop: GPUI projects screen wired to ProjectStore - scene: factory (web defaults: v32, Main Track, 1920x1080, 30fps)
Diffstat (limited to 'rust/crates/scene')
-rw-r--r--rust/crates/scene/Cargo.toml1
-rw-r--r--rust/crates/scene/src/factory.rs113
-rw-r--r--rust/crates/scene/src/lib.rs2
3 files changed, 116 insertions, 0 deletions
diff --git a/rust/crates/scene/Cargo.toml b/rust/crates/scene/Cargo.toml
index f81e1457..02d80ec3 100644
--- a/rust/crates/scene/Cargo.toml
+++ b/rust/crates/scene/Cargo.toml
@@ -8,3 +8,4 @@ chrono = { version = "0.4", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
time = { version = "0.1.0", path = "../time" }
+uuid = { version = "1", features = ["v4"] }
diff --git a/rust/crates/scene/src/factory.rs b/rust/crates/scene/src/factory.rs
new file mode 100644
index 00000000..d9a8e8a0
--- /dev/null
+++ b/rust/crates/scene/src/factory.rs
@@ -0,0 +1,113 @@
+use chrono::{DateTime, TimeZone, Utc};
+use time::{FrameRate, MediaTime};
+use uuid::Uuid;
+
+use crate::project::{
+ Background, CanvasSize, CanvasSizeMode, Project, ProjectMetadata, ProjectSettings,
+};
+use crate::scene::Scene;
+use crate::track::{SceneTracks, Track};
+
+pub const MAIN_TRACK_NAME: &str = "Main Track";
+pub const CURRENT_PROJECT_VERSION: u32 = 32;
+pub const DEFAULT_BACKGROUND_COLOR: &str = "#000000";
+pub const DEFAULT_CANVAS_SIZE: CanvasSize = CanvasSize {
+ width: 1920,
+ height: 1080,
+};
+pub const DEFAULT_FPS: FrameRate = FrameRate {
+ numerator: 30,
+ denominator: 1,
+};
+
+pub fn generate_id() -> String {
+ Uuid::new_v4().to_string()
+}
+
+fn now_millis() -> DateTime<Utc> {
+ Utc.timestamp_millis_opt(Utc::now().timestamp_millis()).unwrap()
+}
+
+pub fn build_default_scene(name: impl Into<String>, is_main: bool) -> Scene {
+ let now = now_millis();
+ Scene {
+ id: generate_id(),
+ name: name.into(),
+ is_main,
+ tracks: SceneTracks {
+ overlay: Vec::new(),
+ main: Track::Video {
+ id: generate_id(),
+ name: MAIN_TRACK_NAME.to_string(),
+ elements: Vec::new(),
+ muted: false,
+ hidden: false,
+ },
+ audio: Vec::new(),
+ },
+ bookmarks: Vec::new(),
+ created_at: now,
+ updated_at: now,
+ }
+}
+
+pub fn new_project(name: impl Into<String>) -> Project {
+ let main_scene = build_default_scene("Main scene", true);
+ let now = now_millis();
+ Project {
+ metadata: ProjectMetadata {
+ id: generate_id(),
+ name: name.into(),
+ thumbnail: None,
+ duration: MediaTime::ZERO,
+ created_at: now,
+ updated_at: now,
+ },
+ current_scene_id: main_scene.id.clone(),
+ scenes: vec![main_scene],
+ settings: ProjectSettings {
+ fps: DEFAULT_FPS,
+ canvas_size: DEFAULT_CANVAS_SIZE,
+ canvas_size_mode: Some(CanvasSizeMode::Preset),
+ last_custom_canvas_size: None,
+ original_canvas_size: None,
+ background: Background::Color {
+ color: DEFAULT_BACKGROUND_COLOR.to_string(),
+ },
+ },
+ version: CURRENT_PROJECT_VERSION,
+ timeline_view_state: None,
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn new_project_matches_web_defaults() {
+ let project = new_project("Untitled Project");
+ assert_eq!(project.version, 32);
+ assert_eq!(project.scenes.len(), 1);
+ assert!(project.scenes[0].is_main);
+ assert_eq!(project.current_scene_id, project.scenes[0].id);
+ assert_eq!(project.settings.canvas_size.width, 1920);
+ assert_eq!(project.settings.fps.numerator, 30);
+ match &project.scenes[0].tracks.main {
+ Track::Video { name, .. } => assert_eq!(name, "Main Track"),
+ _ => panic!("main track must be video"),
+ }
+ match &project.settings.background {
+ Background::Color { color } => assert_eq!(color, "#000000"),
+ _ => panic!("default background must be color"),
+ }
+ }
+
+ #[test]
+ fn new_project_round_trips_through_json() {
+ let project = new_project("Test");
+ let json = serde_json::to_value(&project).unwrap();
+ let parsed: Project = serde_json::from_value(json).unwrap();
+ assert_eq!(parsed, project);
+ }
+}
diff --git a/rust/crates/scene/src/lib.rs b/rust/crates/scene/src/lib.rs
index d18925ff..efc778d7 100644
--- a/rust/crates/scene/src/lib.rs
+++ b/rust/crates/scene/src/lib.rs
@@ -1,6 +1,7 @@
pub mod animation;
pub mod effect;
pub mod element;
+pub mod factory;
pub mod iso_date;
pub mod mask;
pub mod params;
@@ -11,6 +12,7 @@ pub mod track;
pub use animation::*;
pub use effect::*;
pub use element::*;
+pub use factory::*;
pub use mask::*;
pub use params::*;
pub use project::*;