From b74b89feb5c8f757d44014dea806da647ec99614 Mon Sep 17 00:00:00 2001 From: tylerjenningsw Date: Sun, 25 Oct 2026 20:46:19 -0400 Subject: [PATCH] Animation presets: effect keyframes in presets saved by earlier versions start at the playhead too (#1971) --- crates/engine/src/cmd/animation.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/animation.rs b/crates/engine/src/cmd/animation.rs index aa5b2dec3..70401fa40 100644 --- a/crates/engine/src/cmd/animation.rs +++ b/crates/engine/src/cmd/animation.rs @@ -18,6 +18,8 @@ use crate::{EngineError, KeyRef, Result, Session, cmd}; pub const PRESET_TAG: &str = "effectcraftAnimationPreset"; /// The preset format version that `anim.savePreset` writes. pub const PRESET_VERSION: u64 = 2; +/// The first preset version that stores effect keys relative to the earliest key (#1971). +const RELATIVE_EFFECT_KEYS: u64 = 2; fn has_selected_props(s: &Session) -> std::result::Result<(), String> { has_comp(s)?; @@ -130,8 +132,16 @@ fn apply_preset(s: &mut Session, p: &Value) -> Result { s.save_prefs(); s.prefs_revision += 1; } - let effects: Vec = + let mut effects: Vec = doc["effects"].as_array().map(|a| a.iter().filter_map(|v| serde_json::from_value(v.clone()).ok()).collect()).unwrap_or_default(); + // Older presets stored effect keys at the source layer's times. + if doc[PRESET_TAG].as_u64().unwrap_or(1) < RELATIVE_EFFECT_KEYS + && let Some(first) = earliest_key(&effects) + { + for g in &mut effects { + retime_effect(g, 1.0, "anim.applyPreset", |t| Ok(Tick(t.0.checked_sub(first.0).ok_or_else(|| effect_time_error("anim.applyPreset"))?)))?; + } + } let props: Vec<(String, Property)> = doc["properties"] .as_array() .map(|a| {