M5.11: Effects panel Legacy bin and alphabetical folders, Text param editing, vfx goldens and docs

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Brandon ThomasandClaude Opus 5.5 committed 2026-10-02 11:04:45 -04:00
1 parent 2e278c8ff0
commit 3139e63870
19 files changed
+177 -6

No files matched your search

+6
View File
@@ -52,6 +52,12 @@ procedural demo footage (`crates/media/src/generators.rs`); no external media. R
| `crates/golden/goldens/mask_color.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `mask_color`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/mask_inverted.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `mask_inverted`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/mask_opacity.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `mask_opacity`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/vfx_distort.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `vfx_distort`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/vfx_ultra_key.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `vfx_ultra_key`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/vfx_glows.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `vfx_glows`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/vfx_spacer_stroke_shadow.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `vfx_spacer_stroke_shadow`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/vfx_vr_rotate.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `vfx_vr_rotate`) from procedurally generated media | MIT OR Apache-2.0 |
| `crates/golden/goldens/vfx_stylize.png` | FilmCraft contributors | Original work: golden reference rendered by FilmCraft (crates/golden/tests/golden.rs, scene `vfx_stylize`) from procedurally generated media | MIT OR Apache-2.0 |
## Third-party media shown in screenshots
+1 -1
View File
@@ -134,7 +134,7 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels,
<p align="center"><sub>NASA's <i>Earth Views from the ISS</i> with a look applied, and the Effects browser open on the dissolves.</sub></p>
- **Around 55 video effects and 30 transitions.** Blurs, keys, distortions, stylize and colour effects. Cross dissolve, dip to black or white, film dissolve, wipes, irises, pushes, slides, zooms, page peel, cube spin and more.
- **Premiere 26's full Video Effects bin (93 effects in 16 folders), the Legacy bin and the obsolete effects old projects use, plus around 30 transitions.** Blurs (Bokeh, Focus, Compound), keys (Ultra Key, Track Matte), distortions (Corner Pin, Turbulent Displace, Warp Stabilizer), Lights & Glows, Immersive Video (VR) effects on equirectangular footage, Posterize Time, Echo and more. Cross dissolve, dip to black or white, film dissolve, wipes, irises, pushes, slides, zooms, page peel, cube spin and more.
- **Motion and opacity on every clip:** position, scale, rotation, anchor point and anti-flicker, plus 26 blend modes.
- **Keyframes like Premiere's:** linear, Bezier, auto and continuous Bezier, hold, ease in and ease out. Effect Controls shows a keyframe lane for every parameter, and each animated parameter opens into **value and velocity graphs** with draggable influence handles.
- **A GPU compositor** built on wgpu (Metal, Vulkan, DirectX 12, WebGPU). It samples YUV straight from the decoder with footprint supersampling and blends in linear light. A CPU path renders the same frames, and the two are tested against each other.
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

@@ -0,0 +1,8 @@
asset: vfx_distort.png
title: Corner Pin over Turbulent Displace
author: FilmCraft contributors
source: original work (rendered by FilmCraft's own renderer from a procedurally generated project; no external media)
license: MIT OR Apache-2.0
license-file:
added: 2026-10-02 by FilmCraft contributors (FILMCRAFT_BLESS=1)
notes: Golden reference image generated by crates/golden/tests/golden.rs (vfx_distort). Regenerate with FILMCRAFT_BLESS=1. Contains no Adobe artwork.
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@@ -0,0 +1,8 @@
asset: vfx_glows.png
title: Wonder Glow and Glint
author: FilmCraft contributors
source: original work (rendered by FilmCraft's own renderer from a procedurally generated project; no external media)
license: MIT OR Apache-2.0
license-file:
added: 2026-10-02 by FilmCraft contributors (FILMCRAFT_BLESS=1)
notes: Golden reference image generated by crates/golden/tests/golden.rs (vfx_glows). Regenerate with FILMCRAFT_BLESS=1. Contains no Adobe artwork.
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,8 @@
asset: vfx_spacer_stroke_shadow.png
title: Spacer, Stroke and Long Shadow over a Gradient
author: FilmCraft contributors
source: original work (rendered by FilmCraft's own renderer from a procedurally generated project; no external media)
license: MIT OR Apache-2.0
license-file:
added: 2026-10-02 by FilmCraft contributors (FILMCRAFT_BLESS=1)
notes: Golden reference image generated by crates/golden/tests/golden.rs (vfx_spacer_stroke_shadow). Regenerate with FILMCRAFT_BLESS=1. Contains no Adobe artwork.
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

@@ -0,0 +1,8 @@
asset: vfx_stylize.png
title: Channel Mix, Color Emboss and Rounded Crop
author: FilmCraft contributors
source: original work (rendered by FilmCraft's own renderer from a procedurally generated project; no external media)
license: MIT OR Apache-2.0
license-file:
added: 2026-10-02 by FilmCraft contributors (FILMCRAFT_BLESS=1)
notes: Golden reference image generated by crates/golden/tests/golden.rs (vfx_stylize). Regenerate with FILMCRAFT_BLESS=1. Contains no Adobe artwork.
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -0,0 +1,8 @@
asset: vfx_ultra_key.png
title: Ultra Key on colour bars over footage
author: FilmCraft contributors
source: original work (rendered by FilmCraft's own renderer from a procedurally generated project; no external media)
license: MIT OR Apache-2.0
license-file:
added: 2026-10-02 by FilmCraft contributors (FILMCRAFT_BLESS=1)
notes: Golden reference image generated by crates/golden/tests/golden.rs (vfx_ultra_key). Regenerate with FILMCRAFT_BLESS=1. Contains no Adobe artwork.
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@@ -0,0 +1,8 @@
asset: vfx_vr_rotate.png
title: VR Rotate Sphere
author: FilmCraft contributors
source: original work (rendered by FilmCraft's own renderer from a procedurally generated project; no external media)
license: MIT OR Apache-2.0
license-file:
added: 2026-10-02 by FilmCraft contributors (FILMCRAFT_BLESS=1)
notes: Golden reference image generated by crates/golden/tests/golden.rs (vfx_vr_rotate). Regenerate with FILMCRAFT_BLESS=1. Contains no Adobe artwork.
+94 -1
View File
@@ -460,6 +460,87 @@ fn mask_opacity() -> Scene {
b.at(12)
}
/// M5.11 Distort: Corner Pin (a demo picture pinned into a quad) over Turbulent-Displaced bars.
fn vfx_distort() -> Scene {
let mut b = Builder::new(2);
let bars = b.media(Generator::BarsAndTone);
let fg = b.demo(DemoScene::Dunes);
let c = b.place(0, bars, 0, 48);
b.effect(c, "turbulent_displace", &[("amount", fl(40.0)), ("size", fl(80.0)), ("complexity", fl(2.0))]);
let top = b.place(1, fg, 0, 48);
b.effect(
top,
"corner_pin",
&[("upper_left", pt(120.0, 60.0)), ("upper_right", pt(560.0, 20.0)), ("lower_left", pt(60.0, 330.0)), ("lower_right", pt(520.0, 300.0))],
);
b.at(12)
}
/// M5.11 Keying: Ultra Key removing the bars' green over a demo background, with spill suppression.
fn vfx_ultra_key() -> Scene {
let mut b = Builder::new(2);
let bg = b.demo(DemoScene::OceanSunset);
let bars = b.media(Generator::BarsAndTone);
b.place(0, bg, 0, 48);
let top = b.place(1, bars, 0, 48);
b.effect(top, "ultra_key", &[("key_color", ParamValue::Color([0.0, 0.75, 0.0, 1.0]))]);
b.at(12)
}
/// M5.11 Lights & Glows: Wonder Glow and Glint on a night city.
fn vfx_glows() -> Scene {
let mut b = Builder::new(1);
let city = b.demo(DemoScene::CityNight);
let c = b.place(0, city, 0, 48);
b.effect(c, "wonder_glow", &[("threshold", fl(55.0)), ("radius", fl(20.0))]);
b.effect(c, "glint", &[("threshold", fl(80.0)), ("length", fl(40.0))]);
b.at(12)
}
/// M5.11 Utility / Perspective: Spacer inset with rounded corners, an inside Stroke and a fading
/// Long Shadow, over a Gradient generator.
fn vfx_spacer_stroke_shadow() -> Scene {
let mut b = Builder::new(2);
let bg = b.media(Generator::BlackVideo);
let fg = b.demo(DemoScene::Forest);
let back = b.place(0, bg, 0, 48);
b.effect(
back,
"gradient",
&[
("start", pt(0.0, 0.0)),
("end", pt(640.0, 360.0)),
("start_color", ParamValue::Color([0.15, 0.2, 0.45, 1.0])),
("end_color", ParamValue::Color([0.9, 0.6, 0.3, 1.0])),
],
);
let top = b.place(1, fg, 0, 48);
b.effect(top, "spacer", &[("left", fl(90.0)), ("radius", fl(30.0))]);
b.effect(top, "stroke", &[("width", fl(6.0)), ("position", ParamValue::Choice(2))]);
b.effect(top, "long_shadow", &[("length", fl(80.0)), ("opacity", fl(70.0))]);
b.at(12)
}
/// M5.11 Immersive Video: VR Rotate Sphere (pan and tilt) on equirectangular-treated aurora.
fn vfx_vr_rotate() -> Scene {
let mut b = Builder::new(1);
let aur = b.demo(DemoScene::Aurora);
let c = b.place(0, aur, 0, 48);
b.effect(c, "vr_rotate_sphere", &[("pan", fl(90.0)), ("tilt", fl(25.0)), ("roll", fl(10.0))]);
b.at(12)
}
/// M5.11 Stylize / Image Control: Rounded Crop, Color Emboss and Channel Mix on plasma.
fn vfx_stylize() -> Scene {
let mut b = Builder::new(1);
let pl = b.demo(DemoScene::Plasma);
let c = b.place(0, pl, 0, 48);
b.effect(c, "channel_mix", &[("rr", fl(0.0)), ("rb", fl(100.0)), ("bb", fl(0.0)), ("br", fl(100.0))]);
b.effect(c, "color_emboss", &[("relief", fl(3.0)), ("contrast", fl(150.0))]);
b.effect(c, "rounded_crop", &[("left", fl(8.0)), ("right", fl(8.0)), ("top", fl(8.0)), ("bottom", fl(8.0)), ("radius", fl(50.0)), ("border", fl(4.0))]);
b.at(12)
}
/// (name, title, scene).
fn scenes() -> Vec<(&'static str, &'static str, fn() -> Scene)> {
vec![
@@ -480,6 +561,12 @@ fn scenes() -> Vec<(&'static str, &'static str, fn() -> Scene)> {
("mask_color", "Masks: Black & White inside an expanded polygon minus a feathered Bezier mask", mask_color),
("mask_inverted", "Masks: Mosaic outside an inverted ellipse mask at 80% opacity", mask_inverted),
("mask_opacity", "Masks: feathered ellipse opacity mask on a rotated top layer", mask_opacity),
("vfx_distort", "Corner Pin over Turbulent Displace", vfx_distort),
("vfx_ultra_key", "Ultra Key on colour bars over footage", vfx_ultra_key),
("vfx_glows", "Wonder Glow and Glint", vfx_glows),
("vfx_spacer_stroke_shadow", "Spacer, Stroke and Long Shadow over a Gradient", vfx_spacer_stroke_shadow),
("vfx_vr_rotate", "VR Rotate Sphere", vfx_vr_rotate),
("vfx_stylize", "Channel Mix, Color Emboss and Rounded Crop", vfx_stylize),
]
}
@@ -538,7 +625,13 @@ goldens!(
mask_blur,
mask_color,
mask_inverted,
mask_opacity
mask_opacity,
vfx_distort,
vfx_ultra_key,
vfx_glows,
vfx_spacer_stroke_shadow,
vfx_vr_rotate,
vfx_stylize
);
/// Sanity: the scenes are not trivially empty or identical to each other.
@@ -293,6 +293,22 @@ pub(crate) fn param_row(
(ParamKind::Path, _) => {
crate::panels::masks::path_value(app, &mut vui, clip, idx, mask, actions);
}
(ParamKind::Text, ParamValue::Text(s)) if !pd.id.ends_with("_lut") => {
// edited in a buffer; committed (one undo step) when the field loses focus
let mut buf = vui.data_mut(|d| d.get_temp::<String>(id)).unwrap_or_else(|| s.clone());
let r = vui.add(egui::TextEdit::singleline(&mut buf).desired_width(160.0));
app.auto.add(&format!("effectControls.text.{}.{}", idx, pd.id), r.rect, pd.label);
if r.lost_focus() {
if buf != *s {
set = Some(json!(buf));
}
vui.data_mut(|d| d.remove::<String>(id));
} else if r.has_focus() {
vui.data_mut(|d| d.insert_temp(id, buf));
} else {
vui.data_mut(|d| d.remove::<String>(id));
}
}
_ => {
vui.label(param_text(&app.session.project, pd.id, &value));
}
+6 -2
View File
@@ -21,7 +21,7 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
let filter = q.to_ascii_lowercase();
let defs = filmcraft_project::effect_defs();
// folder tree: top-level categories in Premiere's order
let tops = ["Presets", "Lumetri Presets", "Audio Effects", "Audio Transitions", "Video Effects", "Video Transitions"];
let tops = ["Presets", "Lumetri Presets", "Audio Effects", "Audio Transitions", "Video Effects", "Video Transitions", "Legacy"];
let mut apply: Option<String> = None;
let mut preset_action: Option<(String, String)> = None;
egui::ScrollArea::vertical().id_salt("fx-scroll").auto_shrink([false, false]).show(&mut bui, |ui| {
@@ -33,11 +33,15 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
}
continue;
}
let items: Vec<_> = defs
let mut items: Vec<_> = defs
.iter()
.filter(|d| d.category.first() == Some(&top))
.filter(|d| filter.is_empty() || d.name.to_ascii_lowercase().contains(&filter))
.collect();
// Premiere lists effect folders and effects alphabetically (obsolete ones last)
if top == "Video Effects" || top == "Legacy" {
items.sort_by_key(|d| (d.category.get(1) == Some(&"Obsolete"), d.category.get(1).copied().unwrap_or(""), d.name.to_ascii_lowercase()));
}
if !filter.is_empty() && items.is_empty() {
continue;
}
+1 -1
View File
@@ -57,7 +57,7 @@ and `filmcraft-cli`.
| `speech` | L2 | speech-to-text: `Transcriber` trait, Whisper model catalogue + verified downloader (feature `download`), pure-Rust Whisper inference on candle with word timestamps (feature `whisper`), speaker labelling ([transcripts.md](transcripts.md)) |
| `codecs` | L2 | container + codec hub: MP4/MOV and MKV sources, GOP-aware seeking, decoder registry, audio decoding |
| `interchange` | L2 | EDL, FCP7 XML, FCPXML and OTIO import/export (no file I/O) |
| `render` | L3 | sequence evaluation, CPU compositor, video effects, transitions, audio mix |
| `render` | L3 | sequence evaluation, CPU compositor, video effects (`effects`, `vfx`; effects needing other frames or tracks read them through `vfx::FxEnv`), transitions, audio mix |
| `gpu` | L3 | wgpu compositor (WGSL) |
| `golden` | L3 | test-only: golden-image tests of the CPU renderer and GPU-vs-CPU parity; empty library, dev-dependencies only |
| `export` | L3 | render → encode → mux pipeline, progress/cancel |
+5 -1
View File
@@ -101,7 +101,11 @@ Each codec README has the full fixture matrix and the measured results.
with `crates/golden/goldens/<scene>.png` by `filmcraft_testkit::golden`:
**PSNR ≥ 45 dB, max abs ≤ 12, 99th-percentile per-pixel max channel difference ≤ 2** (8-bit
sRGB levels; `Tolerance::RENDER`). On failure the actual frame and a ×8 difference image go to
`<workspace>/target/golden-failures/`. `scenes_are_distinct` guards against blank or duplicate
`<workspace>/target/golden-failures/`. Six `vfx_*` scenes cover the M5.11 effects (Corner Pin over Turbulent
Displace, Ultra Key, Wonder Glow + Glint, Spacer + Stroke + Long Shadow over Gradient, VR Rotate Sphere,
Channel Mix + Color Emboss + Rounded Crop); per-effect unit tests live in `crates/render/src/vfx/tests.rs`
(identity at neutral parameters, determinism, range, a known value each, temporal/track effects through
the compositor). `scenes_are_distinct` guards against blank or duplicate
scenes.
- **Blessing:** `FILMCRAFT_BLESS=1 cargo test -p filmcraft-golden` rewrites the references (and
writes a `.attribution` sidecar for any new one; it prints the `ATTRIBUTION.md` row to add).