Naming: descriptive names for the CC effects, Lumetri, Mocha, Keylight and Mercury (#3327)

Related to #1365. Display labels only; effect, command, parameter, panel and serialized ids and the AEP/script match-name tables are unchanged.

- 69 Cycore CC effects, Key Light, Mocha shape, Lumetri Color/Scopes and the Mercury renderer labels get descriptive names; the old names stay case-insensitive lookup and search aliases.
- Backend::parse accepts the new renderer labels, so reported settings round-trip.
- Display names are unique per language in every effect catalog (new test).
- Warp Stabilizer and Roto Brush keep their names until RFC-0029 settles.
- Mapping in docs/feature-naming.md.
This commit is contained in:
FredApps authored and GitHub committed 2026-11-09 04:51:10 +01:00
1 parent a41ff5015c
commit 9893eb0d8d
58 files changed
+1321 -820

No files matched your search

+3 -7
View File
@@ -129,18 +129,14 @@ or into the Timeline, between layers and at the time you point to.
308 built-in effects across its categories, each with its parameter names, order and
defaults: blur and sharpen, channel, color correction (Curves, Levels, Hue/Saturation, a full
color-grading panel…), distort (Warp, Bulge, Turbulent Displace, CC Power Pin…), generate (Fractal Noise,
color-grading panel…), distort (Warp, Bulge, Turbulent Displace, Perspective Pin…), generate (Fractal Noise,
Gradient Ramp, Stroke, Write-on, Audio Spectrum…), keying, matte, noise and grain, perspective,
**simulation** (CC Particle World, CC Rainfall, Shatter, Card Dance, Caustics, Wave World…),
stylize (Glow, CC Glass…), **time** (Echo, Posterize Time, Timewarp, Time Displacement…),
**simulation** (Particle Emitter 3D, Rainfall, Shatter, Card Dance, Caustics, Wave World…),
stylize (Glow, Glass Relief…), **time** (Echo, Posterize Time, Timewarp, Time Displacement…),
**audio** (Reverb, Parametric EQ, Delay, Stereo Mixer…), text, transitions, utility and expression
controls. All nine **Layer Styles** (Drop Shadow, Inner/Outer Glow, Bevel and Emboss, Satin,
overlays, Stroke) with Global Light. Preview plays audio in sync, with meters and waveforms.
<p align="center">
<img src="docs/images/effectcraft-effects.png" alt="A CC Particle World burst with Glow, and the Effect Controls panel listing the particle system's parameters" width="100%">
</p>
## 3D
Classic 3D compositing: 3D layers with orientation and material options,
+4 -4
View File
@@ -35,8 +35,8 @@
//!
//! Project: --project F.ecproj (or a positional *.ecproj) | --demo | --empty (default: demo; mcp: empty)
//! Saving: --save (back to --project) | --save-as F.ecproj
//! GPU: --gpu renders on the GPU compositor (Mercury GPU Acceleration) when an adapter exists;
//! the default is the CPU (Mercury Software Only)
//! GPU: --gpu renders on the GPU compositor (GPU Acceleration) when an adapter exists;
//! the default is the CPU (Software Rendering)
//! Bridge: --bridge PORT drives a running `effectcraft --control PORT` instead of a headless session
//! Output: --json for one compact JSON document on stdout (errors: {"error": …}, exit 1)
//! ```
@@ -466,7 +466,7 @@ fn backend(args: &Args, default_demo: bool) -> Result<Backend, Failure> {
}
/// A wired session; `--gpu` attaches the GPU compositor (renders then follow the project's
/// renderer setting, Mercury GPU Acceleration by default).
/// renderer setting, GPU Acceleration by default).
fn session(args: &Args) -> Result<effectcraft_engine::Session, Failure> {
let mut s = effectcraft_host::session();
if args.flag("--autosave") {
@@ -1443,7 +1443,7 @@ fn adv3d_bench_comp(p: &mut effectcraft_engine::project::Project) -> Option<Item
/// `bench --gpu`: CPU vs GPU ms/frame for every comp (or `--comp`) at Full and Half. "cold"
/// renders everything (no layer cache); "warm" reuses the layer cache (playback / scrubbing of
/// unchanged layers: compositing cost); "viewer" is the GPU display path without readback;
/// "auto" is Backend::Auto (Mercury GPU Acceleration) choosing per comp from measured times,
/// "auto" is Backend::Auto (GPU Acceleration) choosing per comp from measured times,
/// warm; "up/dn MB" are the GPU's uploads / readbacks per warm GPU frame.
fn bench_gpu(s: &Session, args: &Args) -> Result<(), Failure> {
use effectcraft_render::Backend;
+1 -1
View File
@@ -106,7 +106,7 @@ fn track_matte(qa: &mut Qa) {
fn adjustment_layer(qa: &mut Qa, normal: &Img) {
// Adjustment layer: Lumetri exposure, inside a feathered, expanded elliptical mask; then Glow.
qa.exec("layer.newAdjustment", json!({"name": "Grade"}));
let fx = qa.exec("effect.apply", json!({"effect": "Lumetri Color", "layers": ["Grade"]}));
let fx = qa.exec("effect.apply", json!({"effect": "Color Grading", "layers": ["Grade"]}));
assert_eq!(fx["paths"], json!(["effects/#1"]), "effect.apply answers with the instance path: {fx}");
qa.tool("set_property", json!({"layer": "Grade", "path": "effects/#1/basicCorrection/tone/exposure", "value": 2}));
let before = qa.frame(None, 0.5);
+8 -8
View File
@@ -1,6 +1,6 @@
//! Blur & Sharpen, batch 2: edge-preserving blurs (Bilateral, Smart), per-channel and map-driven
//! blurs (Channel, Compound, CC Vector), bokeh (Camera Lens Blur), radial streaks and small
//! utilities (Reduce Interlace Flicker, CC Cross Blur).
//! utilities (Reduce Interlace Flicker, Cross Blur).
use effectcraft_color::luminance;
use effectcraft_keyframe::Value;
@@ -507,9 +507,9 @@ fn camera_lens_blur(ctx: &EffectCtx, mut b: Buf) -> Buf {
}
// ---------------------------------------------------------------------------------------------
// CC Radial Fast Blur
// Fast Radial Blur
/// Transparent pixels CC Radial Fast Blur adds on every side of a `w` × `h` buffer with Center
/// Transparent pixels Fast Radial Blur adds on every side of a `w` × `h` buffer with Center
/// at `c` (buffer pixels) and smear `s`: content `r` from Center streaks out to `r / (1 − s)`,
/// so the farthest corner reaches `d · s / (1 − s)` past itself (at most 4096, as the other
/// growing effects). Shared with the GPU path so both grow the same way.
@@ -562,7 +562,7 @@ fn radial_fast_blur(ctx: &EffectCtx, mut b: Buf) -> Buf {
}
// ---------------------------------------------------------------------------------------------
// CC Vector Blur
// Vector Blur
fn vector_blur(ctx: &EffectCtx, mut b: Buf) -> Buf {
let amount = ctx.params.f("amount").max(0.0) * b.scale;
@@ -616,7 +616,7 @@ fn vector_blur(ctx: &EffectCtx, mut b: Buf) -> Buf {
}
// ---------------------------------------------------------------------------------------------
// Reduce Interlace Flicker / CC Cross Blur
// Reduce Interlace Flicker / Cross Blur
fn reduce_flicker(ctx: &EffectCtx, mut b: Buf) -> Buf {
let s = ctx.params.f("softness").max(0.0) * b.scale;
@@ -735,7 +735,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.blur.ccradialfast",
"CC Radial Fast Blur",
"Fast Radial Blur",
vec![
p("center", "Center", Value::Vec2([0.5, 0.5]), ParamUi::Point),
p("amount", "Amount", num(50.0), slider(0.0, 100.0, 0.0, 100.0, 1)),
@@ -745,7 +745,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.blur.ccvector",
"CC Vector Blur",
"Vector Blur",
vec![
p("type", "Type", Value::Enum(0), popup(&["Natural", "Constant Length", "Perpendicular", "Direction Center", "Direction Fading"])),
p("amount", "Amount", num(10.0), slider(0.0, 500.0, 0.0, 100.0, 1)),
@@ -765,7 +765,7 @@ pub fn specs() -> Vec<EffectSpec> {
},
spec(
"ec.blur.cccross",
"CC Cross Blur",
"Cross Blur",
vec![
p("radiusX", "Radius X", num(10.0), slider(0.0, 500.0, 0.0, 100.0, 1)),
p("radiusY", "Radius Y", num(10.0), slider(0.0, 500.0, 0.0, 100.0, 1)),
+4 -4
View File
@@ -1,6 +1,6 @@
//! Blur & Sharpen: CC Radial Blur and Camera-Shake Deblur.
//! Blur & Sharpen: Variable Radial Blur and Camera-Shake Deblur.
//!
//! * **CC Radial Blur** — zoom (straight, fading, centred both ways) and rotational (plain or
//! * **Variable Radial Blur** — zoom (straight, fading, centred both ways) and rotational (plain or
//! fading) blurs around a centre point, sampled along the ray / arc through each pixel with a
//! sample count set by Quality.
//! * **Camera-Shake Deblur** — frame-based restoration in the spirit of published video deblurring
@@ -22,7 +22,7 @@ fn spec(id: &'static str, name: &'static str, params: Vec<crate::ParamSpec>, ren
EffectSpec { id, name, category: "Blur & Sharpen", params, render, gpu: false, float: true }
}
// ---------------------------------------------------------------- CC Radial Blur
// ---------------------------------------------------------------- Variable Radial Blur
pub const RADIAL_TYPES: [&str; 5] = ["Straight Zoom", "Fading Zoom", "Centered", "Rotate", "Rotate Fading"];
@@ -246,7 +246,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.blur.ccradial",
"CC Radial Blur",
"Variable Radial Blur",
vec![
p("type", "Type", Value::Enum(1), popup(&RADIAL_TYPES)),
p("amount", "Amount", num(10.0), slider(-100.0, 100.0, -100.0, 100.0, 1)),
+4 -4
View File
@@ -1,5 +1,5 @@
//! Channel effects, batch 2: layer-to-layer combinations (Blend, Calculations, Compound
//! Arithmetic) and CC Composite. Second layers come from layer parameters through the effect
//! Arithmetic) and Source Composite. Second layers come from layer parameters through the effect
//! host; with no layer chosen the effect uses the layer itself, as After Effects does.
use effectcraft_color::{BlendMode, blend_pixel, hsl_to_rgb, luminance, rgb_to_hsl};
@@ -69,7 +69,7 @@ fn blend(ctx: &EffectCtx, mut b: Buf) -> Buf {
// ---------------------------------------------------------------- Calculations
/// Blending modes offered by Calculations / CC Composite (menu order).
/// Blending modes offered by Calculations / Source Composite (menu order).
const CALC_MODES: [BlendMode; 22] = [
BlendMode::Normal,
BlendMode::Darken,
@@ -150,7 +150,7 @@ fn calculations(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Composite
// ---------------------------------------------------------------- Source Composite
const CC_COMPOSITE_MODES: [&str; 16] = [
"In Front",
@@ -321,7 +321,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.channel.cccomposite",
"CC Composite",
"Source Composite",
vec![
p("opacity", "Opacity", num(100.0), pct()),
p("compositeOriginal", "Composite Original", Value::Enum(0), popup(&CC_COMPOSITE_MODES)),
+4 -4
View File
@@ -878,7 +878,7 @@ fn broadcast_colors(ctx: &EffectCtx, mut b: Buf) -> Buf {
}
// ---------------------------------------------------------------------------------------------
// CC Toner, CC Color Offset, CC Kernel
// Multi-Tone Tint, Channel Offset, Convolution Kernel
fn cc_toner(ctx: &EffectCtx, mut b: Buf) -> Buf {
let g = |id: &str| {
@@ -1101,7 +1101,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.color.cctoner",
"CC Toner",
"Multi-Tone Tint",
vec![
p("tones", "Tones", Value::Enum(1), popup(&["Duotone", "Tritone", "Pentone"])),
p("highlights", "Highlights", col(1.0, 1.0, 1.0), ParamUi::Color),
@@ -1115,7 +1115,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.color.cccoloroffset",
"CC Color Offset",
"Channel Offset",
vec![
p("redPhase", "Red Phase", num(0.0), ParamUi::Angle),
p("greenPhase", "Green Phase", num(0.0), ParamUi::Angle),
@@ -1124,7 +1124,7 @@ pub fn specs() -> Vec<EffectSpec> {
],
cc_color_offset,
),
spec("ec.color.cckernel", "CC Kernel", k_params, cc_kernel),
spec("ec.color.cckernel", "Convolution Kernel", k_params, cc_kernel),
]
}
+7 -7
View File
@@ -1,5 +1,5 @@
//! Color Correction effects, batch 3: Change Color, Video Limiter, CC Color Neutralizer,
//! PS Arbitrary Map and Lumetri Color (Basic Correction, Creative, Curves, Color Wheels,
//! Color Correction effects, batch 3: Change Color, Video Limiter, Color Neutralizer,
//! PS Arbitrary Map and Color Grading (Basic Correction, Creative, Curves, Color Wheels,
//! Vignette).
use effectcraft_color::{hsl_to_rgb, luminance, rgb_to_hsl};
@@ -154,7 +154,7 @@ fn video_limiter(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Color Neutralizer
// ---------------------------------------------------------------- Color Neutralizer
fn color_neutralizer(ctx: &EffectCtx, mut b: Buf) -> Buf {
let pairs = [("shadowsUnbalance", "shadowsBalance"), ("midtonesUnbalance", "midtonesBalance"), ("highlightsUnbalance", "highlightsBalance")];
@@ -225,7 +225,7 @@ fn arbitrary_map(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- Lumetri Color
// ---------------------------------------------------------------- Color Grading
/// Smooth tone-curve adjustment: offsets for shadows/midtones/highlights (each -1..1), with the
/// end points fixed.
@@ -431,7 +431,7 @@ impl HslKey {
}
}
/// Lumetri Color: Basic Correction (input LUT, white balance, HDR range, tone, saturation),
/// Color Grading: Basic Correction (input LUT, white balance, HDR range, tone, saturation),
/// Creative (look, adjustments), Curves (tone sliders, RGB curves, hue/saturation curves),
/// Color Wheels, HSL Secondary (key, refine, correction), Vignette, in that order.
fn lumetri(ctx: &EffectCtx, mut b: Buf) -> Buf {
@@ -834,7 +834,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.color.cccolorneutralizer",
"CC Color Neutralizer",
"Color Neutralizer",
vec![
p("shadowsUnbalance", "Shadows Unbalance", col(0.0, 0.0, 0.0), ParamUi::Color),
p("shadowsBalance", "Shadows Balance", col(0.0, 0.0, 0.0), ParamUi::Color),
@@ -860,7 +860,7 @@ pub fn specs() -> Vec<EffectSpec> {
],
arbitrary_map,
),
spec("ec.color.lumetri", "Lumetri Color", lum, lumetri),
spec("ec.color.lumetri", "Color Grading", lum, lumetri),
]
}
+123
View File
@@ -0,0 +1,123 @@
//! Display naming must not change file, command or script identities.
use crate::{find, instantiate, lookup, name_matches};
use effectcraft_project::build::Ids;
const RENAMED: &[(&str, &str, &str)] = &[
("ec.sim.ccballaction", "CC Ball Action", "Ball Grid"),
("ec.distort.ccbendit", "CC Bend It", "Two-Point Bend"),
("ec.distort.ccbender", "CC Bender", "Flexible Bend"),
("ec.distort.ccblobbylize", "CC Blobbylize", "Organic Displacement"),
("ec.stylize.ccblockload", "CC Block Load", "Block Reveal"),
("ec.sim.ccbubbles", "CC Bubbles", "Bubbles"),
("ec.stylize.ccburnfilm", "CC Burn Film", "Film Burn"),
("ec.color.cccolorneutralizer", "CC Color Neutralizer", "Color Neutralizer"),
("ec.color.cccoloroffset", "CC Color Offset", "Channel Offset"),
("ec.channel.cccomposite", "CC Composite", "Source Composite"),
("ec.blur.cccross", "CC Cross Blur", "Cross Blur"),
("ec.perspective.cccylinder", "CC Cylinder", "Cylinder Wrap"),
("ec.sim.ccdrizzle", "CC Drizzle", "Water Ripples"),
("ec.perspective.ccenvironment", "CC Environment", "Environment Map"),
("ec.distort.ccflomotion", "CC Flo Motion", "Dual Lens Warp"),
("ec.time.ccforcemotionblur", "CC Force Motion Blur", "Temporal Motion Blur"),
("ec.stylize.ccglass", "CC Glass", "Glass Relief"),
("ec.transition.ccglasswipe", "CC Glass Wipe", "Glass Wipe"),
("ec.generate.ccgluegun", "CC Glue Gun", "Paint Beads"),
("ec.transition.ccgridwipe", "CC Grid Wipe", "Grid Wipe"),
("ec.distort.ccgriddler", "CC Griddler", "Tile Grid"),
("ec.sim.cchair", "CC Hair", "Surface Fibers"),
("ec.stylize.cchextile", "CC HexTile", "Hexagonal Tiles"),
("ec.transition.ccimagewipe", "CC Image Wipe", "Luminance Image Wipe"),
("ec.transition.ccjaws", "CC Jaws", "Serrated Wipe"),
("ec.stylize.cckaleida", "CC Kaleida", "Kaleidoscope"),
("ec.color.cckernel", "CC Kernel", "Convolution Kernel"),
("ec.distort.cclens", "CC Lens", "Lens Distortion"),
("ec.generate.cclightburst", "CC Light Burst 2.5", "Radial Light Burst"),
("ec.generate.cclightrays", "CC Light Rays", "Light Rays"),
("ec.generate.cclightsweep", "CC Light Sweep", "Light Sweep"),
("ec.transition.cclightwipe", "CC Light Wipe", "Light Wipe"),
("ec.transition.cclinesweep", "CC Line Sweep", "Line Sweep"),
("ec.sim.ccmrmercury", "CC Mr. Mercury", "Liquid Particles"),
("ec.stylize.ccmrsmoothie", "CC Mr. Smoothie", "Palette Map"),
("ec.utility.ccoverbrights", "CC Overbrights", "Out-of-Range Display"),
("ec.distort.ccpageturn", "CC Page Turn", "Page Curl"),
("ec.sim.ccparticlesystems2", "CC Particle Systems II", "Particle Emitter 2D"),
("ec.sim.ccparticleworld", "CC Particle World", "Particle Emitter 3D"),
("ec.sim.ccpixelpolly", "CC Pixel Polly", "Pixel Shatter"),
("ec.stylize.ccplastic", "CC Plastic", "Plastic Shading"),
("ec.distort.ccpowerpin", "CC Power Pin", "Perspective Pin"),
("ec.blur.ccradial", "CC Radial Blur", "Variable Radial Blur"),
("ec.blur.ccradialfast", "CC Radial Fast Blur", "Fast Radial Blur"),
("ec.transition.ccradialscalewipe", "CC Radial ScaleWipe", "Radial Scale Wipe"),
("ec.sim.ccrainfall", "CC Rainfall", "Rainfall"),
("ec.stylize.ccrepetile", "CC RepeTile", "Edge Tile Repeat"),
("ec.distort.ccripplepulse", "CC Ripple Pulse", "Pulsed Ripple"),
("ec.transition.ccscalewipe", "CC Scale Wipe", "Scale Wipe"),
("ec.sim.ccscatterize", "CC Scatterize", "Pixel Scatter"),
("ec.key.ccsimplewireremoval", "CC Simple Wire Removal", "Line Removal"),
("ec.distort.ccslant", "CC Slant", "Slant"),
("ec.distort.ccsmear", "CC Smear", "Directional Smear"),
("ec.sim.ccsnowfall", "CC Snowfall", "Snowfall"),
("ec.perspective.ccsphere", "CC Sphere", "Sphere Wrap"),
("ec.distort.ccsplit", "CC Split", "Split Warp"),
("ec.distort.ccsplit2", "CC Split 2", "Dual Split Warp"),
("ec.perspective.ccspotlight", "CC Spotlight", "Surface Spotlight"),
("ec.sim.ccstarburst", "CC Star Burst", "Starfield"),
("ec.generate.ccthreads", "CC Threads", "Woven Threads"),
("ec.stylize.ccthreshold", "CC Threshold", "Channel Threshold"),
("ec.stylize.ccthresholdrgb", "CC Threshold RGB", "RGB Threshold"),
("ec.distort.cctiler", "CC Tiler", "Scaled Tiles"),
("ec.color.cctoner", "CC Toner", "Multi-Tone Tint"),
("ec.transition.cctwister", "CC Twister", "Twist Wipe"),
("ec.blur.ccvector", "CC Vector Blur", "Vector Blur"),
("ec.stylize.ccvignette", "CC Vignette", "Vignette"),
("ec.transition.ccwarpomatic", "CC WarpoMatic", "Warp Dissolve"),
("ec.time.ccwidetime", "CC Wide Time", "Temporal Blend"),
("ec.color.lumetri", "Lumetri Color", "Color Grading"),
("ec.obsolete.mochashape", "Mocha shape", "Tracked Shape Matte"),
("ec.keying.keylight", "Key Light", "Screen Color Key"),
];
#[test]
fn descriptive_names_keep_every_legacy_lookup_and_search() {
for &(id, old, new) in RENAMED {
let spec = find(id).unwrap();
assert_eq!(spec.name, new, "{id}");
for query in [id.to_string(), old.to_string(), old.to_lowercase(), new.to_string()] {
assert_eq!(lookup(&query).map(|s| s.id), Some(id), "{query}");
}
assert!(name_matches(spec, &old.to_lowercase()), "{old}");
assert!(name_matches(spec, &new.to_lowercase()), "{new}");
}
for alias in ["Keylight", "Keylight (1.2)", "Key Light"] {
assert_eq!(lookup(alias).map(|s| s.id), Some("ec.keying.keylight"));
}
}
#[test]
fn descriptive_display_names_do_not_collide() {
let mut names = std::collections::HashSet::new();
for spec in crate::registry() {
assert!(names.insert(spec.name.to_lowercase()), "duplicate name {}", spec.name);
let label = spec.name.to_lowercase();
assert!(!label.starts_with("cc "), "{}", spec.name);
for mark in ["lumetri", "mercury", "mocha", "keylight"] {
assert!(!label.contains(mark), "{}", spec.name);
}
}
}
#[test]
fn legacy_instance_names_and_parameter_data_survive_refresh() {
for &(id, old, _) in RENAMED {
let spec = find(id).unwrap();
for stored in [old.to_string(), format!("{old} 2"), "My custom instance".to_string()] {
let mut next = 1;
let mut ids = Ids(&mut next);
let mut instance = instantiate(spec, &mut ids, &stored, [128.0, 72.0]);
let before = serde_json::to_value(&instance).unwrap();
crate::migrate::upgrade_instance(spec, &mut instance, &mut ids, [128.0, 72.0]);
assert_eq!(instance.name, stored, "{id}: never rewrite a stored instance name");
assert_eq!(serde_json::to_value(&instance).unwrap(), before, "{id}");
}
}
}
+11 -11
View File
@@ -1,6 +1,6 @@
//! Distort effects, batch 2: Turbulent Displace, Displacement Map (self as map), Optics
//! Compensation, Magnify, Mesh Warp, Bezier Warp, CC Bend It, CC Lens, CC Page Turn, CC Tiler,
//! CC Griddler.
//! Compensation, Magnify, Mesh Warp, Bezier Warp, Two-Point Bend, Lens Distortion, Page Curl, Scaled Tiles,
//! Tile Grid.
//!
//! Mesh Warp and Bezier Warp share a grid rasteriser: a (nx+1)×(ny+1) grid of destination points
//! and matching source points is split into triangles, bucketed per output row and filled
@@ -550,7 +550,7 @@ pub fn bezier_grid(ctx: &EffectCtx, offset: [f64; 2], scale: f64) -> (usize, Vec
(n, dest, srcp)
}
// ---------------------------------------------------------------- CC Bend It
// ---------------------------------------------------------------- Two-Point Bend
fn bend_it(ctx: &EffectCtx, mut b: Buf) -> Buf {
let mut beta = ctx.params.f("bend").to_radians();
@@ -606,7 +606,7 @@ fn bend_it(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Lens
// ---------------------------------------------------------------- Lens Distortion
fn cc_lens(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = b.to_px(ctx.params.v2("center"));
@@ -629,7 +629,7 @@ fn cc_lens(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Page Turn
// ---------------------------------------------------------------- Page Curl
fn page_turn(ctx: &EffectCtx, mut b: Buf) -> Buf {
let f = b.to_px(ctx.params.v2("foldPosition"));
@@ -679,7 +679,7 @@ fn page_turn(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Tiler / CC Griddler
// ---------------------------------------------------------------- Scaled Tiles / Tile Grid
fn cc_tiler(ctx: &EffectCtx, mut b: Buf) -> Buf {
let s = (ctx.params.f("scale") / 100.0).max(0.001);
@@ -829,7 +829,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccbendit",
"CC Bend It",
"Two-Point Bend",
vec![
p("bend", "Bend", num(0.0), ParamUi::Angle),
p("start", "Start", pt(0.5, 0.2), ParamUi::Point),
@@ -840,7 +840,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.cclens",
"CC Lens",
"Lens Distortion",
vec![
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
p("size", "Size", num(50.0), slider(0.0, 400.0, 0.0, 200.0, 1)),
@@ -850,7 +850,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccpageturn",
"CC Page Turn",
"Page Curl",
vec![
p("foldPosition", "Fold Position", pt(0.7, 0.7), ParamUi::Point),
p("foldDirection", "Fold Direction", num(315.0), ParamUi::Angle),
@@ -864,7 +864,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.cctiler",
"CC Tiler",
"Scaled Tiles",
vec![
p("scale", "Scale", num(50.0), slider(1.0, 10000.0, 1.0, 200.0, 1)),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
@@ -874,7 +874,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccgriddler",
"CC Griddler",
"Tile Grid",
vec![
p("horizontalScale", "Horizontal Scale", num(100.0), slider(1.0, 1000.0, 1.0, 400.0, 1)),
p("verticalScale", "Vertical Scale", num(100.0), slider(1.0, 1000.0, 1.0, 400.0, 1)),
+19 -19
View File
@@ -1,5 +1,5 @@
//! Distort effects, batch 3: CC Bender, CC Blobbylize, CC Power Pin, CC Ripple Pulse, CC Slant,
//! CC Smear, CC Split, CC Split 2, Smear and Reshape (mask driven), Twirl (Legacy), Warp (the
//! Distort effects, batch 3: Flexible Bend, Organic Displacement, Perspective Pin, Pulsed Ripple, Slant,
//! Directional Smear, Split Warp, Dual Split Warp, Smear and Reshape (mask driven), Twirl (Legacy), Warp (the
//! fifteen warp styles) and Detail-preserving Upscale.
//!
//! All warps are inverse mapped: every output pixel finds the source point that lands on it.
@@ -59,7 +59,7 @@ fn elastic_exp(i: u32) -> f64 {
[1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 3.5, 4.5][(i as usize).min(7)]
}
// ---------------------------------------------------------------- CC Bender
// ---------------------------------------------------------------- Flexible Bend
fn cc_bender(ctx: &EffectCtx, mut b: Buf) -> Buf {
let amount = ctx.params.f("amount") / 100.0;
@@ -107,7 +107,7 @@ fn norm3(v: [f64; 3]) -> [f64; 3] {
[v[0] / l, v[1] / l, v[2] / l]
}
/// f32 normal/dot helpers for the CC Blobbylize lighting pass. The GPU kernel runs in f32;
/// f32 normal/dot helpers for the Organic Displacement lighting pass. The GPU kernel runs in f32;
/// matching its precision here keeps specular highlights within the CPU/GPU parity tolerance.
fn norm3f(v: [f32; 3]) -> [f32; 3] {
let l = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt().max(1e-12);
@@ -118,7 +118,7 @@ fn dot3f(a: [f32; 3], b: [f32; 3]) -> f32 {
a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
// ---------------------------------------------------------------- CC Blobbylize
// ---------------------------------------------------------------- Organic Displacement
fn cc_blobbylize(ctx: &EffectCtx, mut b: Buf) -> Buf {
let soft = ctx.params.f("softness").max(0.0) * b.scale;
@@ -221,7 +221,7 @@ fn cc_blobbylize(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Power Pin
// ---------------------------------------------------------------- Perspective Pin
fn cc_power_pin(ctx: &EffectCtx, mut b: Buf) -> Buf {
let (lw, lh) = (ctx.layer_size[0].max(1.0), ctx.layer_size[1].max(1.0));
@@ -304,7 +304,7 @@ fn cc_power_pin(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Ripple Pulse
// ---------------------------------------------------------------- Pulsed Ripple
fn cc_ripple_pulse(ctx: &EffectCtx, mut b: Buf) -> Buf {
let level = ctx.params.f("pulseLevel") / 100.0;
@@ -350,7 +350,7 @@ fn cc_ripple_pulse(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Slant
// ---------------------------------------------------------------- Slant
fn cc_slant(ctx: &EffectCtx, mut b: Buf) -> Buf {
let k = ctx.params.f("slant") / 100.0;
@@ -375,7 +375,7 @@ fn cc_slant(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Smear
// ---------------------------------------------------------------- Directional Smear
fn cc_smear(ctx: &EffectCtx, mut b: Buf) -> Buf {
let reach = ctx.params.f("reach") / 100.0;
@@ -403,7 +403,7 @@ fn cc_smear(ctx: &EffectCtx, mut b: Buf) -> Buf {
}
/// The transparent pixels to add on every side of a buffer `size` pixels big (with `offset` and
/// `scale`) for CC Smear: it moves pixels by up to Reach × From→To, and they may move out to the
/// `scale`) for Directional Smear: it moves pixels by up to Reach × From→To, and they may move out to the
/// layer bounds. A text or shape layer's buffer ends at its content while its bounds are
/// comp-sized, so the smear was cut off at the content's box (#659).
pub fn cc_smear_pad(ctx: &EffectCtx, size: [u32; 2], offset: [f64; 2], scale: f64) -> u32 {
@@ -417,7 +417,7 @@ pub fn cc_smear_pad(ctx: &EffectCtx, size: [u32; 2], offset: [f64; 2], scale: f6
(moved.min(4096.0) as u32).min(crate::util::layer_cover_pad(ctx, size, offset, scale))
}
// ---------------------------------------------------------------- CC Split / CC Split 2
// ---------------------------------------------------------------- Split Warp / Dual Split Warp
fn split_impl(ctx: &EffectCtx, mut b: Buf, s1: f64, s2: f64) -> Buf {
if s1 == 0.0 && s2 == 0.0 {
@@ -913,7 +913,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.distort.ccbender",
"CC Bender",
"Flexible Bend",
vec![
p("amount", "Amount", num(0.0), slider(-200.0, 200.0, -100.0, 100.0, 1)),
p("style", "Style", Value::Enum(0), popup(&["Bend", "Marilyn", "Sharp", "Boxer"])),
@@ -925,7 +925,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccblobbylize",
"CC Blobbylize",
"Organic Displacement",
vec![
p("blobLayer", "Blob Layer", Value::Layer(None), ParamUi::Layer),
p("property", "Property", Value::Enum(0), popup(&crate::util::SRC_NAMES[..8])),
@@ -947,7 +947,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccpowerpin",
"CC Power Pin",
"Perspective Pin",
vec![
p("topLeft", "Top Left", pt(0.0, 0.0), ParamUi::Point),
p("topRight", "Top Right", pt(1.0, 0.0), ParamUi::Point),
@@ -964,7 +964,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccripplepulse",
"CC Ripple Pulse",
"Pulsed Ripple",
vec![
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
p("pulseLevel", "Pulse Level (animate)", num(0.0), slider(-1000.0, 1000.0, -100.0, 100.0, 1)),
@@ -976,7 +976,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccslant",
"CC Slant",
"Slant",
vec![
p("slant", "Slant", num(0.0), slider(-1000.0, 1000.0, -100.0, 100.0, 1)),
p("stretching", "Stretching", Value::Bool(false), ParamUi::Checkbox),
@@ -987,7 +987,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccsmear",
"CC Smear",
"Directional Smear",
vec![
p("from", "From", pt(0.35, 0.5), ParamUi::Point),
p("to", "To", pt(0.65, 0.5), ParamUi::Point),
@@ -998,7 +998,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccsplit",
"CC Split",
"Split Warp",
vec![
p("pointA", "Point A", pt(0.25, 0.5), ParamUi::Point),
p("pointB", "Point B", pt(0.75, 0.5), ParamUi::Point),
@@ -1008,7 +1008,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.distort.ccsplit2",
"CC Split 2",
"Dual Split Warp",
vec![
p("pointA", "Point A", pt(0.25, 0.5), ParamUi::Point),
p("pointB", "Point B", pt(0.75, 0.5), ParamUi::Point),
+4 -4
View File
@@ -1,6 +1,6 @@
//! Distort: CC Flo Motion, Liquify and Rolling Shutter Repair.
//! Distort: Dual Lens Warp, Liquify and Rolling Shutter Repair.
//!
//! * **CC Flo Motion** — two knots that pull the image toward themselves (positive amount) or
//! * **Dual Lens Warp** — two knots that pull the image toward themselves (positive amount) or
//! push it away (negative), with a falloff exponent, optional tiling and supersampled
//! antialiasing.
//! * **Liquify** — brush strokes build a displacement mesh (a grid of layer-space offsets). The
@@ -32,7 +32,7 @@ fn spec(id: &'static str, name: &'static str, params: Vec<crate::ParamSpec>, ren
EffectSpec { id, name, category: "Distort", params, render, gpu: false, float: true }
}
// ---------------------------------------------------------------- CC Flo Motion
// ---------------------------------------------------------------- Dual Lens Warp
fn flo_motion(ctx: &EffectCtx, mut b: Buf) -> Buf {
let knots = [(ctx.params.v2("knot1"), ctx.params.f("amount1") / 100.0), (ctx.params.v2("knot2"), ctx.params.f("amount2") / 100.0)];
@@ -560,7 +560,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.distort.ccflomotion",
"CC Flo Motion",
"Dual Lens Warp",
vec![
p("knot1", "Knot 1", Value::Vec2([0.25, 0.5]), ParamUi::Point),
p("amount1", "Amount 1", num(50.0), slider(-400.0, 100.0, -100.0, 100.0, 1)),
+6 -6
View File
@@ -1,5 +1,5 @@
//! Generate effects, batch 2: Cell Pattern (Worley), Ellipse, Lens Flare, Beam, Radio Waves,
//! Advanced Lightning, CC Light Rays, CC Light Burst 2.5, CC Light Sweep.
//! Advanced Lightning, Light Rays, Radial Light Burst, Light Sweep.
//!
//! All designs are original procedural renderings written from the public descriptions of what
//! each effect produces.
@@ -897,7 +897,7 @@ fn advanced_lightning(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Light Rays / Burst
// ---------------------------------------------------------------- Light Rays / Burst
const RAY_STEPS: usize = 32;
@@ -1007,7 +1007,7 @@ fn light_burst(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Light Sweep
// ---------------------------------------------------------------- Light Sweep
fn light_sweep(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = b.to_px(ctx.params.v2("center"));
@@ -1192,7 +1192,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.generate.cclightrays",
"CC Light Rays",
"Light Rays",
vec![
p("intensity", "Intensity", num(100.0), slider(0.0, 600.0, 0.0, 200.0, 1)),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
@@ -1207,7 +1207,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.generate.cclightburst",
"CC Light Burst 2.5",
"Radial Light Burst",
vec![
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
p("intensity", "Intensity", num(100.0), slider(0.0, 600.0, 0.0, 200.0, 1)),
@@ -1220,7 +1220,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.generate.cclightsweep",
"CC Light Sweep",
"Light Sweep",
vec![
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
p("direction", "Direction", num(-30.0), ang()),
+2 -2
View File
@@ -180,7 +180,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.generate.ccgluegun",
"CC Glue Gun",
"Paint Beads",
vec![
p("brushPosition", "Brush Position", pt(0.5, 0.5), ParamUi::Point),
p("strokeWidth", "Stroke Width", num(25.0), slider(0.0, 500.0, 0.0, 100.0, 1)),
@@ -194,7 +194,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.generate.ccthreads",
"CC Threads",
"Woven Threads",
vec![
p("width", "Width", num(50.0), slider(1.0, 1000.0, 1.0, 200.0, 1)),
p("height", "Height", num(50.0), slider(1.0, 1000.0, 1.0, 200.0, 1)),
+2 -2
View File
@@ -317,7 +317,7 @@ fn unmult(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---------------------------------------------------------------- CC Simple Wire Removal
// ---------------------------------------------------------------- Line Removal
fn wire_removal(ctx: &EffectCtx, mut b: Buf) -> Buf {
let pa = ctx.params.v2("pointA");
@@ -464,7 +464,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.key.ccsimplewireremoval",
"CC Simple Wire Removal",
"Line Removal",
vec![
p("pointA", "Point A", Value::Vec2([0.25, 0.25]), ParamUi::Point),
p("pointB", "Point B", Value::Vec2([0.75, 0.75]), ParamUi::Point),
+5 -5
View File
@@ -1,6 +1,6 @@
//! Key Light — a full screen-colour keyer with the controls of After Effects' bundled
//! Screen Color Key — a full screen-colour keyer with the controls of After Effects' bundled
//! "Keylight (1.2)" (that name is a trademark of its vendor, so the effect is registered as
//! **Key Light**; `lookup("Keylight (1.2)")` finds it through [`KEYLIGHT_ALIASES`]).
//! **Screen Color Key**; `lookup("Keylight (1.2)")` finds it through [`KEYLIGHT_ALIASES`]).
//!
//! The method is the textbook *screen difference* key, written from the public description of
//! the controls:
@@ -31,7 +31,7 @@ use crate::util::{Plane, gauss_plane, morph_frac, point_in_poly, premul, unpremu
use crate::{Buf, EffectCtx, EffectSpec, col, num, p, popup, slider};
/// Other names the effect answers to in [`crate::lookup`].
pub const KEYLIGHT_ALIASES: &[&str] = &["Keylight (1.2)", "Keylight"];
pub const KEYLIGHT_ALIASES: &[&str] = &["Keylight (1.2)", "Keylight", "Key Light"];
pub const VIEWS: [&str; 11] = [
"Source",
@@ -463,7 +463,7 @@ pub fn specs() -> Vec<EffectSpec> {
let cc = |id: &'static str, name: &'static str| p(id, name, num(0.0), slider(-100.0, 100.0, -100.0, 100.0, 1));
vec![EffectSpec {
id: "ec.keying.keylight",
name: "Key Light",
name: "Screen Color Key",
category: "Keying",
params: vec![
p("view", "View", Value::Enum(10), popup(&VIEWS)),
@@ -622,7 +622,7 @@ mod tests {
let spec = crate::find("ec.keying.keylight").unwrap();
let mut next = 1;
let mut ids = Ids(&mut next);
let mut g = crate::instantiate(spec, &mut ids, "Key Light", [10.0, 10.0]);
let mut g = crate::instantiate(spec, &mut ids, "Screen Color Key", [10.0, 10.0]);
// Flatten it the way older versions saved it.
let mut flat = vec![];
g.walk_mut(&mut |p| flat.push(p.clone()));
+84 -7
View File
@@ -23,6 +23,8 @@ mod color3;
mod color_fx;
pub mod controls;
pub mod crypto_select;
#[cfg(test)]
mod display_names;
mod distort;
mod distort2;
mod distort3;
@@ -36,6 +38,7 @@ mod keying;
mod keying2;
pub mod keylight;
mod matte;
pub mod migrate;
mod misc;
pub mod mocha_shape;
@@ -560,7 +563,7 @@ pub trait EffectHost: Sync {
}
/// Parameter `id` (a [`flatten_params`] id such as `birthRate`) of effect `effect_index` in
/// the layer's stack (the running effect's [`EffectEnv::effect_index`]) at another **layer
/// time**: CC Particle World samples its Birth Rate at every step it simulates (#1373).
/// time**: Particle Emitter 3D samples its Birth Rate at every step it simulates (#1373).
/// `None` when unavailable.
fn param_at(&self, _effect_index: usize, _id: &str, _layer_time: f64) -> Option<Value> {
None
@@ -776,8 +779,82 @@ pub fn categories() -> Vec<&'static str> {
v
}
/// After Effects' third-party display names of effects we register under a generic name.
const ALIASES: &[(&str, &[&str])] = &[("ec.keying.keylight", keylight::KEYLIGHT_ALIASES)];
/// Legacy display names accepted for saved scripts and searches. Never display these as
/// native feature names; stable effect IDs and external format match names stay unchanged.
const ALIASES: &[(&str, &[&str])] = &[
("ec.sim.ccballaction", &["CC Ball Action"]),
("ec.distort.ccbendit", &["CC Bend It"]),
("ec.distort.ccbender", &["CC Bender"]),
("ec.distort.ccblobbylize", &["CC Blobbylize"]),
("ec.stylize.ccblockload", &["CC Block Load"]),
("ec.sim.ccbubbles", &["CC Bubbles"]),
("ec.stylize.ccburnfilm", &["CC Burn Film"]),
("ec.color.cccolorneutralizer", &["CC Color Neutralizer"]),
("ec.color.cccoloroffset", &["CC Color Offset"]),
("ec.channel.cccomposite", &["CC Composite"]),
("ec.blur.cccross", &["CC Cross Blur"]),
("ec.perspective.cccylinder", &["CC Cylinder"]),
("ec.sim.ccdrizzle", &["CC Drizzle"]),
("ec.perspective.ccenvironment", &["CC Environment"]),
("ec.distort.ccflomotion", &["CC Flo Motion"]),
("ec.time.ccforcemotionblur", &["CC Force Motion Blur"]),
("ec.stylize.ccglass", &["CC Glass"]),
("ec.transition.ccglasswipe", &["CC Glass Wipe"]),
("ec.generate.ccgluegun", &["CC Glue Gun"]),
("ec.transition.ccgridwipe", &["CC Grid Wipe"]),
("ec.distort.ccgriddler", &["CC Griddler"]),
("ec.sim.cchair", &["CC Hair"]),
("ec.stylize.cchextile", &["CC HexTile"]),
("ec.transition.ccimagewipe", &["CC Image Wipe"]),
("ec.transition.ccjaws", &["CC Jaws"]),
("ec.stylize.cckaleida", &["CC Kaleida"]),
("ec.color.cckernel", &["CC Kernel"]),
("ec.distort.cclens", &["CC Lens"]),
("ec.generate.cclightburst", &["CC Light Burst 2.5"]),
("ec.generate.cclightrays", &["CC Light Rays"]),
("ec.generate.cclightsweep", &["CC Light Sweep"]),
("ec.transition.cclightwipe", &["CC Light Wipe"]),
("ec.transition.cclinesweep", &["CC Line Sweep"]),
("ec.sim.ccmrmercury", &["CC Mr. Mercury"]),
("ec.stylize.ccmrsmoothie", &["CC Mr. Smoothie"]),
("ec.utility.ccoverbrights", &["CC Overbrights"]),
("ec.distort.ccpageturn", &["CC Page Turn"]),
("ec.sim.ccparticlesystems2", &["CC Particle Systems II"]),
("ec.sim.ccparticleworld", &["CC Particle World"]),
("ec.sim.ccpixelpolly", &["CC Pixel Polly"]),
("ec.stylize.ccplastic", &["CC Plastic"]),
("ec.distort.ccpowerpin", &["CC Power Pin"]),
("ec.blur.ccradial", &["CC Radial Blur"]),
("ec.blur.ccradialfast", &["CC Radial Fast Blur"]),
("ec.transition.ccradialscalewipe", &["CC Radial ScaleWipe"]),
("ec.sim.ccrainfall", &["CC Rainfall"]),
("ec.stylize.ccrepetile", &["CC RepeTile"]),
("ec.distort.ccripplepulse", &["CC Ripple Pulse"]),
("ec.transition.ccscalewipe", &["CC Scale Wipe"]),
("ec.sim.ccscatterize", &["CC Scatterize"]),
("ec.key.ccsimplewireremoval", &["CC Simple Wire Removal"]),
("ec.distort.ccslant", &["CC Slant"]),
("ec.distort.ccsmear", &["CC Smear"]),
("ec.sim.ccsnowfall", &["CC Snowfall"]),
("ec.perspective.ccsphere", &["CC Sphere"]),
("ec.distort.ccsplit", &["CC Split"]),
("ec.distort.ccsplit2", &["CC Split 2"]),
("ec.perspective.ccspotlight", &["CC Spotlight"]),
("ec.sim.ccstarburst", &["CC Star Burst"]),
("ec.generate.ccthreads", &["CC Threads"]),
("ec.stylize.ccthreshold", &["CC Threshold"]),
("ec.stylize.ccthresholdrgb", &["CC Threshold RGB"]),
("ec.distort.cctiler", &["CC Tiler"]),
("ec.color.cctoner", &["CC Toner"]),
("ec.transition.cctwister", &["CC Twister"]),
("ec.blur.ccvector", &["CC Vector Blur"]),
("ec.stylize.ccvignette", &["CC Vignette"]),
("ec.transition.ccwarpomatic", &["CC WarpoMatic"]),
("ec.time.ccwidetime", &["CC Wide Time"]),
("ec.color.lumetri", &["Lumetri Color"]),
("ec.obsolete.mochashape", &["Mocha shape", "mocha shape"]),
("ec.keying.keylight", keylight::KEYLIGHT_ALIASES),
];
/// Other names effect `id` answers to (in [`lookup`] and searches).
pub fn aliases(id: &str) -> &'static [&'static str] {
@@ -861,7 +938,7 @@ pub fn instantiate(spec: &EffectSpec, ids: &mut Ids, instance_name: &str, layer_
/// effects without their own table.
pub const PARAM_GROUPS: &[(&str, &str)] = &[
// Color Correction: Exposure, Levels (Individual Controls), Change to Color, Colorama,
// Shadow/Highlight, Lumetri Color.
// Shadow/Highlight, Color Grading.
("master", "Master"),
("rgb", "RGB"),
("red", "Red"),
@@ -990,7 +1067,7 @@ pub const PARAM_GROUPS: &[(&str, &str)] = &[
("particleExploder", "Particle Exploder"),
("affects", "Affects"),
("options", "Options"),
// Keying, Matte, Obsolete (Key Light's groups are in `keylight::GROUPS`).
// Keying, Matte, Obsolete (Screen Color Key's groups are in `keylight::GROUPS`).
("ultraSettings", "Ultra Settings"),
("additionalForeground", "Additional Foreground"),
("additionalBackground", "Additional Background"),
@@ -1075,7 +1152,7 @@ fn nested_group<'a>(g: &'a mut PropGroup, ids: &mut Ids, path: &str) -> Option<&
}
/// Effects the GPU compositor (`effectcraft-gpu`) implements with the CPU effect's semantics
/// (Mercury GPU Acceleration; the Effects & Presets GPU badge). Expression controls are
/// (GPU Acceleration; the Effects & Presets GPU badge). Expression controls are
/// pass-throughs and count as GPU effects too.
pub const GPU_EFFECTS: &[&str] = &[
"ec.blur.gaussian",
@@ -1495,7 +1572,7 @@ mod tests {
assert_eq!(grow_sides(lo, hi, 20, 10), Some([0, 0, 30, 20]));
}
/// #2261: a 20 × 20 layer with CC Radial Fast Blur's Center far away grows to at most 16 Mpx;
/// #2261: a 20 × 20 layer with Fast Radial Blur's Center far away grows to at most 16 Mpx;
/// big layers may still grow to four times their area, and small pads are untouched.
#[test]
fn padded_buffers_stay_within_the_budget() {
+2 -2
View File
@@ -1,4 +1,4 @@
//! Matte ▸ Mocha shape: renders planar-tracked roto shapes as a matte.
//! Matte ▸ Tracked Shape Matte: renders planar-tracked roto shapes as a matte.
//!
//! Mocha's own clipboard / export formats are not publicly specified, so the effect reads shape
//! data in a small documented JSON format of ours (in the hidden `shapeData` parameter, either the
@@ -184,7 +184,7 @@ fn mocha_shape(ctx: &EffectCtx, mut b: Buf) -> Buf {
pub fn specs() -> Vec<EffectSpec> {
vec![EffectSpec {
id: "ec.obsolete.mochashape",
name: "Mocha shape",
name: "Tracked Shape Matte",
category: "Matte",
params: vec![
p("blendMode", "Blend mode", Value::Enum(0), popup(&["Add", "Subtract", "Intersect", "Difference"])),
+6 -6
View File
@@ -1,5 +1,5 @@
//! Perspective effects (batch 2): Bevel Alpha, Bevel Edges, Radial Shadow, CC Cylinder,
//! CC Sphere and CC Spotlight.
//! Perspective effects (batch 2): Bevel Alpha, Bevel Edges, Radial Shadow, Cylinder Wrap,
//! Sphere Wrap and Surface Spotlight.
//!
//! Angles follow the convention used by Drop Shadow: measured clockwise from "up", so a light
//! angle `a` sits in the direction `(sin a, -cos a)` (y grows downwards). 3D vectors use x right,
@@ -158,7 +158,7 @@ fn radial_shadow(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
/// Phong-style shading shared by CC Cylinder and CC Sphere.
/// Phong-style shading shared by Cylinder Wrap and Sphere Wrap.
struct Shading {
l: [f64; 3],
color: [f32; 4],
@@ -451,11 +451,11 @@ pub fn specs() -> Vec<EffectSpec> {
],
radial_shadow,
),
spec("ec.perspective.cccylinder", "CC Cylinder", cyl, cylinder),
spec("ec.perspective.ccsphere", "CC Sphere", sph, sphere),
spec("ec.perspective.cccylinder", "Cylinder Wrap", cyl, cylinder),
spec("ec.perspective.ccsphere", "Sphere Wrap", sph, sphere),
spec(
"ec.perspective.ccspotlight",
"CC Spotlight",
"Surface Spotlight",
vec![
p("from", "From", pt(0.3, 0.2), ParamUi::Point),
p("to", "To", pt(0.5, 0.5), ParamUi::Point),
+3 -3
View File
@@ -1,4 +1,4 @@
//! Perspective effects, batch 2: CC Environment (reflection mapping of an environment layer
//! Perspective effects, batch 2: Environment Map (reflection mapping of an environment layer
//! onto the layer's luminance/alpha relief) and 3D Glasses (stereo pairs and anaglyphs from a
//! left and right view layer).
@@ -17,7 +17,7 @@ fn spec(id: &'static str, name: &'static str, params: Vec<crate::ParamSpec>, ren
EffectSpec { id, name, category: "Perspective", params, render, gpu: false, float: true }
}
// ---------------------------------------------------------------- CC Environment
// ---------------------------------------------------------------- Environment Map
/// Environment direction (x right, y down, z towards the viewer) → normalised map coordinates.
fn env_uv(mapping: u32, r: [f64; 3]) -> (f64, f64) {
@@ -194,7 +194,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.perspective.ccenvironment",
"CC Environment",
"Environment Map",
vec![
p("environment", "Environment", Value::Layer(None), ParamUi::Layer),
p("mapping", "Mapping", Value::Enum(0), popup(&["Spherical", "Probe", "Vertical Cross"])),
+8 -8
View File
@@ -32,7 +32,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.sim.ccrainfall",
"CC Rainfall",
"Rainfall",
vec![
p("drops", "Drops", num(5000.0), slider(0.0, 100_000.0, 0.0, 20_000.0, 0)),
p("size", "Size", num(1.0), slider(0.0, 50.0, 0.0, 10.0, 2)),
@@ -53,7 +53,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccsnowfall",
"CC Snowfall",
"Snowfall",
vec![
p("flakes", "Flakes", num(10_000.0), slider(0.0, 200_000.0, 0.0, 50_000.0, 0)),
p("size", "Size", num(3.0), slider(0.0, 50.0, 0.0, 20.0, 2)),
@@ -79,7 +79,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccbubbles",
"CC Bubbles",
"Bubbles",
vec![
p("bubbleAmount", "Bubble Amount", num(100.0), slider(0.0, 10_000.0, 0.0, 1000.0, 0)),
p("bubbleSpeed", "Bubble Speed", num(0.5), slider(-10.0, 10.0, -2.0, 2.0, 2)),
@@ -93,7 +93,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccdrizzle",
"CC Drizzle",
"Water Ripples",
vec![
p("dripRate", "Drip Rate", num(10.0), slider(0.0, 200.0, 0.0, 50.0, 2)),
p("longevity", "Longevity (sec)", num(1.0), slider(0.0, 30.0, 0.0, 5.0, 2)),
@@ -114,7 +114,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccstarburst",
"CC Star Burst",
"Starfield",
vec![
p("scatter", "Scatter", num(100.0), slider(0.0, 1000.0, 0.0, 300.0, 1)),
p("speed", "Speed", num(1.0), slider(-10.0, 10.0, -4.0, 4.0, 2)),
@@ -127,7 +127,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccparticleworld",
"CC Particle World",
"Particle Emitter 3D",
vec![
p("birthRate", "Birth Rate", num(0.5), slider(0.0, 100.0, 0.0, 10.0, 2)),
p("longevity", "Longevity (sec)", num(1.0), slider(0.0, 100.0, 0.0, 10.0, 2)),
@@ -170,7 +170,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccparticlesystems2",
"CC Particle Systems II",
"Particle Emitter 2D",
vec![
p("birthRate", "Birth Rate", num(2.0), slider(0.0, 100.0, 0.0, 20.0, 2)),
p("longevity", "Longevity (sec)", num(1.0), slider(0.0, 100.0, 0.0, 10.0, 2)),
@@ -198,7 +198,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccmrmercury",
"CC Mr. Mercury",
"Liquid Particles",
vec![
p("radiusX", "Radius X", num(50.0), slider(0.0, 2000.0, 0.0, 300.0, 1)),
p("radiusY", "Radius Y", num(50.0), slider(0.0, 2000.0, 0.0, 300.0, 1)),
+3 -3
View File
@@ -79,7 +79,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.sim.ccballaction",
"CC Ball Action",
"Ball Grid",
vec![
p("scatter", "Scatter", num(0.0), slider(0.0, 2000.0, 0.0, 300.0, 1)),
p("rotationAxis", "Rotation Axis", Value::Enum(0), popup(&["X Axis", "Y Axis", "Z Axis", "XY Axis", "XZ Axis", "YZ Axis", "XYZ Axis"])),
@@ -94,7 +94,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccpixelpolly",
"CC Pixel Polly",
"Pixel Shatter",
vec![
p("force", "Force", num(100.0), slider(-1000.0, 1000.0, -300.0, 300.0, 1)),
p("gravity", "Gravity", num(1.0), slider(-20.0, 20.0, -5.0, 5.0, 2)),
@@ -111,7 +111,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.sim.ccscatterize",
"CC Scatterize",
"Pixel Scatter",
vec![
p("scatter", "Scatter", num(0.0), slider(0.0, 1000.0, 0.0, 200.0, 1)),
p("rightTwist", "Right Twist", num(0.0), ParamUi::Angle),
+5 -5
View File
@@ -1,4 +1,4 @@
//! Simulation: Particle Playground and CC Hair.
//! Simulation: Particle Playground and Surface Fibers.
//!
//! **Particle Playground** is a deterministic 2D particle system stepped from layer time 0 at
//! [`SPS`] steps per second through [`SimCache`] (seeking anywhere gives the same frame as
@@ -17,7 +17,7 @@
//! being rendered (their pixels are part of the cache key). Particles replace the layer's own
//! pixels, as in After Effects.
//!
//! **CC Hair** grows strands from the layer's opaque pixels (Density per 1 000 px²), each a
//! **Surface Fibers** grows strands from the layer's opaque pixels (Density per 1 000 px²), each a
//! quadratic curve of Length that droops with Weight, optionally steered and scaled by a hairfall
//! map layer (luminance → length, horizontal/vertical gradient → lean), and shades them with a
//! Kajiya–Kay-style strand model (diffuse ∝ sin(tangent, light), specular from the half vector).
@@ -934,7 +934,7 @@ impl PgPlan {
}
}
// ---------------------------------------------------------------- CC Hair
// ---------------------------------------------------------------- Surface Fibers
fn cc_hair(ctx: &EffectCtx, b: Buf) -> Buf {
let Some(mut plan) = hair_plan(ctx, &b) else { return b };
@@ -942,7 +942,7 @@ fn cc_hair(ctx: &EffectCtx, b: Buf) -> Buf {
plan.finish(b)
}
/// CC Hair's strands as line sprites (each coloured from its root, see [`Tint::Root`]);
/// Surface Fibers's strands as line sprites (each coloured from its root, see [`Tint::Root`]);
/// `None` = no hair (the layer passes through).
pub(crate) fn hair_plan(ctx: &EffectCtx, b: &Buf) -> Option<SpritePlan> {
let pr = ctx.params;
@@ -1144,7 +1144,7 @@ pub fn specs() -> Vec<EffectSpec> {
spec("ec.sim.particleplayground", "Particle Playground", pg, particle_playground),
spec(
"ec.sim.cchair",
"CC Hair",
"Surface Fibers",
vec![
sp("length", "Length", px(30.0, 200.0)),
p("thickness", "Thickness", num(1.0), slider(0.05, 20.0, 0.1, 5.0, 2)),
+9 -9
View File
@@ -343,7 +343,7 @@ fn brush_strokes(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---- CC Kaleida ----
// ---- Kaleidoscope ----
fn kaleida(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = b.to_px(ctx.params.v2("center"));
@@ -368,7 +368,7 @@ fn kaleida(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---- CC RepeTile ----
// ---- Edge Tile Repeat ----
#[inline]
fn tile_coord(v: f64, size: f64) -> (i64, f64) {
@@ -491,7 +491,7 @@ fn color_emboss(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---- CC Vignette ----
// ---- Vignette ----
fn vignette(ctx: &EffectCtx, mut b: Buf) -> Buf {
let amt = ctx.params.f("amount") as f32 / 100.0;
@@ -523,7 +523,7 @@ fn vignette(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ---- CC Threshold / CC Threshold RGB ----
// ---- Channel Threshold / RGB Threshold ----
fn cc_threshold(ctx: &EffectCtx, mut b: Buf) -> Buf {
let t = ctx.params.f("threshold") as f32 / 255.0;
@@ -669,7 +669,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.cckaleida",
"CC Kaleida",
"Kaleidoscope",
vec![
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
p("size", "Size", num(100.0), slider(1.0, 1000.0, 1.0, 400.0, 1)),
@@ -680,7 +680,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.ccrepetile",
"CC RepeTile",
"Edge Tile Repeat",
vec![
p("expandRight", "Expand Right", num(0.0), slider(0.0, 4000.0, 0.0, 500.0, 0)),
p("expandLeft", "Expand Left", num(0.0), slider(0.0, 4000.0, 0.0, 500.0, 0)),
@@ -718,7 +718,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.ccvignette",
"CC Vignette",
"Vignette",
vec![
p("amount", "Amount", num(50.0), slider(-100.0, 100.0, -100.0, 100.0, 1)),
p("angleOfView", "Angle of View", num(60.0), slider(0.0, 179.0, 0.0, 179.0, 1)),
@@ -729,7 +729,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.ccthreshold",
"CC Threshold",
"Channel Threshold",
vec![
p("threshold", "Threshold", num(127.0), thr()),
p("channel", "Channel", Value::Enum(0), popup(&["Luminance", "RGB", "Saturation", "Alpha"])),
@@ -740,7 +740,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.ccthresholdrgb",
"CC Threshold RGB",
"RGB Threshold",
vec![
p("redThreshold", "Red Threshold", num(127.0), thr()),
p("greenThreshold", "Green Threshold", num(127.0), thr()),
+14 -14
View File
@@ -1,5 +1,5 @@
//! Stylize effects, batch 3: CC Block Load, CC Burn Film, CC Glass, CC HexTile, CC Mr. Smoothie
//! and CC Plastic.
//! Stylize effects, batch 3: Block Reveal, Film Burn, Glass Relief, Hexagonal Tiles, Palette Map
//! and Plastic Shading.
//!
//! Written from the public descriptions of what these effects do (progressive block loading,
//! burning film, bump-mapped glass / plastic surfaces lit by an effect light, hexagonal tiling,
@@ -27,7 +27,7 @@ fn pt(x: f64, y: f64) -> Value {
Value::Vec2([x, y])
}
// ------------------------------------------------------------------ CC Block Load
// ------------------------------------------------------------------ Block Reveal
/// Mean colour of every `s`×`s` block (grid of `ceil(w/s)`×`ceil(h/s)`).
fn block_means(img: &Image, s: usize) -> (usize, usize, Vec<Px>) {
@@ -135,7 +135,7 @@ fn block_load(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC Burn Film
// ------------------------------------------------------------------ Film Burn
fn burn_film(ctx: &EffectCtx, mut b: Buf) -> Buf {
let burn = (ctx.params.f("burn") / 100.0).clamp(0.0, 1.0) as f32;
@@ -180,7 +180,7 @@ fn burn_film(ctx: &EffectCtx, mut b: Buf) -> Buf {
const BUMP_PROPS: [&str; 6] = ["Red", "Green", "Blue", "Alpha", "Luminance", "Lightness"];
/// The bump-map layer parameter: CC Glass's Bump Map, CC Plastic's Bump Layer.
/// The bump-map layer parameter: Glass Relief's Bump Map, Plastic Shading's Bump Layer.
pub fn bump_layer_id(ctx: &EffectCtx) -> &'static str {
if ctx.params.get("bumpLayer").is_some() { "bumpLayer" } else { "bumpMap" }
}
@@ -208,7 +208,7 @@ fn height_field(ctx: &EffectCtx, b: &Buf) -> Plane {
pl
}
/// The effect light and surface of CC Glass / CC Plastic (shared with the GPU compositor).
/// The effect light and surface of Glass Relief / Plastic Shading (shared with the GPU compositor).
pub struct BumpLight {
pub intensity: f32,
pub color: [f32; 3],
@@ -342,7 +342,7 @@ fn plastic(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC HexTile
// ------------------------------------------------------------------ Hexagonal Tiles
/// Axial hex cell (pointy-top) containing (x, y) for circumradius `r`; returns the cell centre
/// and integer cell coordinates.
@@ -418,7 +418,7 @@ fn hextile(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC Mr. Smoothie
// ------------------------------------------------------------------ Palette Map
const SMOOTHIE_PROPS: [&str; 8] = ["Red", "Green", "Blue", "Alpha", "Luminance", "Lightness", "Hue", "Saturation"];
@@ -518,7 +518,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.stylize.ccblockload",
"CC Block Load",
"Block Reveal",
vec![
p("completion", "Completion", num(0.0), pct()),
p("scanlines", "Scanlines", Value::Bool(true), ParamUi::Checkbox),
@@ -530,7 +530,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.ccburnfilm",
"CC Burn Film",
"Film Burn",
vec![
p("burn", "Burn", num(0.0), pct()),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
@@ -538,10 +538,10 @@ pub fn specs() -> Vec<EffectSpec> {
],
burn_film,
),
spec("ec.stylize.ccglass", "CC Glass", glass_p, glass),
spec("ec.stylize.ccglass", "Glass Relief", glass_p, glass),
spec(
"ec.stylize.cchextile",
"CC HexTile",
"Hexagonal Tiles",
vec![
p("render", "Render", Value::Enum(0), popup(&["Normal", "Mirrored", "Rotated"])),
p("radius", "Radius", num(50.0), slider(1.0, 4000.0, 2.0, 500.0, 1)),
@@ -553,7 +553,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.stylize.ccmrsmoothie",
"CC Mr. Smoothie",
"Palette Map",
vec![
p("flowLayer", "Flow Layer", Value::Layer(None), ParamUi::Layer),
p("property", "Property", Value::Enum(4), popup(&SMOOTHIE_PROPS)),
@@ -565,7 +565,7 @@ pub fn specs() -> Vec<EffectSpec> {
],
smoothie,
),
spec("ec.stylize.ccplastic", "CC Plastic", plastic_p, plastic),
spec("ec.stylize.ccplastic", "Plastic Shading", plastic_p, plastic),
]
}
+5 -5
View File
@@ -1,9 +1,9 @@
//! Time effects (Effect > Time): Echo, Posterize Time, Time Difference, Time Displacement,
//! Timewarp, CC Force Motion Blur, CC Wide Time and Pixel Motion Blur.
//! Timewarp, Temporal Motion Blur, Temporal Blend and Pixel Motion Blur.
//!
//! These read the layer at *other* layer times through [`EffectHost::self_at`]: its source with
//! its masks and the effects applied before them, as After Effects renders them (SceneYard:
//! Echo after CC Particle Systems II echoes the fireworks, not the black solid under them;
//! Echo after Particle Emitter 2D echoes the fireworks, not the black solid under them;
//! Posterize Time after Turbulent Displace steps the displacement). Timewarp is the exception:
//! it retimes the layer's source with its masks and ignores the effects above it (After
//! Effects 2026: a red solid with a Gradient Ramp and then Timewarp shows the red solid).
@@ -123,7 +123,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.time.ccforcemotionblur",
"CC Force Motion Blur",
"Temporal Motion Blur",
vec![
p("motionBlurLevels", "Motion Blur Levels", num(8.0), slider(2.0, 64.0, 2.0, 32.0, 0)),
p("overrideShutterAngle", "Override Shutter Angle", Value::Bool(true), ParamUi::Checkbox),
@@ -134,7 +134,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.time.ccwidetime",
"CC Wide Time",
"Temporal Blend",
vec![
p("forwardSteps", "Forward Steps", num(3.0), slider(0.0, 45.0, 0.0, 15.0, 0)),
p("backwardSteps", "Backward Steps", num(3.0), slider(0.0, 45.0, 0.0, 15.0, 0)),
@@ -994,7 +994,7 @@ fn matte_image(m: &[f32], like: &Image) -> Image {
out
}
// ---------------------------------------------------------------- CC Force Motion Blur / CC Wide Time / Pixel Motion Blur
// ---------------------------------------------------------------- Temporal Motion Blur / Temporal Blend / Pixel Motion Blur
fn force_motion_blur(ctx: &EffectCtx, b: Buf) -> Buf {
let n = ctx.params.f("motionBlurLevels").round().clamp(2.0, 64.0) as usize;
+5 -5
View File
@@ -1,5 +1,5 @@
//! Transition effects (batch 2): Block Dissolve, Gradient Wipe (gradient layer or self), Iris Wipe, Card
//! Wipe (3D cards with camera, lighting and jitter), CC Grid Wipe, CC Radial ScaleWipe, CC Scale Wipe and CC Light Wipe.
//! Wipe (3D cards with camera, lighting and jitter), Grid Wipe, Radial Scale Wipe, Scale Wipe and Light Wipe.
//!
//! Every transition is the identity at 0 % completion. Angles are clockwise from "up".
@@ -595,7 +595,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.ccgridwipe",
"CC Grid Wipe",
"Grid Wipe",
vec![
cc_done(),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
@@ -609,13 +609,13 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.ccradialscalewipe",
"CC Radial ScaleWipe",
"Radial Scale Wipe",
vec![cc_done(), p("center", "Center", pt(0.5, 0.5), ParamUi::Point), p("reverse", "Reverse Transition", Value::Bool(false), ParamUi::Checkbox)],
radial_scale_wipe,
),
spec(
"ec.transition.ccscalewipe",
"CC Scale Wipe",
"Scale Wipe",
vec![
p("stretch", "Stretch", num(0.0), slider(0.0, 1000.0, 0.0, 50.0, 2)),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
@@ -625,7 +625,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.cclightwipe",
"CC Light Wipe",
"Light Wipe",
vec![
cc_done(),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
+14 -14
View File
@@ -1,5 +1,5 @@
//! Transition effects, batch 2: CC Glass Wipe, CC Image Wipe, CC Jaws, CC Line Sweep,
//! CC Twister and CC WarpoMatic.
//! Transition effects, batch 2: Glass Wipe, Luminance Image Wipe, Serrated Wipe, Line Sweep,
//! Twist Wipe and Warp Dissolve.
//!
//! Written from the public descriptions of these transitions (gradient-driven wipes with glass
//! refraction or warping, jagged "jaws" opening, staggered line sweeps, a ribbon twist that
@@ -68,7 +68,7 @@ fn grad(pl: &Plane, x: usize, y: usize) -> (f32, f32) {
((pl.get_clamped(xi + 1, yi) - pl.get_clamped(xi - 1, yi)) * 0.5, (pl.get_clamped(xi, yi + 1) - pl.get_clamped(xi, yi - 1)) * 0.5)
}
// ------------------------------------------------------------------ CC Glass Wipe
// ------------------------------------------------------------------ Glass Wipe
fn glass_wipe(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = completion(ctx);
@@ -105,7 +105,7 @@ fn glass_wipe(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC Image Wipe
// ------------------------------------------------------------------ Luminance Image Wipe
fn image_wipe(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = completion(ctx);
@@ -132,7 +132,7 @@ fn image_wipe(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC Jaws
// ------------------------------------------------------------------ Serrated Wipe
fn jaws(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = completion(ctx) as f64;
@@ -193,7 +193,7 @@ fn jaws(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC Line Sweep
// ------------------------------------------------------------------ Line Sweep
fn line_sweep(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = completion(ctx) as f64;
@@ -235,7 +235,7 @@ fn line_sweep(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC Twister
// ------------------------------------------------------------------ Twist Wipe
fn twister(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = completion(ctx) as f64;
@@ -283,7 +283,7 @@ fn twister(ctx: &EffectCtx, mut b: Buf) -> Buf {
b
}
// ------------------------------------------------------------------ CC WarpoMatic
// ------------------------------------------------------------------ Warp Dissolve
fn warpomatic(ctx: &EffectCtx, mut b: Buf) -> Buf {
let c = completion(ctx);
@@ -350,7 +350,7 @@ pub fn specs() -> Vec<EffectSpec> {
vec![
spec(
"ec.transition.ccglasswipe",
"CC Glass Wipe",
"Glass Wipe",
vec![
done(),
p("layerToReveal", "Layer to Reveal", Value::Layer(None), ParamUi::Layer),
@@ -362,7 +362,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.ccimagewipe",
"CC Image Wipe",
"Luminance Image Wipe",
vec![
done(),
p("borderSoftness", "Border Softness", num(0.0), pct()),
@@ -376,7 +376,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.ccjaws",
"CC Jaws",
"Serrated Wipe",
vec![
done(),
p("center", "Center", pt(0.5, 0.5), ParamUi::Point),
@@ -389,7 +389,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.cclinesweep",
"CC Line Sweep",
"Line Sweep",
vec![
done(),
p("direction", "Direction", num(0.0), ParamUi::Angle),
@@ -401,7 +401,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.cctwister",
"CC Twister",
"Twist Wipe",
vec![
done(),
p("backside", "Backside", Value::Layer(None), ParamUi::Layer),
@@ -413,7 +413,7 @@ pub fn specs() -> Vec<EffectSpec> {
),
spec(
"ec.transition.ccwarpomatic",
"CC WarpoMatic",
"Warp Dissolve",
vec![
done(),
p("layerToReveal", "Layer to Reveal", Value::Layer(None), ParamUi::Layer),
+1 -1
View File
@@ -365,7 +365,7 @@ pub fn specs() -> Vec<EffectSpec> {
spec("ec.utility.growbounds", "Grow Bounds", vec![p("pixels", "Pixels", num(0.0), slider(0.0, 4000.0, 0.0, 500.0, 0))], grow_bounds),
spec(
"ec.utility.ccoverbrights",
"CC Overbrights",
"Out-of-Range Display",
vec![
p("channel", "Channel", Value::Enum(0), popup(&["Max RGB", "Red", "Green", "Blue", "Alpha", "Luminance"])),
p("highlightColor", "Highlight Color", col(1.0, 0.0, 0.0), ParamUi::Color),
+1 -1
View File
@@ -375,7 +375,7 @@ pub(crate) fn job_accel() -> Option<Arc<dyn Accelerator>> {
}
/// Render options of an analysis's input frames: 100 %; with an accelerator, the project's
/// renderer (Mercury GPU Acceleration: its GPU effects on the device; Software Only: the CPU).
/// renderer (GPU Acceleration: its GPU effects on the device; Software Only: the CPU).
pub(crate) fn analysis_opts(accel: Option<&dyn Accelerator>) -> RenderOpts {
RenderOpts { scale: 1.0, backend: if accel.is_some() { Backend::Auto } else { Backend::Cpu }, ..Default::default() }
}
+4 -4
View File
@@ -719,8 +719,8 @@ fn project_settings(s: &mut Session, p: &Value) -> Result<Value> {
Ok(serde_json::to_value(&s.project.settings).unwrap_or_default())
}
/// Video Rendering and Effects: report or set the renderer (Mercury GPU Acceleration when a GPU
/// adapter exists, else Mercury Software Only).
/// Video Rendering and Effects: report or set the renderer (GPU Acceleration when a GPU
/// adapter exists, else Software Rendering).
fn render_backend(s: &mut Session, p: &Value) -> Result<Value> {
if let Some(b) = p.get("backend").or_else(|| p.get("renderer")) {
let gpu = match b {
@@ -748,14 +748,14 @@ pub fn backend_status(s: &Session) -> Value {
let gpu = s.project.settings.gpu_acceleration;
// Why it renders on the CPU (#262).
let why = if !gpu {
Some("the project's renderer is Mercury Software Only".to_string())
Some("the project's renderer is Software Rendering".to_string())
} else if adapter.is_none() {
Some(s.accel_note.clone().unwrap_or_else(|| "no GPU compositor is attached".into()))
} else {
None
};
json!({
"renderer": if gpu { "Mercury GPU Acceleration" } else { "Mercury Software Only" },
"renderer": if gpu { "GPU Acceleration" } else { "Software Rendering" },
"gpuAcceleration": gpu,
"adapter": adapter,
"active": if gpu && adapter.is_some() { "gpu" } else { "cpu" },
+3 -3
View File
@@ -1,4 +1,4 @@
//! Commands behind the Progress, Media Browser, Metadata and Lumetri Scopes panels.
//! Commands behind the Progress, Media Browser, Metadata and Video Scopes panels.
use effectcraft_project::ItemId;
use effectcraft_raster::Image;
@@ -159,7 +159,7 @@ fn project_comment(s: &mut Session, p: &Value) -> Result<Value> {
Ok(Value::Null)
}
// ---------------------------------------------------------------- Lumetri Scopes
// ---------------------------------------------------------------- Video Scopes
/// The comp frame the scopes read (the viewer's image: over the comp background), at most
/// `max_side` pixels on the long side.
@@ -257,7 +257,7 @@ pub fn specs() -> Vec<CommandSpec> {
cmd!("project.setProjectComment", "Project Comment", [], None, "{comment}", always, project_comment),
query!(
"scopes.analyze",
"Lumetri Scopes",
"Video Scopes",
"{comp?, time?|frame?, scope?: waveformRgb|waveformLuma|waveformYc|vectorscopeYuv|vectorscopeHls|histogram|paradeRgb|paradeYuv, standard?: rec601|rec709|rec2020, float?, clamp?, size?}",
scopes_analyze
),
+1 -1
View File
@@ -238,7 +238,7 @@ fn showcase_3d(p: &mut Project, solids: ItemId) -> Comp {
anim(&mut cam, "cameraOptions/focusDistance", keys(&[(0.0, Value::Scalar(1700.0)), (5.0, Value::Scalar(1900.0)), (10.0, Value::Scalar(1650.0))]));
// Key light: warm spot casting soft shadows. Fill: cool ambient.
let mut key = build::layer(p, &c, "Key Light", LayerSource::Light { kind: effectcraft_project::LightKind::Spot }, (1920, 1080), None);
let mut key = build::layer(p, &c, "Screen Color Key", LayerSource::Light { kind: effectcraft_project::LightKind::Spot }, (1920, 1080), None);
set(&mut key, "transform/position", Value::Vec3([500.0, -500.0, -700.0]));
set(&mut key, "transform/poi", Value::Vec3([960.0, 600.0, 300.0]));
set(&mut key, "lightOptions/intensity", Value::Scalar(150.0));
+1 -1
View File
@@ -259,7 +259,7 @@ pub fn tutorials() -> Vec<Tutorial> {
target: Some("menu.Layer"),
accepts: &["layer.newLight"],
when: Value::Null,
show: vec![("layer.newLight", json!({"kind": "Spot", "name": "Key Light"}))],
show: vec![("layer.newLight", json!({"kind": "Spot", "name": "Screen Color Key"}))],
}),
step(S {
title: "Add a camera",
+1 -1
View File
@@ -1263,7 +1263,7 @@ Window
Essential Graphics | window.panel {"panel":"essentialGraphics"}
Info | window.panel {"panel":"info"} | Cmd+2
Learn | help.inAppTutorials
Lumetri Scopes | window.panel {"panel":"lumetriScopes"}
Video Scopes | window.panel {"panel":"lumetriScopes"}
Mask Interpolation | window.panel {"panel":"maskInterpolation"}
Media Browser | window.panel {"panel":"mediaBrowser"}
Metadata | window.panel {"panel":"metadata"}
+19
View File
@@ -23,6 +23,25 @@ fn platform_entries(mac: bool) -> Vec<(Vec<String>, MenuEntry)> {
out
}
/// Guard the generated display tree, not command IDs, format tokens or dynamic user names.
#[test]
fn builtin_menu_labels_do_not_reintroduce_vendor_feature_names() {
for mac in [true, false] {
let entries = platform_entries(mac);
for (path, entry) in &entries {
for label in path.iter().chain(std::iter::once(&entry.label)) {
let folded = label.to_lowercase();
assert!(!folded.starts_with("cc "), "{label}");
for mark in ["lumetri", "mercury", "mocha", "keylight"] {
assert!(!folded.contains(mark), "{label}");
}
}
}
let scopes = entries.iter().find(|(_, e)| e.command == "window.panel" && e.params["panel"] == "lumetriScopes").unwrap();
assert_eq!(scopes.1.label, "Video Scopes");
}
}
#[test]
fn top_level_order_matches_after_effects() {
let mac: Vec<String> =
+2 -2
View File
@@ -439,7 +439,7 @@ const RIGGED: &str = r#"{
],
"cameras": [{"type": "perspective", "name": "Shot", "perspective": {"yfov": 0.6, "znear": 0.1}}],
"extensions": {"KHR_lights_punctual": {"lights": [
{"type": "spot", "name": "Key Light", "color": [1, 0.8, 0.6], "intensity": 1.5, "spot": {"innerConeAngle": 0.25, "outerConeAngle": 0.5}},
{"type": "spot", "name": "Screen Color Key", "color": [1, 0.8, 0.6], "intensity": 1.5, "spot": {"innerConeAngle": 0.25, "outerConeAngle": 0.5}},
{"type": "point", "name": "Fill Light", "intensity": 0.5, "range": 4}
]}}
}"#;
@@ -478,7 +478,7 @@ fn cameras_and_lights_from_model() {
let r = s.execute("light.fromModel", json!({})).unwrap();
let ls: Vec<Layer> = r["layers"].as_array().unwrap().iter().map(|v| layer_in(&s, cid(&s), v.as_u64().unwrap())).collect();
assert_eq!(ls.len(), 2);
let key = ls.iter().find(|l| l.name == "Key Light").unwrap();
let key = ls.iter().find(|l| l.name == "Screen Color Key").unwrap();
assert_eq!(key.source, LayerSource::Light { kind: LightKind::Spot });
assert!((key.props.prop("lightOptions/coneAngle").unwrap().value.as_f64() - 1.0f64.to_degrees()).abs() < 1e-6);
assert!((key.props.prop("lightOptions/coneFeather").unwrap().value.as_f64() - 50.0).abs() < 1e-6);
+29 -1
View File
@@ -1221,7 +1221,35 @@ fn render_backend_says_why_it_renders_on_the_cpu() {
assert_eq!(why(&mut s), json!("no GPU compositor is attached"));
s.accel_note = Some("headless: renders on the CPU unless started with --gpu".into());
assert_eq!(why(&mut s), json!("headless: renders on the CPU unless started with --gpu"));
assert_eq!(s.execute("render.backend", json!({"backend": "cpu"})).unwrap()["why"], json!("the project's renderer is Mercury Software Only"));
assert_eq!(s.execute("render.backend", json!({"backend": "cpu"})).unwrap()["why"], json!("the project's renderer is Software Rendering"));
}
/// Display labels are descriptive; machine-readable settings remain the same.
#[test]
fn renderer_labels_keep_their_stable_machine_values() {
let mut s = Session::default();
for (backend, label, gpu) in [("cpu", "Software Rendering", false), ("gpu", "GPU Acceleration", true)] {
let status = s.execute("render.backend", json!({"backend": backend})).unwrap();
assert_eq!(status["renderer"], json!(label));
assert_eq!(status["gpuAcceleration"], json!(gpu));
assert_eq!(status["active"], json!("cpu"), "the headless test has no GPU adapter");
}
}
/// The label `render.backend` reports is one it accepts back, so a caller can round-trip the
/// status instead of guessing the command's own values.
#[test]
fn renderer_status_labels_round_trip_through_the_command() {
let mut s = Session::default();
for (backend, label, gpu) in [("cpu", "Software Rendering", false), ("gpu", "GPU Acceleration", true)] {
let reported = s.execute("render.backend", json!({"backend": backend})).unwrap()["renderer"].clone();
assert_eq!(reported, json!(label));
let parsed = effectcraft_render::Backend::parse(reported.as_str().unwrap()).expect("the reported renderer parses back");
assert_eq!(parsed == effectcraft_render::Backend::Cpu, !gpu, "{reported}");
let again = s.execute("render.backend", json!({"backend": reported})).unwrap();
assert_eq!(again["renderer"], reported);
assert_eq!(again["gpuAcceleration"], json!(gpu));
}
}
/// Settings ▸ GPU Information names what the GPU compositor runs on, or why it is off, and the
+5 -2
View File
@@ -21,10 +21,13 @@ pub enum Backend {
}
impl Backend {
/// The backend `s` names, whatever case it is written in: the project's own values (`cpu`,
/// `gpu`, `auto`), the labels Project Settings ▸ Video Rendering and Effects draws
/// (`GPU Acceleration`, `Software Rendering`) and the older After Effects wording.
pub fn parse(s: &str) -> Option<Backend> {
match s.to_ascii_lowercase().as_str() {
"cpu" | "software" | "mercury software only" => Some(Backend::Cpu),
"gpu" | "mercury gpu acceleration" => Some(Backend::Gpu),
"cpu" | "software" | "mercury software only" | "software rendering" => Some(Backend::Cpu),
"gpu" | "mercury gpu acceleration" | "gpu acceleration" => Some(Backend::Gpu),
"auto" => Some(Backend::Auto),
_ => None,
}
+32 -11
View File
@@ -329,7 +329,7 @@ fn card_dance_comp_camera_matches_the_default_view() {
assert!(img.get(10, 50)[3] < 0.01);
}
/// A black 2D solid with CC Particle World, under a camera layer panned right by `pan` px.
/// A black 2D solid with Particle Emitter 3D, under a camera layer panned right by `pan` px.
fn particle_world_scene(pan: f64) -> (Project, ItemId) {
let (mut p, cid, comp) = setup();
let mut l = solid(&mut p, &comp, [0.0, 0.0, 0.0], 200, 100);
@@ -359,7 +359,7 @@ fn particles_x(img: &crate::Image) -> f32 {
sx / m
}
/// #397: CC Particle World on a 2D layer is seen through the comp's camera layer, and the layer
/// #397: Particle Emitter 3D on a 2D layer is seen through the comp's camera layer, and the layer
/// cache notices the camera moving.
#[test]
fn particle_world_follows_the_comp_camera() {
@@ -374,7 +374,7 @@ fn particle_world_follows_the_comp_camera() {
assert!(b < a - 20.0, "panning the camera right moves the particles left: {a} -> {b}");
}
/// A black solid with CC Particle World whose Birth Rate is 3 until layer time `cut`, then 0 a
/// A black solid with Particle Emitter 3D whose Birth Rate is 3 until layer time `cut`, then 0 a
/// frame later (`None`: 3 throughout); the layer starts at comp time `start`, stretched `stretch` %.
fn burst_scene(cut: Option<f64>, start: f64, stretch: f64) -> (Project, ItemId) {
burst_scene_keys(cut, start, stretch, false)
@@ -624,7 +624,7 @@ fn a_text_expression_selector_is_not_served_from_the_disk_cache() {
/// A Birth Rate expression reading another layer: changing that layer changes the history but
/// not the current rate (0) nor this layer's properties, which is all the layer cache key sees.
/// CC Particle World layers with expressions therefore aren't layer cached.
/// Particle Emitter 3D layers with expressions therefore aren't layer cached.
#[test]
fn particle_world_with_a_birth_rate_expression_is_not_served_from_the_layer_cache() {
let scene = |opacity: f64| {
@@ -657,8 +657,8 @@ fn particle_world_with_a_birth_rate_expression_is_not_served_from_the_layer_cach
assert!(light(&b) > 1.0 && light(&b) < light(&a), "fewer births: {} vs {}", light(&b), light(&a));
}
/// A grey solid (CC Mr. Mercury shades its blobs from it) with effect `id` (CC Particle Systems
/// II, CC Mr. Mercury): Birth Rate `rate`,
/// A grey solid (Liquid Particles shades its blobs from it) with effect `id` (CC Particle Systems
/// II, Liquid Particles): Birth Rate `rate`,
/// or keyed 3 until 0.5 s and 0 a frame later (`None`); Longevity 1 s.
fn system_scene(id: &str, rate: Option<f64>) -> (Project, ItemId) {
let (mut p, cid, comp) = setup();
@@ -677,7 +677,7 @@ fn system_scene(id: &str, rate: Option<f64>) -> (Project, ItemId) {
(p, cid)
}
/// #1373 for CC Particle Systems II and CC Mr. Mercury through the renderer: a keyed burst
/// #1373 for Particle Emitter 2D and Liquid Particles through the renderer: a keyed burst
/// draws as the constant rate during it, still draws after the rate drops to 0 (unlike a rate
/// of 0 throughout), and draws as nothing born once Longevity has run out.
#[test]
@@ -1057,6 +1057,27 @@ fn comp_frame_ends_the_frame_when_the_render_panics() {
assert_eq!(a.ends.load(Ordering::SeqCst), 1);
}
/// The renderer labels Project Settings ▸ Video Rendering and Effects draws parse back as the
/// backend they name (in any case), and the older spellings still work.
#[test]
fn renderer_labels_parse_back_and_keep_the_older_spellings() {
use crate::Backend;
for (label, backend) in [
("GPU Acceleration", Backend::Gpu),
("gpu acceleration", Backend::Gpu),
("Mercury GPU Acceleration", Backend::Gpu),
("gpu", Backend::Gpu),
("Software Rendering", Backend::Cpu),
("software rendering", Backend::Cpu),
("Mercury Software Only", Backend::Cpu),
("cpu", Backend::Cpu),
("Auto", Backend::Auto),
] {
assert_eq!(Backend::parse(label), Some(backend), "{label}");
}
assert_eq!(Backend::parse("Vulkan"), None);
}
#[test]
fn auto_backend_sends_2d_and_3d_comps_to_the_gpu() {
let (mut p, cid, comp) = setup();
@@ -1223,11 +1244,11 @@ fn effects_on_text_reach_past_the_text_bounds() {
}
assert!(
painted > 50 && hi.saturating_sub(lo) > 100,
"CC Tiler tiles the glyphs across the layer region, not just its text bounds: {painted} painted, x-span {lo}..{hi}"
"Scaled Tiles tiles the glyphs across the layer region, not just its text bounds: {painted} painted, x-span {lo}..{hi}"
);
}
/// #658: CC Smear drags text glyphs beyond the text layer's own bounds. Pixels smeared past
/// #658: Directional Smear drags text glyphs beyond the text layer's own bounds. Pixels smeared past
/// the painted rectangle used to fall off its edge, so the liquid trail never appeared.
#[test]
fn cc_smear_trails_text_past_its_bounds() {
@@ -1246,7 +1267,7 @@ fn cc_smear_trails_text_past_its_bounds() {
);
p.comp_mut(cid).unwrap().layers = vec![l].into();
let smeared = right(&render_frame(&p, cid, Tick::ZERO, 1.0));
assert!(plain > 40 && smeared > plain + 25, "CC Smear trails the glyphs past the text bounds: right edge {plain} → {smeared}");
assert!(plain > 40 && smeared > plain + 25, "Directional Smear trails the glyphs past the text bounds: right edge {plain} → {smeared}");
}
/// A layer parameter pointing at a shape layer sees all of it (in its effect space), and the
@@ -1502,7 +1523,7 @@ fn solo_excludes_other_layers_outside_the_soloed_layers_range() {
assert_eq!(second.get(100, 50), [0.0, 0.0, 1.0, 1.0], "only B inside its range");
}
/// #1252: a layer blended with a CC Particle World layer, under a camera panned by `pan` px.
/// #1252: a layer blended with a Particle Emitter 3D layer, under a camera panned by `pan` px.
fn scene_reader_dependency(pan: f64) -> (Project, ItemId) {
let (mut p, cid, comp) = setup();
let mut source = solid(&mut p, &comp, [0.0, 0.0, 0.0], 200, 100);
+11 -1
View File
@@ -124,7 +124,7 @@ impl PanelKind {
PanelKind::EssentialGraphics => "Essential Graphics",
PanelKind::ScriptPanel(_) => "ScriptUI Panel",
PanelKind::Viewer(_) => "Composition",
PanelKind::LumetriScopes => "Lumetri Scopes",
PanelKind::LumetriScopes => "Video Scopes",
PanelKind::Footage => "Footage",
PanelKind::MediaBrowser => "Media Browser",
PanelKind::Metadata => "Metadata",
@@ -709,6 +709,16 @@ mod tests {
w.apply(action, permissions).unwrap();
}
/// Only the title changes: existing saved workspace layouts still deserialize.
#[test]
fn scopes_label_is_descriptive_and_its_saved_identity_stays_compatible() {
let panel: PanelKind = serde_json::from_str("\"LumetriScopes\"").unwrap();
assert_eq!(panel, LumetriScopes);
assert_eq!(panel.title(), "Video Scopes");
assert_eq!(panel.id(), "LumetriScopes");
assert_eq!(serde_json::to_string(&panel).unwrap(), "\"LumetriScopes\"");
}
#[test]
fn after_effects_workspaces_exist_with_their_core_panels() {
for name in WORKSPACES {
+28 -13
View File
@@ -1054,7 +1054,7 @@ const SIMPLIFIED_CHINESE: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "基本图形"),
("window.panel", "Info", "信息"),
("help.inAppTutorials", "Learn", "学习"),
("window.panel", "Lumetri Scopes", "Lumetri 范围"),
("window.panel", "Video Scopes", "视频示波器"),
("window.panel", "Mask Interpolation", "蒙版插值"),
("window.panel", "Media Browser", "媒体浏览器"),
("window.panel", "Metadata", "元数据"),
@@ -1690,7 +1690,7 @@ const SWEDISH: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Grundläggande grafik"),
("window.panel", "Info", "Info"),
("help.inAppTutorials", "Learn", "Lär dig"),
("window.panel", "Lumetri Scopes", "Lumetri-scope"),
("window.panel", "Video Scopes", "Videoskop"),
("window.panel", "Mask Interpolation", "Maskinterpolering"),
("window.panel", "Media Browser", "Mediebläddrare"),
("window.panel", "Metadata", "Metadata"),
@@ -2336,7 +2336,7 @@ const TRADITIONAL_CHINESE: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "基本圖形"),
("window.panel", "Info", "資訊"),
("help.inAppTutorials", "Learn", "學習"),
("window.panel", "Lumetri Scopes", "Lumetri 示波器"),
("window.panel", "Video Scopes", "視訊示波器"),
("window.panel", "Mask Interpolation", "遮色片插補"),
("window.panel", "Media Browser", "媒體瀏覽器"),
("window.panel", "Metadata", "中繼資料"),
@@ -2975,7 +2975,7 @@ const JAPANESE: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "エッセンシャルグラフィックス"),
("window.panel", "Info", "情報"),
("help.inAppTutorials", "Learn", "学習"),
("window.panel", "Lumetri Scopes", "Lumetriスコープ"),
("window.panel", "Video Scopes", "ビデオスコープ"),
("window.panel", "Mask Interpolation", "マスク補間"),
("window.panel", "Media Browser", "メディアブラウザー"),
("window.panel", "Metadata", "メタデータ"),
@@ -3617,7 +3617,7 @@ const UKRAINIAN: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Основна графіка"),
("window.panel", "Info", "Інформація"),
("help.inAppTutorials", "Learn", "Навчання"),
("window.panel", "Lumetri Scopes", "Вимірювачі Lumetri"),
("window.panel", "Video Scopes", "Відеоскопи"),
("window.panel", "Mask Interpolation", "Інтерполяція маски"),
("window.panel", "Media Browser", "Браузер медіа"),
("window.panel", "Metadata", "Метадані"),
@@ -4260,7 +4260,7 @@ const SPANISH: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Gráficos esenciales"),
("window.panel", "Info", "Información"),
("help.inAppTutorials", "Learn", "Aprender"),
("window.panel", "Lumetri Scopes", "Ámbitos de Lumetri"),
("window.panel", "Video Scopes", "Monitores de vídeo"),
("window.panel", "Mask Interpolation", "Interpolación de máscara"),
("window.panel", "Media Browser", "Navegador de medios"),
("window.panel", "Metadata", "Metadatos"),
@@ -4901,7 +4901,7 @@ const PORTUGUESE: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Gráficos essenciais"),
("window.panel", "Info", "Informações"),
("help.inAppTutorials", "Learn", "Aprender"),
("window.panel", "Lumetri Scopes", "Escopos Lumetri"),
("window.panel", "Video Scopes", "Escopos de vídeo"),
("window.panel", "Mask Interpolation", "Interpolação de máscara"),
("window.panel", "Media Browser", "Navegador de mídia"),
("window.panel", "Metadata", "Metadados"),
@@ -5544,7 +5544,7 @@ const RUSSIAN: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Основная графика"),
("window.panel", "Info", "Информация"),
("help.inAppTutorials", "Learn", "Обучение"),
("window.panel", "Lumetri Scopes", "Измерители Lumetri"),
("window.panel", "Video Scopes", "Видеоскопы"),
("window.panel", "Mask Interpolation", "Интерполяция маски"),
("window.panel", "Media Browser", "Обозреватель медиа"),
("window.panel", "Metadata", "Метаданные"),
@@ -6185,7 +6185,7 @@ const FRENCH: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Graphiques essentiels"),
("window.panel", "Info", "Informations"),
("help.inAppTutorials", "Learn", "Apprentissage"),
("window.panel", "Lumetri Scopes", "Oscilloscopes Lumetri"),
("window.panel", "Video Scopes", "Oscilloscopes vidéo"),
("window.panel", "Mask Interpolation", "Interpolation de masque"),
("window.panel", "Media Browser", "Navigateur multimédia"),
("window.panel", "Metadata", "Métadonnées"),
@@ -6826,7 +6826,7 @@ const GERMAN: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Essential-Grafik"),
("window.panel", "Info", "Info"),
("help.inAppTutorials", "Learn", "Lernen"),
("window.panel", "Lumetri Scopes", "Lumetri-Scopes"),
("window.panel", "Video Scopes", "Videoskope"),
("window.panel", "Mask Interpolation", "Maskeninterpolation"),
("window.panel", "Media Browser", "Medienbrowser"),
("window.panel", "Metadata", "Metadaten"),
@@ -7464,7 +7464,7 @@ const POLISH: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Essential Graphics"),
("window.panel", "Info", "Informacje"),
("help.inAppTutorials", "Learn", "Nauka"),
("window.panel", "Lumetri Scopes", "Zakresy Lumetri"),
("window.panel", "Video Scopes", "Wskaźniki wideo"),
("window.panel", "Mask Interpolation", "Interpolacja maski"),
("window.panel", "Media Browser", "Przeglądarka multimediów"),
("window.panel", "Metadata", "Metadane"),
@@ -8106,7 +8106,7 @@ const CZECH: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "Základní grafika"),
("window.panel", "Info", "Informace"),
("help.inAppTutorials", "Learn", "Výuka"),
("window.panel", "Lumetri Scopes", "Měřicí přístroje Lumetri"),
("window.panel", "Video Scopes", "Videoskopy"),
("window.panel", "Mask Interpolation", "Interpolace masek"),
("window.panel", "Media Browser", "Prohlížeč médií"),
("window.panel", "Metadata", "Metadata"),
@@ -8748,7 +8748,7 @@ const GEORGIAN: &[(&str, &str, &str)] = &[
("window.panel", "Essential Graphics", "ძირითადი გრაფიკა"),
("window.panel", "Info", "ინფორმაცია"),
("help.inAppTutorials", "Learn", "სწავლა"),
("window.panel", "Lumetri Scopes", "Lumetri Scopes"),
("window.panel", "Video Scopes", "ვიდეოსკოპები"),
("window.panel", "Mask Interpolation", "ნიღბის ინტერპოლაცია"),
("window.panel", "Media Browser", "მედიის ბრაუზერი"),
("window.panel", "Metadata", "მეტამონაცემები"),
@@ -8799,6 +8799,21 @@ mod tests {
use serde_json::json;
use std::collections::BTreeSet;
#[test]
fn renamed_menu_translations_do_not_reintroduce_vendor_names() {
for code in CATALOG_CODES {
set_current(code);
for (id, source) in [("window.panel", "Video Scopes")] {
let rendered = command_label(id, source);
let label = rendered.to_lowercase();
for mark in ["lumetri", "mercury"] {
assert!(!label.contains(mark), "{code}: {id} -> {rendered}");
}
}
}
set_current("en");
}
/// The four options at the foot of the header's workspace menu say what After Effects says,
/// read from its workspace button on 2026-10-31: reset, save over this one, save a copy, then
/// edit the list.
File diff suppressed because it is too large. Load diff
+64 -28
View File
@@ -708,8 +708,8 @@ const JAPANESE: &[(&str, &str)] = &[
("Import Photoshop File", "Photoshopファイルを読み込み"),
("Interpret Unlabeled Alpha As", "ラベルのないアルファの解釈"),
("Join the ArtCraft Discord", "ArtCraftのDiscordに参加"),
("Mercury GPU Acceleration ({})", "Mercury GPUアクセラレーション({})"),
("Mercury Software Only", "Mercuryソフトウェアのみ"),
("GPU Acceleration ({})", "GPUアクセラレーション({})"),
("Software Rendering", "ソフトウェアレンダリング"),
("OCIO (built-in ACES config)", "OCIO(組み込みACES設定)"),
("Off (Final Quality)", "オフ(最終品質)"),
("OpenGL (compatibility)", "OpenGL(互換)"),
@@ -1118,7 +1118,7 @@ const JAPANESE: &[(&str, &str)] = &[
("Script Console", "スクリプトコンソール"),
("Essential Graphics", "エッセンシャルグラフィックス"),
("ScriptUI Panel", "ScriptUIパネル"),
("Lumetri Scopes", "Lumetriスコープ"),
("Video Scopes", "ビデオスコープ"),
("Media Browser", "メディアブラウザー"),
("Content-Aware Fill", "コンテンツに応じた塗りつぶし"),
("Create Nulls From Paths", "パスからヌルを作成"),
@@ -1318,6 +1318,7 @@ const JAPANESE: &[(&str, &str)] = &[
("per second", "毎秒"),
("Waveform", "波形"),
("steps", "ステップ"),
("GPU Acceleration (no GPU: software)", "GPUアクセラレーション(GPUなし:ソフトウェア)"),
];
const SIMPLIFIED_CHINESE: &[(&str, &str)] = &[
@@ -1837,8 +1838,8 @@ const SIMPLIFIED_CHINESE: &[(&str, &str)] = &[
("Import Photoshop File", "导入 Photoshop 文件"),
("Interpret Unlabeled Alpha As", "将未标记的 Alpha 解释为"),
("Join the ArtCraft Discord", "加入 ArtCraft Discord"),
("Mercury GPU Acceleration ({})", "Mercury GPU 加速({})"),
("Mercury Software Only", "仅 Mercury 软件"),
("GPU Acceleration ({})", "GPU 加速({})"),
("Software Rendering", "软件渲染"),
("OCIO (built-in ACES config)", "OCIO(内置 ACES 配置)"),
("Off (Final Quality)", "关闭(最终质量)"),
("OpenGL (compatibility)", "OpenGL(兼容)"),
@@ -2280,7 +2281,7 @@ const SIMPLIFIED_CHINESE: &[(&str, &str)] = &[
("Script Console", "脚本控制台"),
("Essential Graphics", "基本图形"),
("ScriptUI Panel", "ScriptUI 面板"),
("Lumetri Scopes", "Lumetri 示波器"),
("Video Scopes", "视频示波器"),
("Media Browser", "媒体浏览器"),
("Content-Aware Fill", "内容识别填充"),
("Create Nulls From Paths", "从路径创建空对象"),
@@ -2433,6 +2434,7 @@ const SIMPLIFIED_CHINESE: &[(&str, &str)] = &[
("Blend Mode", "混合模式"),
("Show mesh", "显示网格"),
("Record Options...", "记录选项..."),
("GPU Acceleration (no GPU: software)", "GPU 加速(无 GPU:软件)"),
];
/// Swedish (`sv`), written from the English source.
@@ -2950,8 +2952,8 @@ const SWEDISH: &[(&str, &str)] = &[
("Import Photoshop File", "Importera Photoshop-fil"),
("Interpret Unlabeled Alpha As", "Tolka omärkt alfa som"),
("Join the ArtCraft Discord", "Gå med i ArtCraft på Discord"),
("Mercury GPU Acceleration ({})", "Mercury GPU-acceleration ({})"),
("Mercury Software Only", "Endast Mercury-programvara"),
("GPU Acceleration ({})", "GPU-acceleration ({})"),
("Software Rendering", "Programvarurendering"),
("OCIO (built-in ACES config)", "OCIO (inbyggd ACES-konfiguration)"),
("Off (Final Quality)", "Av (slutlig kvalitet)"),
("OpenGL (compatibility)", "OpenGL (kompatibilitet)"),
@@ -3191,7 +3193,7 @@ const SWEDISH: &[(&str, &str)] = &[
("Drop {} files to import", "Släpp {} filer för att importera"),
("Effects", "Effekter"),
("Label of {}: {}", "Etikett för {}: {}"),
("Mercury GPU Acceleration (no GPU: software)", "Mercury GPU-acceleration (ingen GPU: programvara)"),
("GPU Acceleration (no GPU: software)", "GPU-acceleration (ingen GPU: programvara)"),
("Only one project can be opened per drop; skipped {} more", "Bara ett projekt kan öppnas per släpp; hoppade över {} till"),
("Open in Essential Graphics", "Öppna i Grundläggande grafik"),
("Original color: click to go back to it", "Originalfärg: klicka för att återgå till den"),
@@ -3440,7 +3442,7 @@ const SWEDISH: &[(&str, &str)] = &[
("Script Console", "Skriptkonsol"),
("Essential Graphics", "Grundläggande grafik"),
("ScriptUI Panel", "ScriptUI-panel"),
("Lumetri Scopes", "Lumetri-scope"),
("Video Scopes", "Videoskop"),
("Media Browser", "Mediebläddrare"),
("Content-Aware Fill", "Innehållsmedveten fyllning"),
("Create Nulls From Paths", "Skapa nullobjekt från banor"),
@@ -4608,7 +4610,7 @@ const TRADITIONAL_CHINESE: &[(&str, &str)] = &[
("Script Console", "指令碼主控台"),
("Essential Graphics", "基本圖形"),
("ScriptUI Panel", "ScriptUI 面板"),
("Lumetri Scopes", "Lumetri 示波器"),
("Video Scopes", "視訊示波器"),
("Media Browser", "媒體瀏覽器"),
("Content-Aware Fill", "內容感知填色"),
("Create Nulls From Paths", "從路徑建立空物件"),
@@ -4761,6 +4763,9 @@ const TRADITIONAL_CHINESE: &[(&str, &str)] = &[
("Blend Mode", "混合模式"),
("Show mesh", "顯示網格"),
("Record Options...", "記錄選項..."),
("Software Rendering", "軟體算繪"),
("GPU Acceleration ({})", "GPU 加速({})"),
("GPU Acceleration (no GPU: software)", "GPU 加速(無 GPU:軟體)"),
];
/// Ukrainian (uk): original translations of the same interface rows as the Chinese catalogs.
@@ -5301,8 +5306,8 @@ const UKRAINIAN: &[(&str, &str)] = &[
("Import Photoshop File", "Імпорт файлу Photoshop"),
("Interpret Unlabeled Alpha As", "Інтерпретувати непозначену альфу як"),
("Join the ArtCraft Discord", "Приєднатися до Discord ArtCraft"),
("Mercury GPU Acceleration ({})", "Прискорення Mercury GPU ({})"),
("Mercury Software Only", "Лише програмний Mercury"),
("GPU Acceleration ({})", "Прискорення GPU ({})"),
("Software Rendering", "Програмне відтворення"),
("OCIO (built-in ACES config)", "OCIO (вбудована конфігурація ACES)"),
("Off (Final Quality)", "Вимкнено (остаточна якість)"),
("OpenGL (compatibility)", "OpenGL (сумісність)"),
@@ -5348,6 +5353,8 @@ const UKRAINIAN: &[(&str, &str)] = &[
("Project", "Проєкт"),
("Total Offset", "Загальний зсув"),
("Per Layer", "На шар"),
("Video Scopes", "Відеоскопи"),
("GPU Acceleration (no GPU: software)", "Прискорення GPU (без GPU: програмне)"),
];
// Brazilian Portuguese.
@@ -5979,7 +5986,7 @@ const PORTUGUESE: &[(&str, &str)] = &[
("Guess", "Adivinhar"),
("Import Image Sequence", "Importar sequência de imagens"),
("Import PDF / Illustrator File", "Importar arquivo PDF / Illustrator"),
("Mercury Software Only", "Apenas software Mercury"),
("Software Rendering", "Renderização por software"),
("OCIO (built-in ACES config)", "OCIO (config do ACES integrado)"),
("Still Duration", "Duração da imagem fixa"),
("Straight", "Direto"),
@@ -6086,7 +6093,7 @@ const PORTUGUESE: &[(&str, &str)] = &[
("Light", "Claro"),
("Lines", "Linhas"),
("Memory & CPU", "Memória e CPU"),
("Mercury GPU Acceleration ({})", "Aceleração de GPU Mercury ({})"),
("GPU Acceleration ({})", "Aceleração de GPU ({})"),
("Off", "Desativado"),
("Options", "Opções"),
("Overlay", "Sobrepor"),
@@ -6111,6 +6118,8 @@ const PORTUGUESE: &[(&str, &str)] = &[
("Video", "Vídeo"),
("channel", "canal"),
("files", "arquivos"),
("Video Scopes", "Escopos de vídeo"),
("GPU Acceleration (no GPU: software)", "Aceleração de GPU (sem GPU: software)"),
];
/// Polish (pl): original translations covering every row in the Chinese panel catalogs.
@@ -6629,8 +6638,8 @@ const POLISH: &[(&str, &str)] = &[
("Import Photoshop File", "Importuj plik Photoshopa"),
("Interpret Unlabeled Alpha As", "Interpretuj nieoznaczoną alfę jako"),
("Join the ArtCraft Discord", "Dołącz do Discorda ArtCraft"),
("Mercury GPU Acceleration ({})", "Akceleracja Mercury GPU ({})"),
("Mercury Software Only", "Tylko programowy Mercury"),
("GPU Acceleration ({})", "Akceleracja GPU ({})"),
("Software Rendering", "Renderowanie programowe"),
("OCIO (built-in ACES config)", "OCIO (wbudowana konfiguracja ACES)"),
("Off (Final Quality)", "Wył. (jakość końcowa)"),
("OpenGL (compatibility)", "OpenGL (zgodność)"),
@@ -6868,6 +6877,8 @@ const POLISH: &[(&str, &str)] = &[
("Resolution:", "Rozdzielczość:"),
("Guide Layer", "Warstwa pomocnicza"),
("Layer Styles", "Style warstwy"),
("Video Scopes", "Wskaźniki wideo"),
("GPU Acceleration (no GPU: software)", "Akceleracja GPU (bez GPU: programowa)"),
];
/// Czech (cs): original translations covering every row in the Chinese panel catalogs.
@@ -7380,8 +7391,8 @@ const CZECH: &[(&str, &str)] = &[
("Import Photoshop File", "Importovat soubor Photoshop"),
("Interpret Unlabeled Alpha As", "Interpretovat neoznačenou alfu jako"),
("Join the ArtCraft Discord", "Připojit se na Discord ArtCraft"),
("Mercury GPU Acceleration ({})", "GPU akcelerace Mercury ({})"),
("Mercury Software Only", "Pouze softwarové zpracování Mercury"),
("GPU Acceleration ({})", "Akcelerace GPU ({})"),
("Software Rendering", "Softwarové vykreslování"),
("OCIO (built-in ACES config)", "OCIO (vestavěná konfigurace ACES)"),
("Off (Final Quality)", "Vypnuto (finální kvalita)"),
("OpenGL (compatibility)", "OpenGL (kompatibilita)"),
@@ -7432,6 +7443,8 @@ const CZECH: &[(&str, &str)] = &[
("Variable fonts only", "Jen proměnná písma"),
("Total Offset", "Celkový posun"),
("Per Layer", "Na vrstvu"),
("Video Scopes", "Videoskopy"),
("GPU Acceleration (no GPU: software)", "Akcelerace GPU (bez GPU: software)"),
];
/// Spanish: neutral, tú, sentence case; the same source strings as the Chinese catalogs, in the same
@@ -7960,8 +7973,8 @@ const SPANISH: &[(&str, &str)] = &[
("Import Photoshop File", "Importar archivo de Photoshop"),
("Interpret Unlabeled Alpha As", "Interpretar alfa sin etiquetar como"),
("Join the ArtCraft Discord", "Únete al Discord de ArtCraft"),
("Mercury GPU Acceleration ({})", "Aceleración por GPU Mercury ({})"),
("Mercury Software Only", "Solo software Mercury"),
("GPU Acceleration ({})", "Aceleración por GPU ({})"),
("Software Rendering", "Renderizado por software"),
("OCIO (built-in ACES config)", "OCIO (configuración ACES integrada)"),
("Off (Final Quality)", "Desactivado (calidad final)"),
("OpenGL (compatibility)", "OpenGL (compatibilidad)"),
@@ -8002,6 +8015,8 @@ const SPANISH: &[(&str, &str)] = &[
("After Effects project", "Proyecto de After Effects"),
("Lottie animation", "Animación de Lottie"),
("Project", "Proyecto"),
("Video Scopes", "Monitores de vídeo"),
("GPU Acceleration (no GPU: software)", "Aceleración por GPU (sin GPU: software)"),
];
/// Georgian (ka): every row of the Chinese catalogs, in the same order (the tests keep them in step).
@@ -8528,8 +8543,8 @@ const GEORGIAN: &[(&str, &str)] = &[
("Import Photoshop File", "Photoshop ფაილის იმპორტი"),
("Interpret Unlabeled Alpha As", "უცნობი ალფას ინტერპრეტაცია"),
("Join the ArtCraft Discord", "შემოგვიერთდით Discord-ზე"),
("Mercury GPU Acceleration ({})", "GPU აჩქარება ({})"),
("Mercury Software Only", "მხოლოდ Mercury Software"),
("GPU Acceleration ({})", "GPU აჩქარება ({})"),
("Software Rendering", "პროგრამული რენდერი"),
("OCIO (built-in ACES config)", "OCIO (ჩაშენებული ACES კონფიგურაცია)"),
("Off (Final Quality)", "გამორთული (საბოლოო ხარისხი)"),
("OpenGL (compatibility)", "OpenGL (თავსებადობა)"),
@@ -8761,6 +8776,7 @@ const GEORGIAN: &[(&str, &str)] = &[
("Total Offset", "ჯამური წანაცვლება"),
("Per Layer", "შრიდან შრემდე"),
("Track", "ტრეკინგი"),
("Video Scopes", "ვიდეოსკოპები"),
];
/// Georgian rows for interface text no other catalog has yet: strings the panels already send
@@ -8951,7 +8967,7 @@ const GEORGIAN_PANELS: &[(&str, &str)] = &[
("Solid Settings", "სოლიდის პარამეტრები"),
("Save as Template", "შაბლონად შენახვა"),
("My Custom RGB", "ჩემი მორგებული RGB"),
("Mercury GPU Acceleration (no GPU: software)", "Mercury GPU აჩქარება (GPU არ არის: პროგრამული)"),
("GPU Acceleration (no GPU: software)", "GPU აჩქარება (GPU არ არის: პროგრამული)"),
("Sort by {}, {}", "დალაგება: {}, {}"),
("Sort by {}", "დალაგება: {}"),
("Label of {}: {}", "{}-ის იარლიყი: {}"),
@@ -9510,8 +9526,8 @@ const FRENCH: &[(&str, &str)] = &[
("Import Photoshop File", "Importer un fichier Photoshop"),
("Interpret Unlabeled Alpha As", "Interpréter l’alpha non étiqueté comme"),
("Join the ArtCraft Discord", "Rejoindre le Discord ArtCraft"),
("Mercury GPU Acceleration ({})", "Accélération GPU Mercury ({})"),
("Mercury Software Only", "Mercury, logiciel uniquement"),
("GPU Acceleration ({})", "Accélération GPU ({})"),
("Software Rendering", "Rendu logiciel"),
("OCIO (built-in ACES config)", "OCIO (configuration ACES intégrée)"),
("Off (Final Quality)", "Désactivé (qualité finale)"),
("OpenGL (compatibility)", "OpenGL (compatibilité)"),
@@ -9926,7 +9942,7 @@ const FRENCH: &[(&str, &str)] = &[
("Solid Settings", "Paramètres du solide"),
("Save as Template", "Enregistrer en tant que modèle"),
("My Custom RGB", "Mon RVB personnalisé"),
("Mercury GPU Acceleration (no GPU: software)", "Accélération GPU Mercury (aucun GPU : logiciel)"),
("GPU Acceleration (no GPU: software)", "Accélération GPU (aucun GPU : logiciel)"),
("Sort by {}, {}", "Trier par {}, {}"),
("Sort by {}", "Trier par {}"),
("Label of {}: {}", "Étiquette de {} : {}"),
@@ -10047,7 +10063,7 @@ const FRENCH: &[(&str, &str)] = &[
("Script Console", "Console de scripts"),
("Essential Graphics", "Graphiques essentiels"),
("ScriptUI Panel", "Panneau ScriptUI"),
("Lumetri Scopes", "Scopes Lumetri"),
("Video Scopes", "Oscilloscopes vidéo"),
("Media Browser", "Explorateur de médias"),
("Content-Aware Fill", "Remplissage adapté au contenu"),
("Create Nulls From Paths", "Créer des objets nuls à partir de tracés"),
@@ -10266,6 +10282,26 @@ const FRENCH: &[(&str, &str)] = &[
mod tests {
use super::*;
/// Check rendered feature labels only. Format names, compatibility tokens and user text
/// are not subject to this guard, and a missing translation keeps its English fallback.
#[test]
fn renamed_panel_labels_do_not_reintroduce_vendor_names() {
for language in ["en", "ja", "zh-hans", "zh-hant", "fr", "sv", "ka", "cs", "de", "es", "pl", "pt-br", "ru", "uk"] {
set_current(language);
for source in ["GPU Acceleration ({})", "GPU Acceleration (no GPU: software)", "Software Rendering", "Video Scopes"] {
let rendered = tr(source);
assert!(!rendered.is_empty(), "{language}: {source}");
let label = rendered.to_lowercase();
for mark in ["lumetri", "mercury", "mocha", "keylight"] {
assert!(!label.contains(mark), "{language}: {source} -> {rendered}");
}
}
// A real interchange label remains factual, not rewritten or rejected.
assert!(!tr("Export Adobe Premiere Pro Project").is_empty());
}
set_current("en");
}
/// The interface text that has moved into this catalog. Add a panel here when you convert it;
/// `every_row_is_used_by_a_converted_panel` then looks for its rows' English sources in it.
pub(super) const CONVERTED: &[(&str, &str)] = &[
+16 -4
View File
@@ -338,11 +338,11 @@ fn interpret_footage_form(s: &effectcraft_engine::Session, proxy: bool, base: &m
/// The Project Settings dialog's title and fields.
fn project_settings_form(s: &effectcraft_engine::Session) -> (String, Vec<Field>) {
let st = &s.project.settings;
// The catalogue row is `Mercury GPU Acceleration ({})`, so the value goes through
// The catalogue row is `GPU Acceleration ({})`, so the value goes through
// tr_args: wrapping the assembled string in tr() would look up the backend's name.
let gpu_label = match &s.accel {
Some(a) => tr_args("Mercury GPU Acceleration ({})", &[&a.name()]),
None => tr("Mercury GPU Acceleration (no GPU: software)").to_string(),
Some(a) => tr_args("GPU Acceleration ({})", &[&a.name()]),
None => tr("GPU Acceleration (no GPU: software)").to_string(),
};
let depth = match st.bit_depth.label() {
l if l.starts_with("16") => 1,
@@ -436,7 +436,7 @@ fn project_settings_form(s: &effectcraft_engine::Session) -> (String, Vec<Field>
Field::choice(
"renderer",
"Video rendering and effects",
&[(gpu_label.as_str(), json!("gpu")), ("Mercury Software Only", json!("software"))],
&[(gpu_label.as_str(), json!("gpu")), ("Software Rendering", json!("software"))],
usize::from(!st.gpu_acceleration),
),
],
@@ -1050,6 +1050,18 @@ pub fn show_view_options(app: &mut EffectcraftApp, ctx: &egui::Context, t: &Toke
mod tests {
use super::*;
#[test]
fn renderer_form_keeps_descriptive_labels_and_stable_option_values() {
crate::i18n::set_current("en");
let (_, fields) = project_settings_form(&effectcraft_engine::Session::default());
let renderer = fields.iter().find(|field| field.key == "renderer").unwrap();
let FieldKind::Choice { options, .. } = &renderer.kind else { panic!("renderer must be a choice") };
assert_eq!(
options.as_slice(),
&[("GPU Acceleration (no GPU: software)".to_string(), json!("gpu")), ("Software Rendering".to_string(), json!("software"))]
);
}
#[test]
fn form_params_build_arrays_and_choices() {
let f = Form {
+1 -1
View File
@@ -756,7 +756,7 @@ pub struct UiState {
/// Flowchart panel options (layers, effects, solids, direction, root comp).
#[serde(default)]
pub flowchart: crate::panels::flowchart::FlowOptions,
/// Lumetri Scopes panel options.
/// Video Scopes panel options.
#[serde(default)]
pub scopes: crate::panels::scopes_panel::ScopesState,
}
+1 -1
View File
@@ -38,7 +38,7 @@ fn harness(panel: Panel, angle: f64) -> (Harness<'static, EffectcraftApp>, u64,
s.execute("comp.new", json!({"name": "Angles", "width": 320, "height": 180, "duration": 4})).unwrap();
let layer = s.execute("layer.newSolid", json!({"name": "Plate", "color": "#40b080"})).unwrap()["layer"].as_u64().unwrap();
let uid = if matches!(panel, Panel::EffectControls) {
let fx = s.execute("effect.apply", json!({"layer": layer, "effect": "CC Bend It"})).unwrap()["effects"][0].as_u64().unwrap();
let fx = s.execute("effect.apply", json!({"layer": layer, "effect": "Two-Point Bend"})).unwrap()["effects"][0].as_u64().unwrap();
s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.find_group(fx).unwrap().get("bend").unwrap().uid
} else {
s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.prop("transform/rotation").unwrap().uid
+2 -2
View File
@@ -1,4 +1,4 @@
//! The colour picker every colour input opens: its hex field sets an effect's colour (CC Toner),
//! The colour picker every colour input opens: its hex field sets an effect's colour (Multi-Tone Tint),
//! the dialogs' colour button stores sRGB (egui's own `color_edit_button_rgba` read the stored
//! sRGB values as linear, so mid-grey `#808080` was stored as `#373737`), the square, slider and
//! HSB / RGB fields set the colour, and Cancel / Escape / the original swatch restore it.
@@ -45,7 +45,7 @@ fn hex_code_sets_an_effect_colour() {
let mut s = Session::default();
s.execute("comp.new", json!({"name": "Hex", "width": 320, "height": 180, "duration": 4})).unwrap();
let layer = s.execute("layer.newSolid", json!({"name": "Plate", "color": "#40b080"})).unwrap()["layer"].as_u64().unwrap();
let fx = s.execute("effect.apply", json!({"layer": layer, "effect": "CC Toner"})).unwrap()["effects"][0].as_u64().unwrap();
let fx = s.execute("effect.apply", json!({"layer": layer, "effect": "Multi-Tone Tint"})).unwrap()["effects"][0].as_u64().unwrap();
let uid = s.active_comp().unwrap().layer(LayerId(layer)).unwrap().props.find_group(fx).unwrap().get("midtones").unwrap().uid;
s.state.selected_layers = vec![LayerId(layer)];
let mut app = EffectcraftApp::new(s);
@@ -260,14 +260,14 @@ fn the_eyedropper_stays_armed_until_the_viewer_has_a_frame() {
}
}
/// Key Light's Screen Colour eyedropper picks from the effect's input: the shown frame is
/// Screen Color Key's Screen Colour eyedropper picks from the effect's input: the shown frame is
/// already keyed (the default screen colour takes most of a green), so sampling it would miss.
#[test]
fn keyer_eyedropper_picks_the_screen_from_the_effect_input() {
let mut s = Session::default();
s.execute("comp.new", json!({"name": "Key", "width": 320, "height": 180, "frameRate": 30, "duration": 1})).unwrap();
let screen = s.execute("layer.newSolid", json!({"name": "Screen", "color": "#30b050"})).unwrap()["layer"].as_u64().unwrap();
let fx = s.execute("effect.apply", json!({"layers": [screen], "effect": "Key Light"})).unwrap()["effects"][0].as_u64().unwrap();
let fx = s.execute("effect.apply", json!({"layers": [screen], "effect": "Screen Color Key"})).unwrap()["effects"][0].as_u64().unwrap();
let prop = layer(&s, screen).effects().unwrap().groups().find(|g| g.uid == fx).and_then(|g| g.get("screenColour")).map(|p| p.uid).unwrap();
s.state.selected_layers = vec![LayerId(screen)];
let mut app = EffectcraftApp::new(s);
@@ -295,7 +295,7 @@ fn keyer_eyedropper_picks_the_screen_from_the_effect_input() {
fn command_clicking_an_effect_twirl_closes_and_opens_its_groups() {
let (app, x) = app();
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| app);
let fx = h.state_mut().session.execute("effect.apply", json!({"layers": [x.small], "effect": "Lumetri Color"})).unwrap()["effects"][0].as_u64().unwrap();
let fx = h.state_mut().session.execute("effect.apply", json!({"layers": [x.small], "effect": "Color Grading"})).unwrap()["effects"][0].as_u64().unwrap();
// Only this effect open, so its header is on screen.
let l = layer(&h.state().session, x.small);
let others: Vec<u64> = l.effects().unwrap().groups().map(|g| g.uid).filter(|u| *u != fx).collect();
@@ -13,7 +13,7 @@ fn rect(h: &Harness<'_, EffectcraftApp>, id: &str) -> Rect {
fn drag_to(h: &mut Harness<'_, EffectcraftApp>, p: Pos2) {
h.input_mut().events.push(Event::PointerMoved(p));
h.input_mut().events.push(Event::PointerButton { pos: p, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE });
egui::DragAndDrop::set_payload(&h.ctx, DragPayload::Effect("CC Bend It".into()));
egui::DragAndDrop::set_payload(&h.ctx, DragPayload::Effect("Two-Point Bend".into()));
h.run_steps(2);
}
+1 -1
View File
@@ -130,7 +130,7 @@ fn undo(h: &mut Harness<'_, EffectcraftApp>) {
#[test]
fn lumetri_rgb_and_hue_saturation_curve_editors() {
let (s0, l, fx) = with_effect("Lumetri Color");
let (s0, l, fx) = with_effect("Color Grading");
let mut h = harness(s0);
only_groups(&mut h, l, fx, &["curves", "rgbCurves", "hueSaturationCurves"]);
let pre = format!("effectControls.effect.{fx}.lumetri.rgbCurves");
+2 -2
View File
@@ -77,12 +77,12 @@ fn position_anchor_and_effect_edits_present_intermediate_pixels() {
(None, "transform/position", json!([22, 18, 0]), json!([18, 18, 0])),
(None, "transform/anchor", json!([9, 8, 0]), json!([6, 8, 0])),
(Some("Gaussian Blur"), "blurriness", json!(3), json!(6)),
(Some("CC Radial Fast Blur"), "center", json!([4, 4]), json!([18, 12])),
(Some("Fast Radial Blur"), "center", json!([4, 4]), json!([18, 12])),
] {
let mut session = Session::default();
session.execute("comp.new", json!({"width":64,"height":36,"duration":1})).unwrap();
let layer = session.execute("layer.newSolid", json!({"color":"#ffffff","width":24,"height":16})).unwrap()["layer"].as_u64().unwrap();
if effect == Some("CC Radial Fast Blur") {
if effect == Some("Fast Radial Blur") {
// A uniform solid is invariant under a radial blur; give the point edit visible detail.
session.execute("effect.apply", json!({"layers":[layer],"effect":"Gradient Ramp"})).unwrap();
}
@@ -54,7 +54,7 @@ fn nested_groups_keep_indentation_value_alignment_and_effect_gaps_at_fixed_compa
let mut s = Session::default();
s.execute("comp.new", json!({"width":64,"height":36,"duration":1})).unwrap();
s.execute("layer.newSolid", json!({"name":"Plate","color":"#406080"})).unwrap();
let fx = s.execute("effect.apply", json!({"effect":"Lumetri Color"})).unwrap()["effects"][0].as_u64().unwrap();
let fx = s.execute("effect.apply", json!({"effect":"Color Grading"})).unwrap()["effects"][0].as_u64().unwrap();
let next = s.execute("effect.apply", json!({"effect":"Checkbox Control"})).unwrap()["effects"][0].as_u64().unwrap();
let g = s.active_comp().unwrap().layers[0].props.find_group(fx).unwrap();
let basic = g.sub("basicCorrection").unwrap();
+1 -1
View File
@@ -2370,7 +2370,7 @@ fn command_clicking_a_group_twirl_opens_its_whole_tree() {
// twirls open with it, and closed again with it.
let mut h = harness();
let id = layer_id(&h, "Box");
h.state_mut().session.execute("effect.apply", json!({"effect": "Lumetri Color", "layers": [id]})).unwrap();
h.state_mut().session.execute("effect.apply", json!({"effect": "Color Grading", "layers": [id]})).unwrap();
fn walk(g: &effectcraft_engine::project::PropGroup, out: &mut Vec<u64>) {
for sg in g.groups() {
out.push(sg.uid);
+13 -13
View File
@@ -121,7 +121,7 @@ are not rewritten, so an expression that computes an effect point on a shape or
other values may need `+ [thisComp.width / 2, thisComp.height / 2]`. Effects that use the layer
bounds (edge pinning, wipes, Offset, generators) now cover the whole comp-sized bounds instead of
their bottom-right quarter. Tracking data of effects that analyse footage (Warp Stabilizer, 3D
Camera Tracker, Mocha shape) is left as it is: footage has a source rectangle, whose effect space
Camera Tracker, Tracked Shape Matte) is left as it is: footage has a source rectangle, whose effect space
did not change.
## 4. Rendering
@@ -331,7 +331,7 @@ before conversion (a quarter of the conversions; the result differs from convert
in blocks where colours clip) and resampled from there, as other frames are from full size.
**GPU compositor** (`crates/gpu`; Project Settings ▸ Video Rendering and Effects ▸ Mercury GPU
Acceleration, the default, or Mercury Software Only; `render.backend`). The CPU renderer is the
Acceleration, the default, or Software Rendering; `render.backend`). The CPU renderer is the
reference and keeps rendering layer content (sources, masks, CPU effects, layer styles) into the
layer cache. The render crate defines an `Accelerator` trait; `effectcraft_gpu::Gpu` implements it
on wgpu compute shaders. `RenderOpts::backend` picks `Cpu`, `Gpu` or `Auto` (an accelerator
@@ -341,7 +341,7 @@ per comp, output scale and path (readback or viewer display) it averages CPU and
(warm-up on both sides, the fastest warm-up frame starting the average, single stalls capped),
picks the GPU unless the CPU is clearly faster, and re-measures the other side every 48 frames.
Render Queue jobs don't use Auto: every frame of a job renders on the project's renderer (the
GPU compositor with Mercury GPU Acceleration), so runs of a render don't differ by timing.
GPU compositor with GPU Acceleration), so runs of a render don't differ by timing.
Light comps (a few small layers, which the CPU composites only within their bounds) then stay on
the CPU instead of paying for full-frame passes and a readback. A GPU frame walks the comp like
`draw_comp`: cached layer buffers are uploaded once per buffer, then transformed with the CPU's
@@ -370,16 +370,16 @@ Preserve Transparency / blend kernels (a 3D track matte renders solo through the
Environment Light Background layers draw their sky in a kernel (`adv_sky`, from
`Renderer::sky_draw`) before the rest of the run, in Classic and Advanced 3D comps. Wireframe
outlines draw on the GPU from the CPU's pixel list (`Renderer::wireframe_pixels`). GPU effects
(`effects::GPU_EFFECTS`, 280 of them: blurs, colour correction, keying incl. Key Light, mattes,
channel, stylize, distortion and warps (Warp, Bezier Warp, Smear, Reshape, CC Bend It, CC Page
Turn, CC Bender, CC Blobbylize), Cartoon, bevels, shapes, the transitions (CC light family, CC
transitions, Block Dissolve), perspective (Radial Shadow, CC Cylinder / Sphere / Spotlight /
(`effects::GPU_EFFECTS`, 280 of them: blurs, colour correction, keying incl. Screen Color Key, mattes,
channel, stylize, distortion and warps (Warp, Bezier Warp, Smear, Reshape, Two-Point Bend, CC Page
Turn, Flexible Bend, Organic Displacement), Cartoon, bevels, shapes, the transitions (CC light family, CC
transitions, Block Dissolve), perspective (Radial Shadow, Cylinder Wrap / Sphere / Spotlight /
Environment, 3D Glasses), generators, noise, grain, text (Numbers, Timecode), time, 3D Channel (aux channels as an
extra texture), Immersive Video, colour management (colour programs from
`effects::color_program`, LUTs in a storage buffer) and the simulations' render passes (the
simulation stays on the CPU and hands its plan — sprites, pieces, blobs, grids — to a tiled
rasteriser; the particle effects too, `gpu::fx_particles`: CC Particle World / Systems II,
Particle Playground with its Layer Map frames in one atlas, CC Ball Action, CC Pixel Polly, CC
rasteriser; the particle effects too, `gpu::fx_particles`: Particle Emitter 3D / Systems II,
Particle Playground with its Layer Map frames in one atlas, Ball Grid, Pixel Shatter, CC
Scatterize; plans too large for one item table draw in several passes over the previous one),
and the geometry generators (Lightning, Advanced Lightning, Radio Waves, Stroke, Scribble,
Vegas, Write-on, Audio Spectrum / Waveform, Basic / Path Text: bolts, strokes, waves, audio
@@ -390,7 +390,7 @@ as kernels, in one module per family (`gpu::fx_*` with `shaders/fx_*.wgsl`); con
effects run as one chain with one upload and one readback. Statistics that need the whole frame
(Auto Levels / Contrast / Color, Equalize, Shadow/Highlight, Color Stabilizer, Remove Grain's
noise level) are measured on the CPU from one readback and applied on the GPU; effects reading
other frames (Echo, Posterize Time, Time Difference, Time Displacement, CC Force Motion Blur, CC
other frames (Echo, Posterize Time, Time Difference, Time Displacement, Temporal Motion Blur, CC
Wide Time, Pixel Motion Blur, Timewarp) upload the frames the host renders (`time_frames`) and
combine them on the GPU; Time Displacement's per-pixel times and Timewarp's motion vectors
(`time_fx::timewarp_plan`) are computed on the CPU. Numbers and Timecode rasterise their glyph
@@ -433,12 +433,12 @@ sentinel is implemented here. Browser scope futures are not synchronously awaite
forwards shared-device errors, while owned worker devices install their own handlers. On the web
(WebGPU) the GPU composites viewer frames; steps that need a readback fall back to the CPU (the
Info panel's pixel readout reads GPU frames back asynchronously). **GPU particles**
(`effects::psim`, `gpu::particles`): CC Particle World, CC Particle Systems II and Particle
(`effects::psim`, `gpu::particles`): Particle Emitter 3D, Particle Emitter 2D and Particle
Playground cannons without interacting forces evolve every particle independently, so the GPU
backend (reached through `EffectHost::particles` when the GPU compositor is active) simulates one
particle per invocation from the CPU's birth schedule and keeps per-key state checkpoints on the
GPU, like `SimCache`; the CPU simulation stays the oracle (tests compare ids and positions).
CC Particle World, CC Particle Systems II and CC Mr. Mercury sample their Birth Rate at every
Particle Emitter 3D, Particle Emitter 2D and Liquid Particles sample their Birth Rate at every
step (`EffectHost::param_at`, #1373), so a keyed rate only decides the births of its own time;
the rate is left out of the simulation key, and a checkpoint is resumed only with the same rate history (the CPU state's `hist`, the GPU
checkpoint's births). The rate's keyframes are read at the step's exact layer time
@@ -629,7 +629,7 @@ Unix milliseconds. The layer's Start Time becomes `dataStart + videoStart − fi
(`videoStart` given, or the file's creation date on the desktop; reduced to a time of day when
the data has no dates).
**Lumetri Scopes** (`raster::scopes`) are density plots of the viewer frame (rendered over the
**Video Scopes** (`raster::scopes`) are density plots of the viewer frame (rendered over the
comp background) with BT.601 / BT.709 / BT.2020 luma and colour-difference coefficients.
## 5. Expressions
+72 -72
View File
@@ -48,21 +48,21 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| Bilateral Blur | `ec.blur.bilateral` | 3 | GPU | 32 | Implemented |
| CC Cross Blur | `ec.blur.cccross` | 3 | GPU | 32 | Implemented |
| CC Radial Blur | `ec.blur.ccradial` | 4 | GPU | 32 | Implemented |
| CC Radial Fast Blur | `ec.blur.ccradialfast` | 3 | GPU | 32 | Implemented |
| CC Vector Blur | `ec.blur.ccvector` | 4 | GPU | 32 | Implemented |
| Camera Lens Blur | `ec.blur.cameralens` | 16 | GPU | 32 | Implemented |
| Camera-Shake Deblur | `ec.blur.camerashakedeblur` | 8 | | 32 | Implemented |
| Channel Blur | `ec.blur.channel` | 6 | GPU | 32 | Implemented |
| Compound Blur | `ec.blur.compound` | 4 | GPU | 32 | Implemented |
| Cross Blur | `ec.blur.cccross` | 3 | GPU | 32 | Implemented |
| Directional Blur | `ec.blur.directional` | 2 | GPU | 32 | Implemented |
| Fast Box Blur | `ec.blur.fastbox` | 4 | GPU | 32 | Implemented |
| Fast Radial Blur | `ec.blur.ccradialfast` | 3 | GPU | 32 | Implemented |
| Gaussian Blur | `ec.blur.gaussian` | 3 | GPU | 32 | Implemented |
| Radial Blur | `ec.blur.radial` | 4 | GPU | 32 | Implemented |
| Sharpen | `ec.blur.sharpen` | 1 | GPU | 32 | Implemented |
| Smart Blur | `ec.blur.smart` | 3 | GPU | 32 | Implemented |
| Unsharp Mask | `ec.blur.unsharp` | 3 | GPU | 32 | Implemented |
| Variable Radial Blur | `ec.blur.ccradial` | 4 | GPU | 32 | Implemented |
| Vector Blur | `ec.blur.ccvector` | 4 | GPU | 32 | Implemented |
## Channel
@@ -70,7 +70,6 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
|---|---|---:|:-:|:-:|---|
| Arithmetic | `ec.channel.arithmetic` | 5 | GPU | 32 | Implemented |
| Blend | `ec.channel.blend` | 4 | GPU | 32 | Implemented |
| CC Composite | `ec.channel.cccomposite` | 3 | GPU | 32 | Implemented |
| Calculations | `ec.channel.calculations` | 9 | GPU | 32 | Implemented |
| Channel Combiner | `ec.channel.combiner` | 6 | GPU | 32 | Implemented |
| Compound Arithmetic | `ec.channel.compoundarithmetic` | 6 | GPU | 32 | Implemented |
@@ -81,6 +80,7 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Set Matte | `ec.channel.setmatte` | 6 | GPU | 32 | Implemented |
| Shift Channels | `ec.channel.shiftchannels` | 4 | GPU | 32 | Implemented |
| Solid Composite | `ec.channel.solidcomposite` | 4 | GPU | 32 | Implemented |
| Source Composite | `ec.channel.cccomposite` | 3 | GPU | 32 | Implemented |
## Color Correction
@@ -92,18 +92,18 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Black & White | `ec.color.blackwhite` | 8 | GPU | 32 | Implemented |
| Brightness & Contrast | `ec.color.brightnesscontrast` | 3 | GPU | 32 | Implemented |
| Broadcast Colors | `ec.color.broadcast` | 3 | GPU | 32 | Implemented |
| CC Color Neutralizer | `ec.color.cccolorneutralizer` | 11 | GPU | 32 | Implemented |
| CC Color Offset | `ec.color.cccoloroffset` | 4 | GPU | 32 | Implemented |
| CC Kernel | `ec.color.cckernel` | 12 | GPU | 32 | Implemented |
| CC Toner | `ec.color.cctoner` | 7 | GPU | 32 | Implemented |
| Change Color | `ec.color.changecolor` | 9 | GPU | 32 | Implemented |
| Change to Color | `ec.color.changetocolor` | 9 | GPU | 32 | Implemented |
| Channel Mixer | `ec.color.channelmixer` | 13 | GPU | 32 | Implemented |
| Channel Offset | `ec.color.cccoloroffset` | 4 | GPU | 32 | Implemented |
| Color Balance | `ec.color.colorbalance` | 10 | GPU | 32 | Implemented |
| Color Balance (HLS) | `ec.color.colorbalancehls` | 3 | GPU | 32 | Implemented |
| Color Grading | `ec.color.lumetri` | 66 | GPU | 32 | Implemented |
| Color Link | `ec.color.colorlink` | 6 | GPU | 32 | Implemented |
| Color Neutralizer | `ec.color.cccolorneutralizer` | 11 | GPU | 32 | Implemented |
| Color Stabilizer | `ec.color.colorstabilizer` | 6 | GPU | 32 | Implemented |
| Colorama | `ec.color.colorama` | 20 | GPU | 32 | Implemented |
| Convolution Kernel | `ec.color.cckernel` | 12 | GPU | 32 | Implemented |
| Curves | `ec.color.curves` | 0 | GPU | 32 | Implemented |
| Equalize | `ec.color.equalize` | 2 | GPU | 32 | Implemented |
| Exposure | `ec.color.exposure` | 14 | GPU | 32 | Implemented |
@@ -112,7 +112,7 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Leave Color | `ec.color.leavecolor` | 5 | GPU | 32 | Implemented |
| Levels | `ec.color.levels` | 36 | GPU | 32 | Implemented |
| Levels (Individual Controls) | `ec.color.levelsic` | 27 | GPU | 32 | Implemented |
| Lumetri Color | `ec.color.lumetri` | 66 | GPU | 32 | Implemented |
| Multi-Tone Tint | `ec.color.cctoner` | 7 | GPU | 32 | Implemented |
| OCIO CDL Transform | `ec.color.ociocdl` | 12 | GPU | 32 | Implemented |
| OCIO Color Space Transform | `ec.color.ociocolorspace` | 7 | GPU | 32 | Implemented |
| OCIO Display Transform | `ec.color.ociodisplay` | 9 | GPU | 32 | Implemented |
@@ -133,40 +133,40 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
|---|---|---:|:-:|:-:|---|
| Bezier Warp | `ec.distort.bezierwarp` | 13 | GPU | 32 | Implemented |
| Bulge | `ec.distort.bulge` | 6 | GPU | 32 | Implemented |
| CC Bend It | `ec.distort.ccbendit` | 4 | GPU | 32 | Implemented |
| CC Bender | `ec.distort.ccbender` | 5 | GPU | 32 | Implemented |
| CC Blobbylize | `ec.distort.ccblobbylize` | 15 | GPU | 32 | Implemented |
| CC Flo Motion | `ec.distort.ccflomotion` | 7 | GPU | 32 | Implemented |
| CC Griddler | `ec.distort.ccgriddler` | 5 | GPU | 32 | Implemented |
| CC Lens | `ec.distort.cclens` | 3 | GPU | 32 | Implemented |
| CC Page Turn | `ec.distort.ccpageturn` | 7 | GPU | 32 | Implemented |
| CC Power Pin | `ec.distort.ccpowerpin` | 10 | GPU | 32 | Implemented |
| CC Ripple Pulse | `ec.distort.ccripplepulse` | 5 | GPU | 32 | Implemented |
| CC Slant | `ec.distort.ccslant` | 4 | GPU | 32 | Implemented |
| CC Smear | `ec.distort.ccsmear` | 4 | GPU | 32 | Implemented |
| CC Split | `ec.distort.ccsplit` | 3 | GPU | 32 | Implemented |
| CC Split 2 | `ec.distort.ccsplit2` | 4 | GPU | 32 | Implemented |
| CC Tiler | `ec.distort.cctiler` | 3 | GPU | 32 | Implemented |
| Corner Pin | `ec.distort.cornerpin` | 4 | GPU | 32 | Implemented |
| Detail-preserving Upscale | `ec.distort.upscale` | 4 | | 32 | Implemented |
| Directional Smear | `ec.distort.ccsmear` | 4 | GPU | 32 | Implemented |
| Displacement Map | `ec.distort.displacementmap` | 8 | GPU | 32 | Implemented |
| Dual Lens Warp | `ec.distort.ccflomotion` | 7 | GPU | 32 | Implemented |
| Dual Split Warp | `ec.distort.ccsplit2` | 4 | GPU | 32 | Implemented |
| Flexible Bend | `ec.distort.ccbender` | 5 | GPU | 32 | Implemented |
| Lens Distortion | `ec.distort.cclens` | 3 | GPU | 32 | Implemented |
| Liquify | `ec.distort.liquify` | 13 | GPU | 32 | Implemented |
| Magnify | `ec.distort.magnify` | 10 | GPU | 32 | Implemented |
| Mesh Warp | `ec.distort.meshwarp` | 3 | GPU | 32 | Implemented |
| Mirror | `ec.distort.mirror` | 2 | GPU | 32 | Implemented |
| Offset | `ec.distort.offset` | 2 | GPU | 32 | Implemented |
| Optics Compensation | `ec.distort.opticscompensation` | 6 | GPU | 32 | Implemented |
| Organic Displacement | `ec.distort.ccblobbylize` | 15 | GPU | 32 | Implemented |
| Page Curl | `ec.distort.ccpageturn` | 7 | GPU | 32 | Implemented |
| Perspective Pin | `ec.distort.ccpowerpin` | 10 | GPU | 32 | Implemented |
| Polar Coordinates | `ec.distort.polar` | 2 | GPU | 32 | Implemented |
| Pulsed Ripple | `ec.distort.ccripplepulse` | 5 | GPU | 32 | Implemented |
| Puppet | `ec.distort.puppet` | 1 | | 32 | Implemented |
| Reshape | `ec.distort.reshape` | 6 | GPU | 32 | Implemented |
| Ripple | `ec.distort.ripple` | 7 | GPU | 32 | Implemented |
| Rolling Shutter Repair | `ec.distort.rollingshutterrepair` | 5 | | 32 | Implemented |
| Scaled Tiles | `ec.distort.cctiler` | 3 | GPU | 32 | Implemented |
| Slant | `ec.distort.ccslant` | 4 | GPU | 32 | Implemented |
| Smear | `ec.distort.smear` | 8 | GPU | 32 | Implemented |
| Spherize | `ec.distort.spherize` | 2 | GPU | 32 | Implemented |
| Split Warp | `ec.distort.ccsplit` | 3 | GPU | 32 | Implemented |
| Tile Grid | `ec.distort.ccgriddler` | 5 | GPU | 32 | Implemented |
| Transform | `ec.distort.transform` | 12 | GPU | 32 | Implemented |
| Turbulent Displace | `ec.distort.turbulentdisplace` | 11 | GPU | 32 | Implemented |
| Twirl | `ec.distort.twirl` | 3 | GPU | 32 | Implemented |
| Twirl (Legacy) | `ec.distort.twirllegacy` | 3 | GPU | 32 | Implemented |
| Two-Point Bend | `ec.distort.ccbendit` | 4 | GPU | 32 | Implemented |
| Warp | `ec.distort.warp` | 5 | GPU | 32 | Implemented |
| Warp Stabilizer | `ec.distort.warpstabilizer` | 20 | | 32 | Implemented |
| Wave Warp | `ec.distort.wavewarp` | 7 | GPU | 32 | Implemented |
@@ -194,11 +194,6 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Audio Spectrum | `ec.generate.audiospectrum` | 23 | GPU | 32 | Implemented |
| Audio Waveform | `ec.generate.audiowaveform` | 17 | GPU | 32 | Implemented |
| Beam | `ec.generate.beam` | 11 | GPU | 32 | Implemented |
| CC Glue Gun | `ec.generate.ccgluegun` | 7 | GPU | 32 | Implemented |
| CC Light Burst 2.5 | `ec.generate.cclightburst` | 6 | GPU | 32 | Implemented |
| CC Light Rays | `ec.generate.cclightrays` | 8 | GPU | 32 | Implemented |
| CC Light Sweep | `ec.generate.cclightsweep` | 9 | GPU | 32 | Implemented |
| CC Threads | `ec.generate.ccthreads` | 8 | GPU | 32 | Implemented |
| Cell Pattern | `ec.generate.cellpattern` | 14 | GPU | 32 | Implemented |
| Checkerboard | `ec.generate.checkerboard` | 10 | GPU | 32 | Implemented |
| Circle | `ec.generate.circle` | 11 | GPU | 32 | Implemented |
@@ -209,11 +204,16 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Gradient Ramp | `ec.generate.gradientramp` | 7 | GPU | 32 | Implemented |
| Grid | `ec.generate.grid` | 12 | GPU | 32 | Implemented |
| Lens Flare | `ec.generate.lensflare` | 4 | GPU | 32 | Implemented |
| Light Rays | `ec.generate.cclightrays` | 8 | GPU | 32 | Implemented |
| Light Sweep | `ec.generate.cclightsweep` | 9 | GPU | 32 | Implemented |
| Paint Beads | `ec.generate.ccgluegun` | 7 | GPU | 32 | Implemented |
| Paint Bucket | `ec.generate.paintbucket` | 11 | GPU | 32 | Implemented |
| Radial Light Burst | `ec.generate.cclightburst` | 6 | GPU | 32 | Implemented |
| Radio Waves | `ec.generate.radiowaves` | 31 | GPU | 32 | Implemented |
| Scribble | `ec.generate.scribble` | 25 | GPU | 32 | Implemented |
| Stroke | `ec.generate.stroke` | 11 | GPU | 32 | Implemented |
| Vegas | `ec.generate.vegas` | 26 | GPU | 32 | Implemented |
| Woven Threads | `ec.generate.ccthreads` | 8 | GPU | 32 | Implemented |
| Write-on | `ec.generate.writeon` | 10 | GPU | 32 | Implemented |
## Immersive Video
@@ -238,15 +238,15 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| Advanced Spill Suppressor | `ec.key.advancedspill` | 8 | GPU | 32 | Implemented |
| CC Simple Wire Removal | `ec.key.ccsimplewireremoval` | 7 | GPU | 32 | Implemented |
| Color Difference Key | `ec.key.colordifference` | 16 | GPU | 32 | Implemented |
| Color Range | `ec.key.colorrange` | 8 | GPU | 32 | Implemented |
| Difference Matte | `ec.key.differencematte` | 6 | GPU | 32 | Implemented |
| Extract | `ec.key.extract` | 6 | GPU | 32 | Implemented |
| Inner/Outer Key | `ec.key.innerouter` | 88 | GPU | 32 | Implemented |
| Key Cleaner | `ec.key.keycleaner` | 4 | GPU | 32 | Implemented |
| Key Light | `ec.keying.keylight` | 56 | GPU | 32 | Implemented |
| Line Removal | `ec.key.ccsimplewireremoval` | 7 | GPU | 32 | Implemented |
| Linear Color Key | `ec.key.linearcolor` | 6 | GPU | 32 | Implemented |
| Screen Color Key | `ec.keying.keylight` | 56 | GPU | 32 | Implemented |
| Screen Key | `ec.key.screen` | 11 | GPU | 32 | Implemented |
| Unmult | `ec.key.unmult` | 6 | GPU | 32 | Implemented |
@@ -255,12 +255,12 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| Matte Choker | `ec.matte.mattechoker` | 7 | GPU | 32 | Implemented |
| Mocha shape | `ec.obsolete.mochashape` | 6 | | 32 | Implemented |
| Object Matte | `ec.matte.objectmatte` | 13 | | 32 | Implemented |
| Refine Hard Matte | `ec.matte.refinehard` | 16 | GPU | 32 | Implemented |
| Refine Soft Matte | `ec.matte.refinesoft` | 18 | GPU | 32 | Implemented |
| Roto Brush & Refine Edge | `ec.matte.rotobrush` | 25 | | 32 | Implemented |
| Simple Choker | `ec.matte.simplechoker` | 2 | GPU | 32 | Implemented |
| Tracked Shape Matte | `ec.obsolete.mochashape` | 6 | | 32 | Implemented |
## Noise & Grain
@@ -308,65 +308,65 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| 3D Glasses | `ec.perspective.3dglasses` | 8 | GPU | 32 | Implemented |
| Bevel Alpha | `ec.perspective.bevelalpha` | 4 | GPU | 32 | Implemented |
| Bevel Edges | `ec.perspective.beveledges` | 4 | GPU | 32 | Implemented |
| CC Cylinder | `ec.perspective.cccylinder` | 15 | GPU | 32 | Implemented |
| CC Environment | `ec.perspective.ccenvironment` | 4 | GPU | 32 | Implemented |
| CC Sphere | `ec.perspective.ccsphere` | 14 | GPU | 32 | Implemented |
| CC Spotlight | `ec.perspective.ccspotlight` | 8 | GPU | 32 | Implemented |
| Cylinder Wrap | `ec.perspective.cccylinder` | 15 | GPU | 32 | Implemented |
| Drop Shadow | `ec.perspective.dropshadow` | 6 | GPU | 32 | Implemented |
| Environment Map | `ec.perspective.ccenvironment` | 4 | GPU | 32 | Implemented |
| Radial Shadow | `ec.perspective.radialshadow` | 9 | GPU | 32 | Implemented |
| Sphere Wrap | `ec.perspective.ccsphere` | 14 | GPU | 32 | Implemented |
| Surface Spotlight | `ec.perspective.ccspotlight` | 8 | GPU | 32 | Implemented |
## Simulation
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| CC Ball Action | `ec.sim.ccballaction` | 8 | GPU | 32 | Implemented |
| CC Bubbles | `ec.sim.ccbubbles` | 7 | GPU | 32 | Implemented |
| CC Drizzle | `ec.sim.ccdrizzle` | 14 | GPU | 32 | Implemented |
| CC Hair | `ec.sim.cchair` | 20 | GPU | 32 | Implemented |
| CC Mr. Mercury | `ec.sim.ccmrmercury` | 23 | GPU | 32 | Implemented |
| CC Particle Systems II | `ec.sim.ccparticlesystems2` | 21 | GPU | 32 | Implemented |
| CC Particle World | `ec.sim.ccparticleworld` | 36 | GPU | 32 | Implemented |
| CC Pixel Polly | `ec.sim.ccpixelpolly` | 10 | GPU | 32 | Implemented |
| CC Rainfall | `ec.sim.ccrainfall` | 14 | GPU | 32 | Implemented |
| CC Scatterize | `ec.sim.ccscatterize` | 4 | GPU | 32 | Implemented |
| CC Snowfall | `ec.sim.ccsnowfall` | 19 | GPU | 32 | Implemented |
| CC Star Burst | `ec.sim.ccstarburst` | 6 | GPU | 32 | Implemented |
| Ball Grid | `ec.sim.ccballaction` | 8 | GPU | 32 | Implemented |
| Bubbles | `ec.sim.ccbubbles` | 7 | GPU | 32 | Implemented |
| Card Dance | `ec.sim.carddance` | 53 | GPU | 32 | Implemented |
| Caustics | `ec.sim.caustics` | 28 | GPU | 32 | Implemented |
| Foam | `ec.sim.foam` | 36 | GPU | 32 | Implemented |
| Liquid Particles | `ec.sim.ccmrmercury` | 23 | GPU | 32 | Implemented |
| Particle Emitter 2D | `ec.sim.ccparticlesystems2` | 21 | GPU | 32 | Implemented |
| Particle Emitter 3D | `ec.sim.ccparticleworld` | 36 | GPU | 32 | Implemented |
| Particle Playground | `ec.sim.particleplayground` | 92 | GPU | 32 | Implemented |
| Pixel Scatter | `ec.sim.ccscatterize` | 4 | GPU | 32 | Implemented |
| Pixel Shatter | `ec.sim.ccpixelpolly` | 10 | GPU | 32 | Implemented |
| Rainfall | `ec.sim.ccrainfall` | 14 | GPU | 32 | Implemented |
| Shatter | `ec.sim.shatter` | 60 | GPU | 32 | Implemented |
| Snowfall | `ec.sim.ccsnowfall` | 19 | GPU | 32 | Implemented |
| Starfield | `ec.sim.ccstarburst` | 6 | GPU | 32 | Implemented |
| Surface Fibers | `ec.sim.cchair` | 20 | GPU | 32 | Implemented |
| Water Ripples | `ec.sim.ccdrizzle` | 14 | GPU | 32 | Implemented |
| Wave World | `ec.sim.waveworld` | 35 | GPU | 32 | Implemented |
## Stylize
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| Block Reveal | `ec.stylize.ccblockload` | 5 | GPU | 32 | Implemented |
| Brush Strokes | `ec.stylize.brushstrokes` | 7 | GPU | 32 | Implemented |
| CC Block Load | `ec.stylize.ccblockload` | 5 | GPU | 32 | Implemented |
| CC Burn Film | `ec.stylize.ccburnfilm` | 3 | GPU | 32 | Implemented |
| CC Glass | `ec.stylize.ccglass` | 17 | GPU | 32 | Implemented |
| CC HexTile | `ec.stylize.cchextile` | 5 | GPU | 32 | Implemented |
| CC Kaleida | `ec.stylize.cckaleida` | 4 | GPU | 32 | Implemented |
| CC Mr. Smoothie | `ec.stylize.ccmrsmoothie` | 7 | GPU | 32 | Implemented |
| CC Plastic | `ec.stylize.ccplastic` | 18 | GPU | 32 | Implemented |
| CC RepeTile | `ec.stylize.ccrepetile` | 5 | GPU | 32 | Implemented |
| CC Threshold | `ec.stylize.ccthreshold` | 4 | GPU | 32 | Implemented |
| CC Threshold RGB | `ec.stylize.ccthresholdrgb` | 7 | GPU | 32 | Implemented |
| CC Vignette | `ec.stylize.ccvignette` | 4 | GPU | 32 | Implemented |
| Cartoon | `ec.stylize.cartoon` | 12 | GPU | 32 | Implemented |
| Channel Threshold | `ec.stylize.ccthreshold` | 4 | GPU | 32 | Implemented |
| Color Emboss | `ec.stylize.coloremboss` | 4 | GPU | 32 | Implemented |
| Edge Tile Repeat | `ec.stylize.ccrepetile` | 5 | GPU | 32 | Implemented |
| Emboss | `ec.stylize.emboss` | 4 | GPU | 32 | Implemented |
| Film Burn | `ec.stylize.ccburnfilm` | 3 | GPU | 32 | Implemented |
| Find Edges | `ec.stylize.findedges` | 2 | GPU | 32 | Implemented |
| Glass Relief | `ec.stylize.ccglass` | 17 | GPU | 32 | Implemented |
| Glow | `ec.stylize.glow` | 14 | GPU | 32 | Implemented |
| Hexagonal Tiles | `ec.stylize.cchextile` | 5 | GPU | 32 | Implemented |
| Kaleidoscope | `ec.stylize.cckaleida` | 4 | GPU | 32 | Implemented |
| Mosaic | `ec.stylize.mosaic` | 3 | GPU | 32 | Implemented |
| Motion Tile | `ec.stylize.motiontile` | 8 | GPU | 32 | Implemented |
| Palette Map | `ec.stylize.ccmrsmoothie` | 7 | GPU | 32 | Implemented |
| Plastic Shading | `ec.stylize.ccplastic` | 18 | GPU | 32 | Implemented |
| Posterize | `ec.stylize.posterize` | 1 | GPU | 32 | Implemented |
| RGB Threshold | `ec.stylize.ccthresholdrgb` | 7 | GPU | 32 | Implemented |
| Roughen Edges | `ec.stylize.roughenedges` | 13 | GPU | 32 | Implemented |
| Scatter | `ec.stylize.scatter` | 3 | GPU | 32 | Implemented |
| Strobe Light | `ec.stylize.strobe` | 7 | GPU | 32 | Implemented |
| Texturize | `ec.stylize.texturize` | 4 | GPU | 32 | Implemented |
| Threshold | `ec.stylize.threshold` | 1 | GPU | 32 | Implemented |
| Vignette | `ec.stylize.ccvignette` | 4 | GPU | 32 | Implemented |
## Text
@@ -379,11 +379,11 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| CC Force Motion Blur | `ec.time.ccforcemotionblur` | 4 | GPU | 32 | Implemented |
| CC Wide Time | `ec.time.ccwidetime` | 3 | GPU | 32 | Implemented |
| Echo | `ec.time.echo` | 5 | GPU | 32 | Implemented |
| Pixel Motion Blur | `ec.time.pixelmotionblur` | 4 | GPU | 32 | Implemented |
| Posterize Time | `ec.time.posterizetime` | 1 | GPU | 32 | Implemented |
| Temporal Blend | `ec.time.ccwidetime` | 3 | GPU | 32 | Implemented |
| Temporal Motion Blur | `ec.time.ccforcemotionblur` | 4 | GPU | 32 | Implemented |
| Time Difference | `ec.time.timedifference` | 5 | GPU | 32 | Implemented |
| Time Displacement | `ec.time.timedisplacement` | 4 | GPU | 32 | Implemented |
| Timewarp | `ec.time.timewarp` | 28 | GPU | 32 | Implemented |
@@ -393,29 +393,28 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| Block Dissolve | `ec.transition.blockdissolve` | 5 | GPU | 32 | Implemented |
| CC Glass Wipe | `ec.transition.ccglasswipe` | 5 | GPU | 32 | Implemented |
| CC Grid Wipe | `ec.transition.ccgridwipe` | 7 | GPU | 32 | Implemented |
| CC Image Wipe | `ec.transition.ccimagewipe` | 7 | GPU | 32 | Implemented |
| CC Jaws | `ec.transition.ccjaws` | 6 | GPU | 32 | Implemented |
| CC Light Wipe | `ec.transition.cclightwipe` | 8 | GPU | 32 | Implemented |
| CC Line Sweep | `ec.transition.cclinesweep` | 5 | GPU | 32 | Implemented |
| CC Radial ScaleWipe | `ec.transition.ccradialscalewipe` | 3 | GPU | 32 | Implemented |
| CC Scale Wipe | `ec.transition.ccscalewipe` | 3 | GPU | 32 | Implemented |
| CC Twister | `ec.transition.cctwister` | 5 | GPU | 32 | Implemented |
| CC WarpoMatic | `ec.transition.ccwarpomatic` | 8 | GPU | 32 | Implemented |
| Card Wipe | `ec.transition.cardwipe` | 44 | GPU | 32 | Implemented |
| Glass Wipe | `ec.transition.ccglasswipe` | 5 | GPU | 32 | Implemented |
| Gradient Wipe | `ec.transition.gradientwipe` | 5 | GPU | 32 | Implemented |
| Grid Wipe | `ec.transition.ccgridwipe` | 7 | GPU | 32 | Implemented |
| Iris Wipe | `ec.transition.iriswipe` | 7 | GPU | 32 | Implemented |
| Light Wipe | `ec.transition.cclightwipe` | 8 | GPU | 32 | Implemented |
| Line Sweep | `ec.transition.cclinesweep` | 5 | GPU | 32 | Implemented |
| Linear Wipe | `ec.transition.linearwipe` | 3 | GPU | 32 | Implemented |
| Luminance Image Wipe | `ec.transition.ccimagewipe` | 7 | GPU | 32 | Implemented |
| Radial Scale Wipe | `ec.transition.ccradialscalewipe` | 3 | GPU | 32 | Implemented |
| Radial Wipe | `ec.transition.radialwipe` | 5 | GPU | 32 | Implemented |
| Scale Wipe | `ec.transition.ccscalewipe` | 3 | GPU | 32 | Implemented |
| Serrated Wipe | `ec.transition.ccjaws` | 6 | GPU | 32 | Implemented |
| Twist Wipe | `ec.transition.cctwister` | 5 | GPU | 32 | Implemented |
| Venetian Blinds | `ec.transition.venetian` | 4 | GPU | 32 | Implemented |
| Warp Dissolve | `ec.transition.ccwarpomatic` | 8 | GPU | 32 | Implemented |
## Utility
| Effect | Id | Params | GPU | 32 | Status |
|---|---|---:|:-:|:-:|---|
| Apply Color LUT | `ec.utility.applylut` | 1 | GPU | 32 | Implemented |
| CC Overbrights | `ec.utility.ccoverbrights` | 2 | GPU | 32 | Implemented |
| Cineon Converter | `ec.utility.cineon` | 7 | GPU | 32 | Implemented |
| Color Profile Converter | `ec.utility.colorprofileconverter` | 7 | GPU | 32 | Implemented |
| Face Measurements | `ec.utility.facemeasurements` | 14 | | 32 | Implemented |
@@ -423,4 +422,5 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
| Grow Bounds | `ec.utility.growbounds` | 1 | GPU | 32 | Implemented |
| HDR Compander | `ec.utility.hdrcompander` | 3 | GPU | 32 | Implemented |
| HDR Highlight Compression | `ec.utility.hdrcompression` | 1 | GPU | 32 | Implemented |
| Out-of-Range Display | `ec.utility.ccoverbrights` | 2 | GPU | 32 | Implemented |
+108
View File
@@ -0,0 +1,108 @@
# Descriptive feature names
Related to #1365. This is a naming cleanup, not a trademark clearance or a product rename.
## Naming policy
Use short, descriptive labels for EffectCraft implementations. Do not reuse a vendor prefix or
coined feature name as our branding. Qualify similar effects by what distinguishes them; each
English display name remains unique across the registry.
- Renderer: **GPU Acceleration** / **Software Rendering**.
- Panel: **Video Scopes**.
- The table below covers the 69 former CC effects plus color grading, the shape matte and keying.
## Compatibility contract
Only presentation names change. Effect IDs, command IDs, parameter IDs, enum values, panel IDs,
serialized types and AEP import/export match names stay unchanged. Old effect display names
remain case-insensitive lookup and search aliases. Existing project instance names, custom names,
expressions, animation and values are not rewritten. The UI displays a current label for an exact
legacy default name, optionally followed by its numeric instance suffix; all other names stay
verbatim. A user-entered name identical to a legacy default cannot be distinguished from it, but
its saved value is still retained.
External format specifications, comparison documents, attribution records and compatibility
fixtures may still name the external product or effect they actually describe.
## Display mapping
| Stable ID | Previous display name | Current display name |
|---|---|---|
| `ec.sim.ccballaction` | CC Ball Action | Ball Grid |
| `ec.distort.ccbendit` | CC Bend It | Two-Point Bend |
| `ec.distort.ccbender` | CC Bender | Flexible Bend |
| `ec.distort.ccblobbylize` | CC Blobbylize | Organic Displacement |
| `ec.stylize.ccblockload` | CC Block Load | Block Reveal |
| `ec.sim.ccbubbles` | CC Bubbles | Bubbles |
| `ec.stylize.ccburnfilm` | CC Burn Film | Film Burn |
| `ec.color.cccolorneutralizer` | CC Color Neutralizer | Color Neutralizer |
| `ec.color.cccoloroffset` | CC Color Offset | Channel Offset |
| `ec.channel.cccomposite` | CC Composite | Source Composite |
| `ec.blur.cccross` | CC Cross Blur | Cross Blur |
| `ec.perspective.cccylinder` | CC Cylinder | Cylinder Wrap |
| `ec.sim.ccdrizzle` | CC Drizzle | Water Ripples |
| `ec.perspective.ccenvironment` | CC Environment | Environment Map |
| `ec.distort.ccflomotion` | CC Flo Motion | Dual Lens Warp |
| `ec.time.ccforcemotionblur` | CC Force Motion Blur | Temporal Motion Blur |
| `ec.stylize.ccglass` | CC Glass | Glass Relief |
| `ec.transition.ccglasswipe` | CC Glass Wipe | Glass Wipe |
| `ec.generate.ccgluegun` | CC Glue Gun | Paint Beads |
| `ec.transition.ccgridwipe` | CC Grid Wipe | Grid Wipe |
| `ec.distort.ccgriddler` | CC Griddler | Tile Grid |
| `ec.sim.cchair` | CC Hair | Surface Fibers |
| `ec.stylize.cchextile` | CC HexTile | Hexagonal Tiles |
| `ec.transition.ccimagewipe` | CC Image Wipe | Luminance Image Wipe |
| `ec.transition.ccjaws` | CC Jaws | Serrated Wipe |
| `ec.stylize.cckaleida` | CC Kaleida | Kaleidoscope |
| `ec.color.cckernel` | CC Kernel | Convolution Kernel |
| `ec.distort.cclens` | CC Lens | Lens Distortion |
| `ec.generate.cclightburst` | CC Light Burst 2.5 | Radial Light Burst |
| `ec.generate.cclightrays` | CC Light Rays | Light Rays |
| `ec.generate.cclightsweep` | CC Light Sweep | Light Sweep |
| `ec.transition.cclightwipe` | CC Light Wipe | Light Wipe |
| `ec.transition.cclinesweep` | CC Line Sweep | Line Sweep |
| `ec.sim.ccmrmercury` | CC Mr. Mercury | Liquid Particles |
| `ec.stylize.ccmrsmoothie` | CC Mr. Smoothie | Palette Map |
| `ec.utility.ccoverbrights` | CC Overbrights | Out-of-Range Display |
| `ec.distort.ccpageturn` | CC Page Turn | Page Curl |
| `ec.sim.ccparticlesystems2` | CC Particle Systems II | Particle Emitter 2D |
| `ec.sim.ccparticleworld` | CC Particle World | Particle Emitter 3D |
| `ec.sim.ccpixelpolly` | CC Pixel Polly | Pixel Shatter |
| `ec.stylize.ccplastic` | CC Plastic | Plastic Shading |
| `ec.distort.ccpowerpin` | CC Power Pin | Perspective Pin |
| `ec.blur.ccradial` | CC Radial Blur | Variable Radial Blur |
| `ec.blur.ccradialfast` | CC Radial Fast Blur | Fast Radial Blur |
| `ec.transition.ccradialscalewipe` | CC Radial ScaleWipe | Radial Scale Wipe |
| `ec.sim.ccrainfall` | CC Rainfall | Rainfall |
| `ec.stylize.ccrepetile` | CC RepeTile | Edge Tile Repeat |
| `ec.distort.ccripplepulse` | CC Ripple Pulse | Pulsed Ripple |
| `ec.transition.ccscalewipe` | CC Scale Wipe | Scale Wipe |
| `ec.sim.ccscatterize` | CC Scatterize | Pixel Scatter |
| `ec.key.ccsimplewireremoval` | CC Simple Wire Removal | Line Removal |
| `ec.distort.ccslant` | CC Slant | Slant |
| `ec.distort.ccsmear` | CC Smear | Directional Smear |
| `ec.sim.ccsnowfall` | CC Snowfall | Snowfall |
| `ec.perspective.ccsphere` | CC Sphere | Sphere Wrap |
| `ec.distort.ccsplit` | CC Split | Split Warp |
| `ec.distort.ccsplit2` | CC Split 2 | Dual Split Warp |
| `ec.perspective.ccspotlight` | CC Spotlight | Surface Spotlight |
| `ec.sim.ccstarburst` | CC Star Burst | Starfield |
| `ec.generate.ccthreads` | CC Threads | Woven Threads |
| `ec.stylize.ccthreshold` | CC Threshold | Channel Threshold |
| `ec.stylize.ccthresholdrgb` | CC Threshold RGB | RGB Threshold |
| `ec.distort.cctiler` | CC Tiler | Scaled Tiles |
| `ec.color.cctoner` | CC Toner | Multi-Tone Tint |
| `ec.transition.cctwister` | CC Twister | Twist Wipe |
| `ec.blur.ccvector` | CC Vector Blur | Vector Blur |
| `ec.stylize.ccvignette` | CC Vignette | Vignette |
| `ec.transition.ccwarpomatic` | CC WarpoMatic | Warp Dissolve |
| `ec.time.ccwidetime` | CC Wide Time | Temporal Blend |
| `ec.color.lumetri` | Lumetri Color | Color Grading |
| `ec.obsolete.mochashape` | Mocha shape | Tracked Shape Matte |
| `ec.keying.keylight` | Key Light | Screen Color Key |
`Roto Brush & Refine Edge` and `Warp Stabilizer` keep their current names; renaming them is
deferred.
No effect algorithms or formats are changed.
+1 -1
View File
@@ -174,7 +174,7 @@ the same futures with `passes::block_on`; they never wait there).
- **Render Queue**: `effectcraft_export::export_async` renders each frame in passes (frames
with deferred readbacks render one by one instead of in parallel batches) and encodes as
before (`Exporter::export_async`). As on the desktop, a job renders every frame on the
project's renderer (the worker's GPU with Mercury GPU Acceleration), not on whichever
project's renderer (the worker's GPU with GPU Acceleration), not on whichever
compositor measured faster, so runs don't differ by timing.
- **Analyses** (Warp Stabilizer, 3D Camera Tracker, Track Motion, mask and face tracking, Roto
Brush freeze and propagation): their work functions are `async`; started with `wait` inside