mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-14 19:26:59 -04:00
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:
1 parent
2e278c8ff0
commit
3139e63870
19 files changed
+177
-6
No files matched your search
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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).
|
||||
|
||||
Reference in new issue
Block a user