diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 3fc73c92..4b170ba6 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -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 diff --git a/README.md b/README.md index 60f0871c..b27c8c22 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels,
NASA's Earth Views from the ISS with a look applied, and the Effects browser open on the dissolves.
-- **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. diff --git a/crates/golden/goldens/vfx_distort.png b/crates/golden/goldens/vfx_distort.png new file mode 100644 index 00000000..abadc419 Binary files /dev/null and b/crates/golden/goldens/vfx_distort.png differ diff --git a/crates/golden/goldens/vfx_distort.png.attribution b/crates/golden/goldens/vfx_distort.png.attribution new file mode 100644 index 00000000..c55ba227 --- /dev/null +++ b/crates/golden/goldens/vfx_distort.png.attribution @@ -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. diff --git a/crates/golden/goldens/vfx_glows.png b/crates/golden/goldens/vfx_glows.png new file mode 100644 index 00000000..bd96ce11 Binary files /dev/null and b/crates/golden/goldens/vfx_glows.png differ diff --git a/crates/golden/goldens/vfx_glows.png.attribution b/crates/golden/goldens/vfx_glows.png.attribution new file mode 100644 index 00000000..0e408370 --- /dev/null +++ b/crates/golden/goldens/vfx_glows.png.attribution @@ -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. diff --git a/crates/golden/goldens/vfx_spacer_stroke_shadow.png b/crates/golden/goldens/vfx_spacer_stroke_shadow.png new file mode 100644 index 00000000..b06ef5bf Binary files /dev/null and b/crates/golden/goldens/vfx_spacer_stroke_shadow.png differ diff --git a/crates/golden/goldens/vfx_spacer_stroke_shadow.png.attribution b/crates/golden/goldens/vfx_spacer_stroke_shadow.png.attribution new file mode 100644 index 00000000..31793fb1 --- /dev/null +++ b/crates/golden/goldens/vfx_spacer_stroke_shadow.png.attribution @@ -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. diff --git a/crates/golden/goldens/vfx_stylize.png b/crates/golden/goldens/vfx_stylize.png new file mode 100644 index 00000000..a13c31c0 Binary files /dev/null and b/crates/golden/goldens/vfx_stylize.png differ diff --git a/crates/golden/goldens/vfx_stylize.png.attribution b/crates/golden/goldens/vfx_stylize.png.attribution new file mode 100644 index 00000000..6efb300c --- /dev/null +++ b/crates/golden/goldens/vfx_stylize.png.attribution @@ -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. diff --git a/crates/golden/goldens/vfx_ultra_key.png b/crates/golden/goldens/vfx_ultra_key.png new file mode 100644 index 00000000..095901c6 Binary files /dev/null and b/crates/golden/goldens/vfx_ultra_key.png differ diff --git a/crates/golden/goldens/vfx_ultra_key.png.attribution b/crates/golden/goldens/vfx_ultra_key.png.attribution new file mode 100644 index 00000000..3cebf092 --- /dev/null +++ b/crates/golden/goldens/vfx_ultra_key.png.attribution @@ -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. diff --git a/crates/golden/goldens/vfx_vr_rotate.png b/crates/golden/goldens/vfx_vr_rotate.png new file mode 100644 index 00000000..91844a4b Binary files /dev/null and b/crates/golden/goldens/vfx_vr_rotate.png differ diff --git a/crates/golden/goldens/vfx_vr_rotate.png.attribution b/crates/golden/goldens/vfx_vr_rotate.png.attribution new file mode 100644 index 00000000..0ba6c637 --- /dev/null +++ b/crates/golden/goldens/vfx_vr_rotate.png.attribution @@ -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. diff --git a/crates/golden/tests/golden.rs b/crates/golden/tests/golden.rs index a3552efe..fbbc74db 100644 --- a/crates/golden/tests/golden.rs +++ b/crates/golden/tests/golden.rs @@ -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. diff --git a/crates/ui-egui/src/panels/effect_controls.rs b/crates/ui-egui/src/panels/effect_controls.rs index 813f029a..e3d36b96 100644 --- a/crates/ui-egui/src/panels/effect_controls.rs +++ b/crates/ui-egui/src/panels/effect_controls.rs @@ -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::