From e94869e0fe0932392d2c65cdbe3a78681e74b6ae Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Sat, 24 Oct 2026 17:53:43 +0200 Subject: [PATCH] Lottie: import a layer's time stretch below 1 % as 100 %, with a warning --- crates/lottie/src/import.rs | 9 ++++++++- crates/lottie/src/tests.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/lottie/src/import.rs b/crates/lottie/src/import.rs index b2eeece49..7388a6742 100644 --- a/crates/lottie/src/import.rs +++ b/crates/lottie/src/import.rs @@ -399,7 +399,14 @@ fn build_layers(cx: &mut Ctx, project: &mut Project, comp: &mut Comp, layers: &[ l.in_point = tb.tick(ip); l.out_point = tb.tick(op.max(ip)); l.start_time = tb.tick(f(j, "st").unwrap_or(0.0)); - l.stretch = f(j, "sr").unwrap_or(1.0) * 100.0; + // Below 1 % (or 0) the layer time divides by ~0, and layer.timeStretch refuses it too. + let sr = f(j, "sr").unwrap_or(1.0); + l.stretch = if sr.is_finite() && sr.abs() >= 0.01 { + sr * 100.0 + } else { + cx.im.warn(format!("{name}: a time stretch of {} % is not supported (100 % used)", sr * 100.0)); + 100.0 + }; if j.get("ddd").and_then(Json::as_u64) == Some(1) { l.switches.three_d = true; } diff --git a/crates/lottie/src/tests.rs b/crates/lottie/src/tests.rs index e819c0239..ace39f0ef 100644 --- a/crates/lottie/src/tests.rs +++ b/crates/lottie/src/tests.rs @@ -484,6 +484,18 @@ fn layers_parenting_timing_mattes_masks_and_blend_modes() { compare_renders(&p, cid, &q, nc, 2.0 / 255.0); } +#[test] +fn zero_time_stretch_is_not_imported() { + let doc = json!({"w": 20, "h": 20, "fr": 30, "ip": 0, "op": 30, "assets": [], + "layers": [{"ty": 1, "ind": 1, "sc": "#ff0000", "sw": 20, "sh": 20, "sr": 0, "ip": 0, "op": 30, "st": 0, "ks": {}}]}); + let mut q = Project::default(); + let imp = import(&mut q, doc.to_string().as_bytes(), "Imported", "", &mut |_| None).unwrap(); + let l = &q.comp(imp.comp).unwrap().layers[0]; + // layer.timeStretch refuses anything below 1 %, and keyframe commands refuse a layer with 0 %. + assert_eq!(l.stretch, 100.0); + assert!(imp.warnings.iter().any(|w| w.contains("time stretch")), "{:?}", imp.warnings); +} + #[test] fn precomp_with_time_remap() { let (mut p, cid) = setup();