Class: Plushie::Animation::Tween
- Inherits:
-
Object
- Object
- Plushie::Animation::Tween
- Defined in:
- lib/plushie/animation/tween.rb,
sig/plushie/animation.rbs
Overview
SDK-side animation interpolation.
Pure functions operating on structs for manual, host-side animations. The host computes interpolated values on each animation frame tick.
For most use cases, prefer renderer-side descriptors (Transition, Spring, Sequence) which animate with zero wire traffic. Use Tween when you need host-side control over the interpolated value (e.g., driving non-visual state from an animation).
Easing functions
All easing functions take a t value in 0.0..1.0 and return a
curved t value. Available easings:
linear: identityease_in: cubic ease inease_out: cubic ease outease_in_out: cubic ease in-outease_in_quad: quadratic ease inease_out_quad: quadratic ease outease_in_out_quad: quadratic ease in-outspring: spring with overshoot
Animation struct
The Tween tracks a single animated value over time.
Create one with new, start it with start, and advance it on
each frame with advance.
Defined Under Namespace
Classes: State
Constant Summary collapse
- EASINGS =
-- Easing functions ---------------------------------------------------
{ linear: ->(t) { t }, ease_in: ->(t) { t * t * t }, ease_out: ->(t) { inv = 1.0 - t 1.0 - inv * inv * inv }, ease_in_out: ->(t) { if t < 0.5 4.0 * t * t * t else inv = -2.0 * t + 2.0 1.0 - inv * inv * inv / 2.0 end }, ease_in_quad: ->(t) { t * t }, ease_out_quad: ->(t) { 1.0 - (1.0 - t) * (1.0 - t) }, ease_in_out_quad: ->(t) { if t < 0.5 2.0 * t * t else 1.0 - (-2.0 * t + 2.0)**2 / 2.0 end }, spring: ->(t) { if t <= 0.0 0.0 elsif t >= 1.0 1.0 else c4 = 2.0 * Math::PI / 3.0 2.0**(-10.0 * t) * Math.sin((t * 10.0 - 0.75) * c4) + 1.0 end } }.freeze
Instance Attribute Summary collapse
-
#auto_reverse [Boolean] swap from/to on each cycle([Boolean]) ⇒ Object
readonly
Immutable animation state.
-
#repeat [Integer, :forever, nil] remaining repeat count([Integer,: forever, nil]) ⇒ Object
readonly
Immutable animation state.
Class Method Summary collapse
-
.advance(anim, timestamp) ⇒ Array(Numeric, State), Array(Numeric, Symbol)
Advance the animation to the given frame timestamp.
- .ease_in ⇒ Float
- .ease_in_out ⇒ Float
- .ease_in_out_quad ⇒ Float
- .ease_in_quad ⇒ Float
- .ease_out ⇒ Float
- .ease_out_quad ⇒ Float
-
.finished?(anim) ⇒ Boolean
Returns true if the animation has run to completion.
-
.interpolate(from, to, t, easing = :linear) ⇒ Float
Linearly interpolate between
fromandtoat progresst, with an optional easing function applied totfirst. - .linear ⇒ Float
-
.looping(from, to, duration_ms, **opts) ⇒ State
Create a looping tween that repeats forever with auto-reverse.
-
.new(from, to, duration_ms, easing: :linear, repeat: nil, auto_reverse: false) ⇒ State
Create a new animation.
- .spring ⇒ Float
-
.start(anim, timestamp) ⇒ State
Start (or restart) the animation at the given frame timestamp.
-
.value(anim) ⇒ Numeric
Return the current interpolated value.
Instance Attribute Details
#auto_reverse [Boolean] swap from/to on each cycle([Boolean]) ⇒ Object (readonly)
Immutable animation state.
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/plushie/animation/tween.rb', line 45 State = ::Data.define(:from, :to, :duration, :started_at, :easing, :value, :repeat, :auto_reverse) do include Plushie::Model::Extensions def initialize(from:, to:, duration:, started_at: nil, easing: :linear, value: nil, repeat: nil, auto_reverse: false) super(from: from, to: to, duration: duration, started_at: started_at, easing: easing, value: value.nil? ? from : value, repeat: repeat, auto_reverse: auto_reverse) end end |
#repeat [Integer, :forever, nil] remaining repeat count([Integer,: forever, nil]) ⇒ Object (readonly)
Immutable animation state.
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/plushie/animation/tween.rb', line 45 State = ::Data.define(:from, :to, :duration, :started_at, :easing, :value, :repeat, :auto_reverse) do include Plushie::Model::Extensions def initialize(from:, to:, duration:, started_at: nil, easing: :linear, value: nil, repeat: nil, auto_reverse: false) super(from: from, to: to, duration: duration, started_at: started_at, easing: easing, value: value.nil? ? from : value, repeat: repeat, auto_reverse: auto_reverse) end end |
Class Method Details
.advance(anim, timestamp) ⇒ Array(Numeric, State), Array(Numeric, Symbol)
Advance the animation to the given frame timestamp.
Returns [current_value, updated_animation] while the animation is
in progress, or [final_value, :finished] when it completes.
179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/plushie/animation/tween.rb', line 179 def self.advance(anim, ) return [anim.value, anim] if anim.started_at.nil? elapsed = - anim.started_at t = clamp(elapsed.to_f / anim.duration) current = interpolate(anim.from, anim.to, t, anim.easing) if t >= 1.0 handle_cycle_end(anim) else [current, anim.with(value: current)] end end |
.ease_in ⇒ Float
23 |
# File 'sig/plushie/animation.rbs', line 23
def self.ease_in: (Float t) -> Float
|
.ease_in_out ⇒ Float
25 |
# File 'sig/plushie/animation.rbs', line 25
def self.ease_in_out: (Float t) -> Float
|
.ease_in_out_quad ⇒ Float
28 |
# File 'sig/plushie/animation.rbs', line 28
def self.ease_in_out_quad: (Float t) -> Float
|
.ease_in_quad ⇒ Float
26 |
# File 'sig/plushie/animation.rbs', line 26
def self.ease_in_quad: (Float t) -> Float
|
.ease_out ⇒ Float
24 |
# File 'sig/plushie/animation.rbs', line 24
def self.ease_out: (Float t) -> Float
|
.ease_out_quad ⇒ Float
27 |
# File 'sig/plushie/animation.rbs', line 27
def self.ease_out_quad: (Float t) -> Float
|
.finished?(anim) ⇒ Boolean
Returns true if the animation has run to completion.
197 198 199 200 |
# File 'lib/plushie/animation/tween.rb', line 197 def self.finished?(anim) return false if anim.started_at.nil? anim.value == anim.to end |
.interpolate(from, to, t, easing = :linear) ⇒ Float
Linearly interpolate between from and to at progress t,
with an optional easing function applied to t first.
116 117 118 119 120 121 |
# File 'lib/plushie/animation/tween.rb', line 116 def self.interpolate(from, to, t, easing = :linear) easing_fn = resolve_easing(easing) clamped = clamp(t) eased = easing_fn.call(clamped) from + (to - from) * eased end |
.linear ⇒ Float
22 |
# File 'sig/plushie/animation.rbs', line 22
def self.linear: (Float t) -> Float
|
.looping(from, to, duration_ms, **opts) ⇒ State
Create a looping tween that repeats forever with auto-reverse.
Convenience for common back-and-forth animations (pulsing, breathing, oscillating).
158 159 160 |
# File 'lib/plushie/animation/tween.rb', line 158 def self.looping(from, to, duration_ms, **opts) new(from, to, duration_ms, repeat: :forever, auto_reverse: true, **opts) end |
.new(from, to, duration_ms, easing: :linear, repeat: nil, auto_reverse: false) ⇒ State
Create a new animation.
132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/plushie/animation/tween.rb', line 132 def self.new(from, to, duration_ms, easing: :linear, repeat: nil, auto_reverse: false) raise ArgumentError, "duration_ms must be positive" unless duration_ms.is_a?(Integer) && duration_ms > 0 State.new( from: from, to: to, duration: duration_ms, easing: easing, repeat: repeat, auto_reverse: auto_reverse ) end |
.spring ⇒ Float
29 |
# File 'sig/plushie/animation.rbs', line 29
def self.spring: (Float t) -> Float
|
.start(anim, timestamp) ⇒ State
Start (or restart) the animation at the given frame timestamp.
167 168 169 |
# File 'lib/plushie/animation/tween.rb', line 167 def self.start(anim, ) anim.with(started_at: , value: anim.from) end |
.value(anim) ⇒ Numeric
Return the current interpolated value.
205 |
# File 'lib/plushie/animation/tween.rb', line 205 def self.value(anim) = anim.value |