#3087: keep an effect without a counterpart as a placeholder

Third-party plug-ins and pseudo effects (expression controls) were dropped on
import, so expressions reading them broke. Such an effect now arrives as an
effect group whose effect id is its After Effects match name: it renders
nothing, like a missing plug-in, and is listed by Find Missing Effects. It
holds the effect's parameters flat, named as in After Effects, with their
values, keys and expressions in the units After Effects' expressions read.
It is still reported (once per match name, "kept without rendering") and
counted in imported.placeholderEffects. The parameters and popup items kept
are bounded per import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
arnav-hiwarkarandClaude Opus 5.5 committed 2026-11-11 16:46:06 +05:30
1 parent 6aca5e473c
commit b60f231fe9
8 files changed
+461 -42

No files matched your search

+18
View File
@@ -1376,6 +1376,24 @@ fn checkbox_and_dropdown_results() {
assert_close!(f.ev(f.b, ROT, "effect('Dropdown Menu Control')('Menu') * 10", 0.0).unwrap().as_f64(), 10.0);
}
/// An effect EffectCraft does not have (an imported After Effects placeholder, #3087) is read by
/// name like any other: its parameters by their names, a popup 1-based.
#[test]
fn an_unknown_effects_parameters_are_read_by_name() {
let mut f = fx();
let g = group_push(&mut f.p, |ids| {
let mut g = ids.group("Pseudo/0.25", "Settings");
g.kind = effectcraft_project::GroupKind::Effect { effect: "Pseudo/0.25".into() };
g.children.push(ids.prop("param1", "Speed", Value::Scalar(3.0)).into());
g.children.push(ids.prop("param2", "Mode", Value::Enum(1)).into());
g
});
f.layer_mut(f.b).props.sub_mut("effects").unwrap().children.push(g.into());
assert_close!(f.ev(f.b, ROT, "effect('Settings')('Speed') * 2", 0.0).unwrap().as_f64(), 6.0);
assert_close!(f.ev(f.b, ROT, "effect('Settings')('Mode') * 10", 0.0).unwrap().as_f64(), 20.0);
assert_close!(f.ev(f.b, ROT, "effect('Settings')(1)", 0.0).unwrap().as_f64(), 3.0);
}
#[test]
fn syntax_error_reports_line() {
let f = fx();