SDK-side stateful interpolator for model-level animation.
Pure functions operating on structs -- no processes, no state management beyond what lives in your app model. Use this for complex animations that need frame-by-frame control: canvas animations, physics simulations, custom interpolation logic.
For simple property animations (fades, slides, scales), prefer
renderer-side transitions via Plushie.Animation.Transition
which require zero model state and zero wire traffic.
Example
alias Plushie.Animation.Tween
def init(_opts) do
%{anim: Tween.new(from: 0.0, to: 1.0, duration: 300, easing: :ease_out)}
end
def subscribe(_model) do
[Plushie.Subscription.on_animation_frame(:frame)]
end
def update(model, %SystemEvent{type: :animation_frame, data: ts}) do
anim = model.anim |> Tween.start_once(ts) |> Tween.advance(ts)
%{model | anim: anim}
end
def view(model) do
opacity = Tween.value(model.anim)
# use opacity in widget props
endEasing
Uses Plushie.Animation.Easing for the full catalogue of 31
named curves plus cubic bezier. Pass easing as an atom:
Tween.new(from: 0.0, to: 1.0, duration: 300, easing: :ease_out_bounce)Interruption
Change the target mid-animation with redirect/2. The animation
smoothly continues from its current interpolated value:
anim = Tween.redirect(model.anim, to: 0.0, at: timestamp)Spring mode
For physics-based animation on the SDK side:
anim = Tween.spring(from: 0.0, to: 1.0, stiffness: 200, damping: 20)
Summary
Functions
Advances the animation to the given timestamp.
Returns true if the animation has completed.
Creates a new timed animation.
Redirects the animation to a new target, starting from the current interpolated value. Resets the timer.
Returns true if the animation is actively running (started and not finished).
Creates a spring-mode animation (SDK-side spring solver).
Starts the animation at the given timestamp. Resets value to from.
Starts the animation only if it hasn't been started yet.
Returns the current interpolated value.
Types
@type t() :: %Plushie.Animation.Tween{ auto_reverse: boolean() | nil, delay: non_neg_integer() | nil, duration: pos_integer() | nil, easing: Plushie.Animation.Easing.t(), easing_fn: (float() -> float()) | nil, finished: boolean(), from: number(), last_timestamp: integer() | nil, repeat: pos_integer() | :forever | nil, spring_config: map() | nil, started_at: integer() | nil, to: number(), value: number() | nil }
Functions
Advances the animation to the given timestamp.
Always returns an updated %Tween{} struct. Check
finished?/1 to detect completion.
If the animation hasn't been started, returns the struct unchanged.
Returns true if the animation has completed.
Creates a new timed animation.
Required options
from:-- start valueto:-- end valueduration:-- duration in milliseconds
Optional
easing:-- easing atom or{:cubic_bezier, ...}. Default::ease_in_outdelay:-- delay before start in ms. Default: 0repeat:-- repeat count or:foreverauto_reverse:-- reverse on each repeat cycle
Example
Tween.new(from: 0.0, to: 1.0, duration: 300, easing: :ease_out)
Redirects the animation to a new target, starting from the current interpolated value. Resets the timer.
Use this for smooth interruption -- the animation continues from where it is rather than jumping.
Options
to:-- new target value (required)at:-- current timestamp (required)easing:-- optionally change easingduration:-- optionally change duration
Returns true if the animation is actively running (started and not finished).
Creates a spring-mode animation (SDK-side spring solver).
Required options
from:-- start valueto:-- end value
Optional
stiffness:-- spring constant. Default: 100damping:-- friction. Default: 10mass:-- mass. Default: 1.0velocity:-- initial velocity. Default: 0.0
Example
Tween.spring(from: 0.0, to: 1.0, stiffness: 200, damping: 20)
Starts the animation at the given timestamp. Resets value to from.
If already started, restarts from the beginning.
Starts the animation only if it hasn't been started yet.
Convenience for the common pattern of starting on the first frame.
Returns the current interpolated value.