mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 11:17:12 -04: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 <[email protected]> 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.
|
You need [Rust](https://rustup.rs/) 1.95 or newer.
|
||||||
|
|
||||||
```sh
|
```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 test --workspace
|
||||||
cargo xtask ci # what every commit must pass
|
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
|
```sh
|
||||||
git clone https://github.com/storytold/effectcraft
|
git clone https://github.com/storytold/effectcraft
|
||||||
cd 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 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)
|
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…]`
|
//! 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;
|
//! `--control <port>` (or `EFFECTCRAFT_CONTROL_PORT`) starts a localhost JSON-lines control server;
|
||||||
//! see `effectcraft_ui_egui::control` for the methods.
|
//! see `effectcraft_ui_egui::control` for the methods.
|
||||||
#![cfg_attr(all(target_os = "windows", not(debug_assertions)), windows_subsystem = "windows")]
|
#![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()
|
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 {
|
fn main() -> eframe::Result {
|
||||||
// Help ▸ Enable Logging writes through this logger; warnings feed the compatibility report.
|
// Help ▸ Enable Logging writes through this logger; warnings feed the compatibility report.
|
||||||
effectcraft_engine::logging::install();
|
effectcraft_engine::logging::install();
|
||||||
effectcraft_engine::logging::install_panic_hook();
|
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 Some(Args { control_port, files, demo, home }) = parse_args(std::env::args().skip(1), std::env::var("EFFECTCRAFT_CONTROL_PORT").ok()) else {
|
||||||
let mut files = Vec::new();
|
println!("effectcraft {}", env!("CARGO_PKG_VERSION"));
|
||||||
let mut demo = true;
|
return Ok(());
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// The font menus list the installed fonts: read their names while the window opens.
|
// The font menus list the installed fonts: read their names while the window opens.
|
||||||
effectcraft_engine::text::fonts::scan_system_in_background();
|
effectcraft_engine::text::fonts::scan_system_in_background();
|
||||||
// Wayland shows the window's icon from its desktop entry: an AppImage brings its own.
|
// 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));
|
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
|
## 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`
|
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
|
to act, then `screenshot {"panel":"Timeline"}` to check the result. `render_frame` shows the
|
||||||
composition itself at any zoom.
|
composition itself at any zoom.
|
||||||
Reference in new issue
Block a user