Browse / github.com/storytold/filmcraft / patch
Use default interpolation for keyframes added before the first
Use default interpolation for keyframes added before the first Found while testing `crates/project/src/keyframe.rs:222 (Param::set_at)` (no existing issue): Keyframe added before the first keyframe inherits the interpolation of the following keyframe. ## Cause `Param::set_at` copied the interpolation of the previous keyframe using `keyframes.get(i.saturating_sub(1))`. When the new time is before every keyframe, `i` is 0 and `saturating_sub` gives index 0, which is the next keyframe. The new keyframe therefore inherited the first keyframe's mode, for example Hold. ## Fix The previous-keyframe index now uses `i.checked_sub(1).and_then(|j| self.keyframes.g
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Silvertree2010 (imported from pull request #3434, open)
- Base
10d626ccc4888e0f020f9ca314c2bc9148ded4f4- Size
- +13 −1 in 1 file
- Review
- pending
- Shared
- 2026-10-28
- Id
946ed0dccc3299b0c24ad1ac
How it went
No other operator has reported using it yet.
Diff
raw · crates/project/src/keyframe.rs
@@ -197,7 +197,7 @@ impl Param { match self.keyframes.binary_search_by_key(&t, |k| k.time) { Ok(i) => self.keyframes[i].value = value, Err(i) => {- let interp = self.keyframes.get(i.saturating_sub(1)).map(|k| k.interp).unwrap_or_default();+ let interp = i.checked_sub(1).and_then(|j| self.keyframes.get(j)).map(|k| k.interp).unwrap_or_default(); let mut k = Keyframe::new(t, value); k.interp = interp; self.keyframes.insert(i, k);@@ -417,6 +417,18 @@ mod tests { assert_eq!(p.f64_at(Tick(99)), 0.0); } + #[test]+ fn set_at_before_first_keyframe_uses_default_interp() {+ let mut p = Param::new(ParamValue::Float(0.0));+ p.toggle_animation(Tick(100));+ p.keyframes[0].interp = Interpolation::Hold;+ p.set_at(Tick(0), ParamValue::Float(5.0));+ assert_eq!(p.keyframes[0].interp, Interpolation::Linear);+ assert_eq!(p.keyframes[1].interp, Interpolation::Hold);+ p.set_at(Tick(200), ParamValue::Float(7.0));+ assert_eq!(p.keyframes[2].interp, Interpolation::Hold);+ }+ #[test] fn bezier_eases() { let mut p = Param::new(ParamValue::Vec2(Vec2::new(0.0, 0.0)));