Files
effectcraft/crates/ui-egui/tests/render_queue_snapshot.rs
T
Brandon ThomasandClaude Opus 5.5 7f9c3a85c0 M10: render queue + export
- crates/export (effectcraft-export): render a comp's span to H.264 MP4 (+AAC),
  ProRes 422/4444 MOV (+PCM, alpha), PNG/JPEG/TIFF/EXR sequences and animated GIF
  via FilmCraft's pure-Rust encoders and MP4/MOV muxer; parallel batched frame
  rendering, progress callback with cancellation.
- project: Render Queue model (Render Settings, Output Module, output path
  templates, status) saved with the project.
- render: FootageSource::audio hook + comp audio mixdown (levels, in/out, solo,
  precomps); media implements it.
- engine: Exporter hook, background/blocking render job, renderQueue.* commands
  (add Cmd+M, remove, setRender, setRenderSettings, setOutputModule, setOutput,
  move, duplicate, render, stop, list, formats).
- host wires the exporter; CLI `render` subcommand.
- ui-egui: After Effects-style Render Queue panel with automation ids.
- tests: encode/decode round trips for every format (FilmCraft decoders,
  ffmpeg/ffprobe oracle when installed), audio, cancel, engine commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:02:06 -04:00

44 lines
2.3 KiB
Rust

//! Headless look at the Render Queue panel (wgpu offscreen). Ignored by default (needs a GPU
//! adapter); run with
//! `RQ_SNAPSHOT=/abs/out.png cargo test -p effectcraft-ui-egui --test render_queue_snapshot -- --ignored`.
use effectcraft_engine::Session;
use effectcraft_engine::project::render_queue::RenderStatus;
use effectcraft_ui_egui::EffectcraftApp;
use egui_kittest::Harness;
use serde_json::json;
#[test]
#[ignore]
fn render_queue_panel_snapshot() {
let mut s = Session::default();
s.execute("file.openDemoProject", json!({})).unwrap();
s.execute("renderQueue.add", json!({"output": "/renders/[compName].[fileExtension]", "resolution": "half", "timeSpan": "comp"})).unwrap();
s.execute("renderQueue.add", json!({"format": "prores", "channels": "rgba", "output": "/renders/[compName]_alpha.mov"})).unwrap();
s.execute("renderQueue.add", json!({"format": "png", "output": "/renders/frames/[compName]_[#####].png", "timeSpan": "workArea"})).unwrap();
s.execute("renderQueue.add", json!({"format": "gif", "resolution": "quarter"})).unwrap();
{
let p = std::sync::Arc::make_mut(&mut s.project);
p.render_queue[0].status = RenderStatus::Done;
p.render_queue[0].started = Some(1_790_000_000);
p.render_queue[0].render_time = Some(12.4);
p.render_queue[1].status = RenderStatus::Failed("disk full".into());
p.render_queue[1].started = Some(1_790_000_013);
p.render_queue[1].render_time = Some(0.8);
p.render_queue[3].render = false;
p.render_queue[3].status = RenderStatus::Unqueued;
}
let ids: Vec<u64> = s.project.render_queue.iter().take(3).map(|i| i.id).collect();
let mut app = Some(EffectcraftApp::new(s));
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| app.take().expect("app"));
h.ctx.data_mut(|d| d.insert_temp(egui::Id::new("rq-ui"), (ids, None::<u64>)));
h.state_mut().show_panel(effectcraft_ui_egui::dock::PanelKind::RenderQueue);
h.run_steps(4);
let img = h.render().expect("render");
let out = std::env::var("RQ_SNAPSHOT").unwrap_or_else(|_| concat!(env!("CARGO_MANIFEST_DIR"), "/../../target/test-out/render_queue.png").into());
if let Some(d) = std::path::Path::new(&out).parent() {
std::fs::create_dir_all(d).unwrap();
}
img.save(&out).unwrap();
}