mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-13 15:09:03 +00:00
App: launching opens an empty project, not the demo (#204)
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018gnTnH3Jmk5zr4tMq1Mc9f
This commit is contained in:
4 files changed
+61
-21
No files matched your search
+1
-1
@@ -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
|
||||
```
|
||||
|
||||
@@ -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)
|
||||
```
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
//!
|
||||
//! Usage: `effectcraft [--control <port>] [--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 <port>` (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<u16>,
|
||||
files: Vec<String>,
|
||||
/// 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<bool>,
|
||||
}
|
||||
|
||||
/// Parse the arguments after the program name; `None` for `--version`. `env_port` is
|
||||
/// `EFFECTCRAFT_CONTROL_PORT`.
|
||||
fn parse_args(args: impl IntoIterator<Item = String>, env_port: Option<String>) -> Option<Args> {
|
||||
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<u16> = 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<bool> = 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<Args> {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -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.
|
||||
Reference in new issue
Block a user