diff --git a/crates/engine/src/commands/time.rs b/crates/engine/src/commands/time.rs index d06278d02..1bc4638d9 100644 --- a/crates/engine/src/commands/time.rs +++ b/crates/engine/src/commands/time.rs @@ -64,8 +64,9 @@ pub fn parse_display_time(s: &Session, comp: &Comp, text: &str, current: i64) -> fn set(s: &mut Session, p: &Value) -> Result { let comp = s.active_comp().ok_or(EngineError::NoComp)?; - let t = if let Some(f) = p.get("frame").and_then(Value::as_i64) { - comp.frame_rate.tick_of(f) + // Dialog number fields send floats (`5.0`), so a frame is any JSON number, rounded. + let t = if let Some(f) = f_p(p, "frame") { + comp.frame_rate.tick_of(f.round() as i64) } else if let Some(tc) = str_p(p, "timecode") { let cur = comp.frame_rate.frame_at(s.time()); let f = parse_display_time(s, comp, tc, cur).map_err(|e| super::bad("time.set", e))?; diff --git a/crates/engine/src/tests_timeline.rs b/crates/engine/src/tests_timeline.rs index f276300db..53ebd52cd 100644 --- a/crates/engine/src/tests_timeline.rs +++ b/crates/engine/src/tests_timeline.rs @@ -1066,3 +1066,14 @@ fn add_item_keeps_footage_longer_than_the_comp_at_full_length() { let layer = s.active_comp().unwrap().layer(effectcraft_project::LayerId(l)).unwrap(); assert_eq!(layer.out_point.seconds(), 10.0); } + +/// View > Go to Time's dialog sends its Frame field as a float; `time.set` used to reject it +/// with "need `time`, `frame` or `timecode`". +#[test] +fn go_to_time_accepts_a_float_frame_from_the_dialog() { + let (mut s, _) = setup(); + let r = s.execute("time.set", json!({"frame": 12.0})).unwrap(); + assert_eq!(r["frame"], json!(12)); + let r = s.execute("time.set", json!({"frame": 7})).unwrap(); + assert_eq!(r["frame"], json!(7)); +}