--clip FRAMES_DIR --truth MASKS_DIR runs the trackers on image sequences with true
mattes (strokes made from the truth; nothing is bundled or copied), tested end to end.
Trackers report the most memory their banks held (peakMB column).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Simulated user paints a foreground stroke through the true object and a background
stroke on the biggest false positive on the first frame under IoU 0.9, up to 6
rounds. SAM 2 needs none on every clip; classical and MobileSAM need more than 6 on
occlusion and re-entry. All trackers now take strokes on any frame.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
--mobilesam FILE; results recorded in docs/roto-brush-sam2.md (re-entry clip:
0.632 classical, 0.499 MobileSAM, 0.975 SAM 2).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
run_tracker follows the object with the model's video tracker on the same
synthetic clips (--sam2 FILE or the installed weights). 12 frames, dev build:
re-entry clip mean IoU 0.632 classical vs 0.975 SAM 2 (0.000 vs 0.967 after
the object returns); the other clips 0.98 vs 0.99.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Synthetic Roto Brush clips with known mattes (movement, lighting change,
occlusion, leaving and re-entering) and a runner that compares the classical
engine with MobileSAM when installed. Needs no weights; SAM 2 plugs in later.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Session::write_output (and refuse_export) is the one place that checks; Save Frame As
(PNG/PSD/EXR), Export Lottie, Save a Copy (+XML), Collect Files, Export Timeline (and its
pre-rendered movies), Export Template, Save Animation Preset, Export Guides and Export
Shortcuts write through it. The control channel's render.frame/ui.screenshot, MCP
render_frame and CLI render-frame --out check first (new query file.checkOutput for the
bridged cases). Save/Save As/auto-save are untouched.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Every undoable edit keeps the previous project for undo, so the comp it touches
is shared and Arc::make_mut deep-copies it: every layer and every keyframe. An
edit therefore costs time in proportion to the comp's size, and a script that
sets many keyframes in a big comp goes quadratic (a 1,600-layer build with
~100k sampled keys took ~45 minutes).
Comp::layers is now a Layers collection backed by Vec<Arc<Layer>>: copying the
stack copies pointers, and only the layer an edit changes is copied. The API
mirrors Vec<Layer>; serialized form is unchanged (a list of layers).
Comp::layer_mut and the iter_mut().filter/find call sites use find_mut /
iter_mut_where so they copy only the layers they actually change.
- prop.addKey in a 400-layer comp: 1.36 ms -> 0.16 ms per key (flat in comp size)
- the 1,600-layer script build: ~45 min -> 47 s, frames pixel-identical
- regression tests: an edit leaves the other layers shared with undo; layers
round-trip as a plain list
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG
The CLI installed no logger, so GPU warnings (a declined frame, out of
memory, fallback to the CPU) were dropped and an export silently rendered
on the CPU. Install the engine logger with a `warn` default (RUST_LOG
still overrides). Split out of #1415.
After Effects lists Targa among its still-image output formats; EffectCraft
imported Targa (#745) but could not render to it.
- OutputFormat::TargaSequence ("Targa Sequence", `.tga`, numbered like the
other sequences; `tga` / `targa` as a format name or output extension).
- Written by the `image` crate's Targa encoder (its `tga` feature, already
enabled in effectcraft-media; no new crates, Cargo.lock unchanged), with
run-length compression off: an 18-byte header, top-left origin, 24-bit BGR
for RGB, 32-bit BGRA with 8 alpha bits in the image descriptor for
RGB + Alpha (straight or premultiplied), 8-bit grey for Alpha.
- The render queue's size estimate counts the uncompressed bytes.
- CLI usage, the renderQueue command specs, README, architecture.md and
file-format-parity.md name the new format.
Tests: each Targa frame holds exactly the pixels of the PNG sequence of the
same job, with the expected header, numbering and size; the frames read back
through the Targa importer as the same picture (straight, and premultiplied
when interpreted so); the image-sequence round trip, the format parser and
the renderQueue commands cover it too.
xtask bench passed the whole layers scenario on one command line, longer
than Windows' 32 767-character limit (os error 206), so no scenario past
demo ran. effectcraft-cli run takes --args-file F (one argument per line)
and bench writes its commands there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A terminal already gets a live `[1/1] frame 16/180 ... ~14.2s left` line while
`effectcraft-cli render` runs. A program that starts the CLI (FilmCraft runs it to
render a composition for a clip) reads stderr through a pipe, so it saw nothing
until the render ended.
`--progress` prints one line per update instead, at most four a second:
progress <frames done> <frames total> <seconds elapsed> <seconds left, or - when unknown>
It has no effect on a terminal, which keeps its live line. Without the flag
nothing changes.
Documented in the usage text, the module header and docs/agents.md.
Tests: cargo fmt --check and cargo clippy --all-targets -D warnings pass; the
effectcraft-cli tests pass except render_out_is_relative_to_the_working_directory,
which already fails on Windows (it compares a canonicalize()d `\?\` path with the
path the CLI prints) and is unrelated to this change.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Keep ordinary --empty renders from loading the demo. Preserve explicit
project, template, and demo selection, and cover them with real GIF renders.
Sort the relative-footage test's expected paths consistently with its output.
Co-authored-by: Codex <codex@openai.com>
effectcraft-cli read its command line with std::env::args, which panics
on an argument that is not valid Unicode (a Latin-1 file name on Linux,
for example). `effectcraft-cli $'\xff'` or
`effectcraft-cli render-frame --out $'caf\xe9.png'` printed a panic from
std's env.rs and exited 101.
It now reads std::env::args_os and refuses such an argument as a usage
error (exit 2) that names it, before anything runs, like an unknown
option. A lossy copy is not used: every argument is a string here, and
`caf\u{fffd}.png` would read or write another file than the one named.
FilmCraft moved its CLI to args_os too (storytold/filmcraft#850).
Tests: a unit test for the conversion and a process test that runs the
CLI with a non-Unicode `--out` path (both unix-only). Before the fix the
process test fails (exit 101, not 2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compare device and inode on Linux alongside existing path checks. Cover
template and values aliases with input-preservation and diagnostic checks.
Sort the existing footage test's expected paths for temporary-directory portability.
Co-authored-by: Codex <codex@openai.com>
`effectcraft-cli mcp` had no way to keep an agent's file access to a folder;
the flags were unknown options. Both now take a folder (repeatable, as in
PhotoCraft): with either given, files are read only under a read or write root
and written only under a write root (none: no writes). Defaults are unchanged.
automation::confine::Confinement checks every engine command the backend runs
(execute_command, command_run, open/save_project, each engine.batch step), in
both headless and bridge mode, before it runs: the file parameters of the
commands that read or write files must be absolute paths inside the roots
(symbolic links resolved through the longest existing ancestor, `..` refused),
as must any other absolute path in a command's parameters. Commands that write
where they aren't told are checked against the target they would write: Save /
Increment and Save the open project's file, renderQueue.render every queued
output (renderQueue.list). Scripts, Execute File, Reveal in Finder, Open Recent
by index, `$N` file-path references in a batch, render_frame/screenshot paths
outside a write root and the bridge's UI-driving tools are refused while
confined. docs/mcp.md describes it.
Test: a confined headless server opens and saves inside its roots and is refused
outside them, for a relative path, `..`, a batch step, a `$N` path, Save to a
read-only root's project, the Render Queue's default output there, a symbolic
link out of the write root, and scripts; the unconfined server still writes
anywhere.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
`effectcraft-cli render --out proj/out/d.mp4 --project proj/x.ecproj` wrote
`proj/proj/out/d.mp4`: the Render Queue resolves a relative output against its own base, while
`--project` and every other CLI path are relative to the working directory. The CLI now makes
`--out` absolute against the working directory before queueing it, so the file lands where the
shell user expects; an absolute path is unchanged, and `rendered[].output` in the JSON result is
the absolute path. Render Queue outputs set inside a project (and `render --queue`) resolve as
before: tokens expanded, then `export.defaultOutputFolder`, the project's folder, the working
directory.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
get_project / render.backend reported "gpuAcceleration": true with
"active": "cpu" and no reason, which read as a broken GPU. The
headless MCP server only attaches the GPU compositor when started with
--gpu, which docs/agents.md didn't mention, and a failed --gpu said
only "no usable GPU adapter" (the adapter's error went to a log no
one sees). The session now keeps the host's reason there is no GPU
compositor (accel_note): the CLI's "headless: renders on the CPU
unless started with --gpu", or the desktop app's compositor setup or
retirement error. The status reports it as `why` whenever it renders
on the CPU (or that the project's renderer is Software Only). --gpu
failures include the adapter's error (Gpu::try_headless).
docs/agents.md documents `mcp --gpu`.
Test: render_backend_says_why_it_renders_on_the_cpu (engine).
Checked with effectcraft-cli mcp and mcp --gpu.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Args::parse kept any unrecognised `--option` as a valueless flag nobody
read, so `exec comp.new --bogus` ran with defaults and exit 0, and a
misspelt valued option left its value behind as a positional:
`--saveas z.ecproj` opened z.ecproj as the project and failed with an
unrelated "cannot read" error.
Options are now checked against the declared lists (VALUED and the new
FLAGS) before anything runs; unknown ones are a usage error naming them
(exit 2), and `--flag=value` on a flag says it takes no value.
render-frame's `--transparent` (the MCP render_frame option) was one of
the silently ignored options; it now keeps the frame's alpha.
Tests: unknown_options_are_refused, every_option_read_is_declared (every
option the code reads is declared, so none is refused),
unknown_options_are_usage_errors (exit 2, nothing runs or renders, and
--transparent renders alpha).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CLI printed with println!/eprintln!, which panic when the stream is
gone, so `exec --list | head` (or any output larger than the pipe buffer)
ended in a broken-pipe panic with exit status 101.
Output now goes through say!/note!, which never panic. Once stdout fails,
later output is dropped but the command still finishes its work (a
`run ... --save` sequence isn't cut short); a closed pipe is quiet and
exits 0, any other stdout error is reported and makes the exit status 1.
The MCP server ends quietly when its client closes stdout.
Test: a_closed_stdout_is_not_a_crash (info --json, exec --list, a saving
run sequence and mcp with stdout closed before they write).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These crates have no production panic sites: add the deny attribute so they stay clean
(geom, color, model, automation, host, export, plugin, and the desktop, CLI and web apps). The
plugin's wasm-only test module gets a separate cfg(test) attribute so clippy recognises it as
test code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- footage.check: background footage check after File > Open (Progress panel), not an undo step
- timeline: track-matte / parent menus built only while open (was O(n^2) per frame);
expression-row lookup per layer; panels hold Arc<Comp> snapshots instead of deep clones
- Project panel: virtualised vertical scrolling, selection reveal, thumbnails rendered off
the UI thread
- effectcraft-cli bench --ops (engine::perf + ui-egui::bench)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>