Author Motion Curves

These examples evaluate curves without opening a controller or modifying the desktop. Definitions, timing rules and validation limits live under curves and durations.

Hold, Travel and Settle

use rdi_core::{AnimationCurve, Curve, Keyframe, KeyframeInterp};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let curve = Curve::keyframes(vec![
        Keyframe::new(0.0, 0.0),
        Keyframe::new(0.15, 0.0),
        Keyframe::new(0.85, 1.0),
        Keyframe::new(1.0, 1.0),
    ], KeyframeInterp::SmoothStep)?;
    for progress in [0.0, 0.15, 0.5, 0.85, 1.0] {
        println!("{progress:.2}: {:.3}", curve.eval(progress));
    }
    Ok(())
}

This is useful when labels should remain readable before and after travel. Attach the curve with IconAnimationSpec::new; use with_axes for different X/Y timing. A movement curve does not automatically become an effect envelope.

Bake a Custom Function

use rdi_core::{AnimationCurve, Curve, KeyframeInterp};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let minimum_jerk = Curve::from_curve_fn(
        |time| time.powi(3) * (10.0 - 15.0 * time + 6.0 * time * time),
        128, KeyframeInterp::Linear,
    )?;
    assert!((minimum_jerk.eval(0.5) - 0.5).abs() < 0.001);
    Ok(())
}

For per-icon curves derived from distance or direction, use from_motion_fn with a MotionContext. For consistent travel speed across unequal distances, choose Duration::Distance or Duration::DistanceClamped rather than changing the sampler. The native reference lists their exact fields.

Next: run a batch or use a curve as an effect envelope.