From 24aed7f2192a8f3fd53d8d13d8f69dcb984be90e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 22:13:19 +0000 Subject: [PATCH] App: launching opens an empty project, not the demo (#204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The desktop app opened the demo project whenever it wasn't given a project file, so File ▸ New Composition on the Home screen added "Comp 4" to the three demo comps. As in After Effects, a launch now starts with an empty Untitled Project. --demo opens the demo (Help ▸ Open Demo Project and the Home screen tile still do); --empty is kept. The arguments are parsed by a function now, with a test (no_arguments_start_an_empty_project). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f --- CONTRIBUTING.md | 2 +- README.md | 2 +- apps/effectcraft/src/main.rs | 75 +++++++++++++++++++++++++++--------- docs/agents.md | 3 +- 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 96beecf9..dfa28c9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ work apply to everyone, people and AI agents alike, and they are not negotiable. You need [Rust](https://rustup.rs/) 1.95 or newer. ```sh -cargo run -p effectcraft # the desktop app, with the demo project +cargo run -p effectcraft -- --demo # the desktop app, with the demo project cargo test --workspace cargo xtask ci # what every commit must pass ``` diff --git a/README.md b/README.md index a30f8001..f738bb1d 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ To build it yourself you need [Rust](https://rustup.rs/) 1.95 or newer. ```sh git clone https://github.com/storytold/effectcraft cd effectcraft -cargo run --release -p effectcraft # the app, with the demo project open +cargo run --release -p effectcraft # the app (add `-- --demo` to open the demo project) cargo run --release -p effectcraft-cli -- render --out intro.mp4 # render the demo headless cargo xtask web --serve 8765 # the browser build on http://127.0.0.1:8765/ (docs/web.md) ``` diff --git a/apps/effectcraft/src/main.rs b/apps/effectcraft/src/main.rs index 0db5d065..aa55a6de 100644 --- a/apps/effectcraft/src/main.rs +++ b/apps/effectcraft/src/main.rs @@ -2,6 +2,9 @@ //! //! Usage: `effectcraft [--control ] [--demo|--empty|--home] [project.ecproj | media files…]` //! +//! Without a project the app starts with an empty Untitled Project, as After Effects does; +//! `--demo` opens the demo project instead (also Help ▸ Open Demo Project). +//! //! `--control ` (or `EFFECTCRAFT_CONTROL_PORT`) starts a localhost JSON-lines control server; //! see `effectcraft_ui_egui::control` for the methods. #![cfg_attr(all(target_os = "windows", not(debug_assertions)), windows_subsystem = "windows")] @@ -32,28 +35,43 @@ fn app_icon() -> egui::IconData { eframe::icon_data::from_png_bytes(png).unwrap_or_default() } +/// The command line. +#[derive(Debug, Default, PartialEq)] +struct Args { + control_port: Option, + files: Vec, + /// Open the demo project when no project is given (`--demo`). + demo: bool, + /// Show or skip the Home screen (`--home`), else the Startup preference decides. + home: Option, +} + +/// Parse the arguments after the program name; `None` for `--version`. `env_port` is +/// `EFFECTCRAFT_CONTROL_PORT`. +fn parse_args(args: impl IntoIterator, env_port: Option) -> Option { + let mut out = Args { control_port: env_port.and_then(|p| p.parse().ok()), ..Default::default() }; + let mut args = args.into_iter(); + while let Some(a) = args.next() { + match a.as_str() { + "--control" => out.control_port = args.next().and_then(|p| p.parse().ok()), + "--demo" => out.demo = true, + "--empty" => out.demo = false, + "--home" => out.home = Some(true), + "--version" => return None, + _ => out.files.push(a), + } + } + Some(out) +} + fn main() -> eframe::Result { // Help ▸ Enable Logging writes through this logger; warnings feed the compatibility report. effectcraft_engine::logging::install(); effectcraft_engine::logging::install_panic_hook(); - let mut control_port: Option = std::env::var("EFFECTCRAFT_CONTROL_PORT").ok().and_then(|p| p.parse().ok()); - let mut files = Vec::new(); - let mut demo = true; - let mut home: Option = None; - let mut args = std::env::args().skip(1); - while let Some(a) = args.next() { - match a.as_str() { - "--control" => control_port = args.next().and_then(|p| p.parse().ok()), - "--demo" => demo = true, - "--empty" => demo = false, - "--home" => home = Some(true), - "--version" => { - println!("effectcraft {}", env!("CARGO_PKG_VERSION")); - return Ok(()); - } - _ => files.push(a), - } - } + let Some(Args { control_port, files, demo, home }) = parse_args(std::env::args().skip(1), std::env::var("EFFECTCRAFT_CONTROL_PORT").ok()) else { + println!("effectcraft {}", env!("CARGO_PKG_VERSION")); + return Ok(()); + }; // The font menus list the installed fonts: read their names while the window opens. effectcraft_engine::text::fonts::scan_system_in_background(); // Wayland shows the window's icon from its desktop entry: an AppImage brings its own. @@ -227,3 +245,24 @@ fn disable_app_nap() { std::mem::forget(info.beginActivityWithOptions_reason(opts, &reason)); } } + +#[cfg(test)] +mod tests { + use super::{Args, parse_args}; + + fn parse(args: &[&str]) -> Option { + parse_args(args.iter().map(|a| a.to_string()), None) + } + + /// Launching without a project opens an empty project, not the demo (#204). + #[test] + fn no_arguments_start_an_empty_project() { + assert_eq!(parse(&[]), Some(Args::default())); + assert!(parse(&["--demo"]).is_some_and(|a| a.demo)); + assert!(parse(&["--demo", "--empty"]).is_some_and(|a| !a.demo)); + let a = parse(&["--control", "9877", "--home", "a.ecproj"]).unwrap_or_default(); + assert_eq!((a.control_port, a.home, a.files), (Some(9877), Some(true), vec!["a.ecproj".to_string()])); + assert_eq!(parse(&["--version"]), None); + assert_eq!(parse_args(Vec::new(), Some("9000".into())).map(|a| a.control_port), Some(Some(9000))); + } +} diff --git a/docs/agents.md b/docs/agents.md index b4ea4763..36c3bd62 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -491,7 +491,8 @@ not read or written. ## Seeing the UI -To work on the UI, start the app with `cargo run -p effectcraft -- --control 9877` and use MCP bridge +To work on the UI, start the app with `cargo run -p effectcraft -- --control 9877` (add `--demo` to +open the demo project; without it the app starts with an empty project) and use MCP bridge mode or the raw control channel. A good loop is: `ui_elements` to find an id, `ui_click` or `ui_drag` to act, then `screenshot {"panel":"Timeline"}` to check the result. `render_frame` shows the composition itself at any zoom.