pub struct SpringConfig {
pub stiffness: f32,
pub damping: f32,
pub mass: f32,
}Expand description
The physical parameters of a damped spring that moves a scalar toward a target.
Stiffness pulls the value toward its target, damping removes energy, and mass resists both.
Keep one set of parameters for every step of an animation. stiffness and mass must be
finite and positive; damping must be finite and non-negative. The constructor does not
validate them, so invalid values can produce NaN or meaningless motion.
Create one with spring. Pass it to SpringAnimation::new to animate an element, or
step it yourself with SpringConfig::step.
§Examples
use gpui::spring;
let config = spring(100., 10., 1.);
let (natural_frequency, damping_ratio) = config.canonical();
assert_eq!(natural_frequency, 10.0);
assert_eq!(damping_ratio, 0.5);See the animation guide for how spring state is retained between frames.
Fields§
§stiffness: f32The spring constant, written $k$. A larger value pulls the spring toward its target more strongly.
damping: f32The viscous damping coefficient, written $c$. With zero damping, a spring set in motion keeps oscillating instead of losing energy.
mass: f32The moving mass, written $m$. A larger mass responds more slowly.
Implementations§
Source§impl SpringConfig
impl SpringConfig
Sourcepub const fn new(stiffness: f32, damping: f32, mass: f32) -> Self
pub const fn new(stiffness: f32, damping: f32, mass: f32) -> Self
Creates a spring from its stiffness, damping and mass. See spring.
Sourcepub fn canonical(&self) -> (f32, f32)
pub fn canonical(&self) -> (f32, f32)
Returns the natural angular frequency $\omega_0$ and the damping ratio $\zeta$.
A ratio below one describes an underdamped spring, which oscillates about its target. One is critical damping; above one is overdamping. For a displaced spring released from rest, critical damping gives the fastest approach to a fixed target without oscillation. A spring that already has velocity can cross the target even with critical damping.
Sourcepub fn step(
&self,
state: SpringState,
target: f32,
delta_time: f32,
) -> SpringState
pub fn step( &self, state: SpringState, target: f32, delta_time: f32, ) -> SpringState
Advances the spring by delta_time seconds toward a fixed target.
The solver assumes target stays fixed during delta_time and computes motion from
elapsed time rather than a fixed frame duration. Splitting an interval into smaller steps
gives the same motion apart from numerical error. Velocity carries over, so retargeting
an interrupted spring does not restart it from rest.
§Examples
use gpui::{SpringState, spring};
let config = spring(320., 24., 1.);
let start = SpringState::default();
let one_step = config.step(start, 1.0, 1.0 / 60.0);
let two_steps = config.step(config.step(start, 1.0, 1.0 / 120.0), 1.0, 1.0 / 120.0);
assert!((one_step.position - two_steps.position).abs() < 1e-3);
assert!(one_step.position > 0.0 && one_step.position < 1.0);Sourcepub fn step_ramp(
&self,
state: SpringState,
target: f32,
target_velocity: f32,
delta_time: f32,
) -> SpringState
pub fn step_ramp( &self, state: SpringState, target: f32, target_velocity: f32, delta_time: f32, ) -> SpringState
Advances the spring by delta_time seconds toward a target that moves at target_velocity.
Use this for a target that moves steadily, such as a dragged pointer. With positive
damping, the transient motion dies away and the spring approaches a constant lag behind
the moving target. Using step would instead treat the target as fixed
within each frame, introducing a lag that depends on frame duration.
§Examples
use gpui::{SpringState, spring};
// A natural frequency of 10 and a damping ratio of 0.8.
let config = spring(100., 16., 1.);
let state = SpringState { position: -0.48, velocity: 3.0 };
let next = config.step_ramp(state, 0.0, 3.0, 0.25);
assert!((next.position - 0.27).abs() < 1e-4);
assert!((next.velocity - 3.0).abs() < 1e-4);Sourcepub fn propagator(&self, delta_time: f32) -> [[f32; 2]; 2]
pub fn propagator(&self, delta_time: f32) -> [[f32; 2]; 2]
Returns the exact state-transition matrix for a fixed target over delta_time seconds.
The matrix maps the displacement from the target and the velocity to their values after
delta_time, which is what step does. Build it once when many springs share
this config and frame delta. Rebuild it when the delta changes.
§Examples
use gpui::spring;
// With no time elapsed, nothing changes.
let matrix = spring(100., 10., 1.).propagator(0.0);
assert_eq!(matrix, [[1.0, 0.0], [0.0, 1.0]]);Sourcepub fn is_settled(&self, state: SpringState, target: f32, epsilon: f32) -> bool
pub fn is_settled(&self, state: SpringState, target: f32, epsilon: f32) -> bool
Returns whether the spring is within epsilon of target, in position and velocity.
The position must be within epsilon of target. The velocity must be at most
epsilon * natural_frequency, which puts it on the same scale as position. A negative or
non-finite epsilon never settles.
§Examples
use gpui::{SpringState, spring};
let config = spring(100., 10., 1.);
let moving = SpringState { position: 1.0, velocity: 1.0 };
let nearly_still = SpringState { position: 1.005, velocity: 0.05 };
assert!(!config.is_settled(moving, 1.0, 0.01));
assert!(config.is_settled(nearly_still, 1.0, 0.01));Sourcepub fn settle_time(
&self,
state: SpringState,
target: f32,
epsilon: f32,
) -> Duration
pub fn settle_time( &self, state: SpringState, target: f32, epsilon: f32, ) -> Duration
Returns a time after which the spring stays settled, measured from state in seconds.
The result is conservative. Stepping the spring to this time, or any later time, leaves it
settled by is_settled with the same target and epsilon. An
undamped spring that isn’t already at rest never settles, so this returns
Duration::MAX. So does a non-positive or non-finite epsilon, unless the spring is
already at rest.
§Examples
use std::time::Duration;
use gpui::{SpringState, spring};
let config = spring(100., 10., 1.);
let start = SpringState::default();
let time = config.settle_time(start, 1.0, 0.001);
assert!(time > Duration::ZERO && time < Duration::MAX);
let later = config.step(start, 1.0, time.as_secs_f32() + 0.1);
assert!(config.is_settled(later, 1.0, 0.001));
assert_eq!(spring(100., 0., 1.).settle_time(start, 1.0, 0.001), Duration::MAX);Trait Implementations§
Source§impl Clone for SpringConfig
impl Clone for SpringConfig
impl Copy for SpringConfig
Source§impl Debug for SpringConfig
impl Debug for SpringConfig
Source§impl From<SpringConfig> for Motion<SpringDescription>
impl From<SpringConfig> for Motion<SpringDescription>
Source§fn from(config: SpringConfig) -> Self
fn from(config: SpringConfig) -> Self
Source§impl From<SpringConfig> for AnyMotion
impl From<SpringConfig> for AnyMotion
Source§fn from(config: SpringConfig) -> Self
fn from(config: SpringConfig) -> Self
Source§impl PartialEq for SpringConfig
impl PartialEq for SpringConfig
impl StructuralPartialEq for SpringConfig
Auto Trait Implementations§
impl Freeze for SpringConfig
impl RefUnwindSafe for SpringConfig
impl Send for SpringConfig
impl Sync for SpringConfig
impl Unpin for SpringConfig
impl UnsafeUnpin for SpringConfig
impl UnwindSafe for SpringConfig
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
replaced by palette::chromatic_adaptation::AdaptIntoUnclamped
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
replaced by palette::chromatic_adaptation::AdaptIntoUnclamped
Source§impl<T, C> AdaptIntoUnclamped<T> for Cwhere
T: AdaptFromUnclamped<C>,
impl<T, C> AdaptIntoUnclamped<T> for Cwhere
T: AdaptFromUnclamped<C>,
Source§type Scalar = <T as AdaptFromUnclamped<C>>::Scalar
type Scalar = <T as AdaptFromUnclamped<C>>::Scalar
Source§fn adapt_into_unclamped_with<M>(self) -> Twhere
M: LmsToXyz<<C as AdaptIntoUnclamped<T>>::Scalar> + XyzToLms<<C as AdaptIntoUnclamped<T>>::Scalar>,
fn adapt_into_unclamped_with<M>(self) -> Twhere
M: LmsToXyz<<C as AdaptIntoUnclamped<T>>::Scalar> + XyzToLms<<C as AdaptIntoUnclamped<T>>::Scalar>,
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T, C> ComponentsInto<C> for T
impl<T, C> ComponentsInto<C> for T
Source§fn components_into(self) -> C
fn components_into(self) -> C
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more