Plushie.Animation.Tween (Plushie v0.6.0)

Copy Markdown View Source

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
end

Easing

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

t()

@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

advance(anim, timestamp)

@spec advance(animation :: t(), timestamp :: integer()) :: t()

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.

finished?(tween)

@spec finished?(animation :: t()) :: boolean()

Returns true if the animation has completed.

new(opts)

@spec new(opts :: keyword()) :: t()

Creates a new timed animation.

Required options

  • from: -- start value
  • to: -- end value
  • duration: -- duration in milliseconds

Optional

  • easing: -- easing atom or {:cubic_bezier, ...}. Default: :ease_in_out
  • delay: -- delay before start in ms. Default: 0
  • repeat: -- repeat count or :forever
  • auto_reverse: -- reverse on each repeat cycle

Example

Tween.new(from: 0.0, to: 1.0, duration: 300, easing: :ease_out)

redirect(anim, opts)

@spec redirect(animation :: t(), opts :: keyword()) :: t()

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 easing
  • duration: -- optionally change duration

running?(tween)

@spec running?(animation :: t()) :: boolean()

Returns true if the animation is actively running (started and not finished).

spring(opts)

@spec spring(opts :: keyword()) :: t()

Creates a spring-mode animation (SDK-side spring solver).

Required options

  • from: -- start value
  • to: -- end value

Optional

  • stiffness: -- spring constant. Default: 100
  • damping: -- friction. Default: 10
  • mass: -- mass. Default: 1.0
  • velocity: -- initial velocity. Default: 0.0

Example

Tween.spring(from: 0.0, to: 1.0, stiffness: 200, damping: 20)

start(anim, timestamp)

@spec start(animation :: t(), timestamp :: integer()) :: t()

Starts the animation at the given timestamp. Resets value to from.

If already started, restarts from the beginning.

start_once(anim, timestamp)

@spec start_once(animation :: t(), timestamp :: integer()) :: t()

Starts the animation only if it hasn't been started yet.

Convenience for the common pattern of starting on the first frame.

value(tween)

@spec value(animation :: t()) :: number() | nil

Returns the current interpolated value.