diff --git a/LemonUI/TinyTween/FloatTween.cs b/LemonUI/TinyTween/FloatTween.cs
new file mode 100644
index 0000000..4d0d0ce
--- /dev/null
+++ b/LemonUI/TinyTween/FloatTween.cs
@@ -0,0 +1,23 @@
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Represents a tween for floating-point values.
+ ///
+ public class FloatTween : Tween
+ {
+ private static readonly LerpFunc LerpFunc = LerpFloat;
+
+ private static float LerpFloat(float start, float end, float progress)
+ {
+ return start + ((end - start) * progress);
+ }
+
+ ///
+ /// Initializes a new instance of the FloatTween class.
+ ///
+ public FloatTween()
+ : base(LerpFunc)
+ {
+ }
+ }
+}
diff --git a/LemonUI/TinyTween/ITween.cs b/LemonUI/TinyTween/ITween.cs
new file mode 100644
index 0000000..f81df23
--- /dev/null
+++ b/LemonUI/TinyTween/ITween.cs
@@ -0,0 +1,52 @@
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Represents an interface for a tween with different stop behaviors.
+ ///
+ public interface ITween
+ {
+ ///
+ /// Gets the current state of the tween.
+ ///
+ TweenState State { get; }
+ ///
+ /// Pauses the tween.
+ ///
+ void Pause();
+ ///
+ /// Resumes the paused tween.
+ ///
+ void Resume();
+ ///
+ /// Stops the tween with the specified stop behavior.
+ ///
+ /// The stop behavior of the tween.
+ void Stop(StopBehavior stopBehavior);
+ ///
+ /// Updates the tween with the elapsed time.
+ ///
+ /// The elapsed time since the last update.
+ void Update(float elapsedTime);
+ }
+
+ ///
+ /// Represents an interface for a typed tween with different stop behaviors.
+ ///
+ /// The type of value being tweened.
+ public interface ITween : ITween
+ where T : struct
+ {
+ ///
+ /// Gets the current value of the tween.
+ ///
+ T CurrentValue { get; }
+ ///
+ /// Starts the tween with the specified start and end values, duration, and scale function.
+ ///
+ /// The starting value of the tween.
+ /// The ending value of the tween.
+ /// The duration of the tween.
+ /// The scale function to be used for the tween.
+ void Start(T start, T end, float duration, ScaleFunc scaleFunc);
+ }
+}
diff --git a/LemonUI/TinyTween/LerpFunc.cs b/LemonUI/TinyTween/LerpFunc.cs
new file mode 100644
index 0000000..2dced37
--- /dev/null
+++ b/LemonUI/TinyTween/LerpFunc.cs
@@ -0,0 +1,12 @@
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Represents a delegate for a lerp function used in a tween.
+ ///
+ /// The type of value being lerped.
+ /// The starting value of the lerp.
+ /// The ending value of the lerp.
+ /// The progress of the lerp.
+ /// The lerped value based on the progress.
+ public delegate T LerpFunc(T start, T end, float progress);
+}
diff --git a/LemonUI/TinyTween/ScaleFunc.cs b/LemonUI/TinyTween/ScaleFunc.cs
new file mode 100644
index 0000000..7c2d89f
--- /dev/null
+++ b/LemonUI/TinyTween/ScaleFunc.cs
@@ -0,0 +1,9 @@
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Represents a delegate for a scale function used in a tween.
+ ///
+ /// The progress of the tween.
+ /// The scaled value based on the progress.
+ public delegate float ScaleFunc(float progress);
+}
diff --git a/LemonUI/TinyTween/ScaleFuncs.cs b/LemonUI/TinyTween/ScaleFuncs.cs
new file mode 100644
index 0000000..6345313
--- /dev/null
+++ b/LemonUI/TinyTween/ScaleFuncs.cs
@@ -0,0 +1,279 @@
+using System;
+
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Provides a collection of scale functions for use in tweens.
+ ///
+ public static class ScaleFuncs
+ {
+ #region Fields
+ ///
+ /// Represents a linear scale function.
+ ///
+ public static readonly ScaleFunc Linear = LinearImpl;
+ ///
+ /// Represents a quadratic ease-in scale function.
+ ///
+ public static readonly ScaleFunc QuadraticEaseIn = QuadraticEaseInImpl;
+ ///
+ /// Represents a quadratic ease-out scale function.
+ ///
+ public static readonly ScaleFunc QuadraticEaseOut = QuadraticEaseOutImpl;
+ ///
+ /// Represents a quadratic ease-in-out scale function.
+ ///
+ public static readonly ScaleFunc QuadraticEaseInOut = QuadraticEaseInOutImpl;
+ ///
+ /// Represents a cubic ease-in scale function.
+ ///
+ public static readonly ScaleFunc CubicEaseIn = CubicEaseInImpl;
+ ///
+ /// Represents a cubic ease-out scale function.
+ ///
+ public static readonly ScaleFunc CubicEaseOut = CubicEaseOutImpl;
+ ///
+ /// Represents a cubic ease-in-out scale function.
+ ///
+ public static readonly ScaleFunc CubicEaseInOut = CubicEaseInOutImpl;
+ ///
+ /// Represents a quartic ease-in scale function.
+ ///
+ public static readonly ScaleFunc QuarticEaseIn = QuarticEaseInImpl;
+ ///
+ /// Represents a quartic ease-out scale function.
+ ///
+ public static readonly ScaleFunc QuarticEaseOut = QuarticEaseOutImpl;
+ ///
+ /// Represents a quartic ease-in-out scale function.
+ ///
+ public static readonly ScaleFunc QuarticEaseInOut = QuarticEaseInOutImpl;
+ ///
+ /// Represents a quintic ease-in scale function.
+ ///
+ public static readonly ScaleFunc QuinticEaseIn = QuinticEaseInImpl;
+ ///
+ /// Represents a quintic ease-out scale function.
+ ///
+ public static readonly ScaleFunc QuinticEaseOut = QuinticEaseOutImpl;
+ ///
+ /// Represents a quintic ease-in-out scale function.
+ ///
+ public static readonly ScaleFunc QuinticEaseInOut = QuinticEaseInOutImpl;
+ ///
+ /// Represents a sine ease-in scale function.
+ ///
+ public static readonly ScaleFunc SineEaseIn = SineEaseInImpl;
+ ///
+ /// Represents a sine ease-out scale function.
+ ///
+ public static readonly ScaleFunc SineEaseOut = SineEaseOutImpl;
+ ///
+ /// Represents a sine ease-in-out scale function.
+ ///
+ public static readonly ScaleFunc SineEaseInOut = SineEaseInOutImpl;
+ #endregion
+
+ #region Functions
+ ///
+ /// Returns the progress as is, resulting in a linear scale.
+ ///
+ /// The progress value between 0 and 1.
+ /// The linear scale value.
+ public static float LinearImpl(float progress)
+ {
+ return progress;
+ }
+
+ ///
+ /// Applies quadratic ease-in to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The eased-in scale value.
+ public static float QuadraticEaseInImpl(float progress)
+ {
+ return EaseInPower(progress, 2);
+ }
+
+ ///
+ /// Applies quadratic ease-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The eased-out scale value.
+ public static float QuadraticEaseOutImpl(float progress)
+ {
+ return EaseOutPower(progress, 2);
+ }
+
+ ///
+ /// Applies quadratic ease-in-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The eased-in-out scale value.
+ public static float QuadraticEaseInOutImpl(float progress)
+ {
+ return EaseInOutPower(progress, 2);
+ }
+
+ ///
+ /// Applies cubic ease-in to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The eased-in scale value.
+ public static float CubicEaseInImpl(float progress)
+ {
+ return EaseInPower(progress, 3);
+ }
+
+ ///
+ /// Applies cubic ease-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The eased-out scale value.
+ public static float CubicEaseOutImpl(float progress)
+ {
+ return EaseOutPower(progress, 3);
+ }
+
+ ///
+ /// Applies cubic ease-in-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The eased-in-out scale value.
+ public static float CubicEaseInOutImpl(float progress)
+ {
+ return EaseInOutPower(progress, 3);
+ }
+
+ ///
+ /// Applies quartic ease-in to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// Returns the progress value modified with quadratic ease-in.
+ public static float QuarticEaseInImpl(float progress)
+ {
+ return EaseInPower(progress, 4);
+ }
+
+ ///
+ /// Applies quartic ease-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// Returns the progress value modified with quadratic ease-out.
+ public static float QuarticEaseOutImpl(float progress)
+ {
+ return EaseOutPower(progress, 4);
+ }
+
+ ///
+ /// Applies quartic ease-in-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// Returns the progress value modified with quadratic ease-in-out.
+ public static float QuarticEaseInOutImpl(float progress)
+ {
+ return EaseInOutPower(progress, 4);
+ }
+
+ ///
+ /// Applies quintic ease-in to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// Returns the progress value modified with quintic ease-in.
+ public static float QuinticEaseInImpl(float progress)
+ {
+ return EaseInPower(progress, 5);
+ }
+
+ ///
+ /// Applies quintic ease-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// Returns the progress value modified with quintic ease-out.
+ public static float QuinticEaseOutImpl(float progress)
+ {
+ return EaseOutPower(progress, 5);
+ }
+
+ ///
+ /// Applies quintic ease-in-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// Returns the progress value modified with quintic ease-in-out.
+ public static float QuinticEaseInOutImpl(float progress)
+ {
+ return EaseInOutPower(progress, 5);
+ }
+
+ ///
+ /// Applies ease-in power to the progress with the specified power.
+ ///
+ /// The progress value between 0 and 1.
+ /// The power value for the ease-out function.
+ /// The modified progress value with ease-in power.
+ public static float EaseInPower(float progress, int power)
+ {
+ return (float)Math.Pow(progress, power);
+ }
+
+ ///
+ /// Applies ease-out power to the progress with the specified power.
+ ///
+ /// The progress value between 0 and 1.
+ /// The power value for the ease-out function.
+ /// The modified progress value with ease-out power.
+ public static float EaseOutPower(float progress, int power)
+ {
+ int sign = (power % 2 != 0) ? 1 : -1;
+ return (float)(sign * (Math.Pow(progress - 1f, power) + sign));
+ }
+
+ ///
+ /// Applies ease-in-out power to the progress with the specified power.
+ ///
+ /// The progress value between 0 and 1.
+ /// The power value for the ease-out function.
+ /// The modified progress value with ease-in-out power.
+ public static float EaseInOutPower(float progress, int power)
+ {
+ progress *= 2f;
+ if (progress < 1f)
+ {
+ return (float)Math.Pow(progress, power) / 2f;
+ }
+ int sign = (power % 2 != 0) ? 1 : -1;
+ return (float)(sign / 2.0 * (Math.Pow(progress - 2f, power) + (sign * 2)));
+ }
+
+ ///
+ /// Applies sine ease-in to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The modified progress value with sine ease-in.
+ public static float SineEaseInImpl(float progress)
+ {
+ return (float)Math.Sin((progress * (float)Math.PI / 2f) - ((float)Math.PI / 2f)) + 1f;
+ }
+
+ ///
+ /// Applies sine ease-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The modified progress value with sine ease-out.
+ public static float SineEaseOutImpl(float progress)
+ {
+ return (float)Math.Sin(progress * (float)Math.PI / 2f);
+ }
+
+ ///
+ /// Applies sine ease-in-out to the progress.
+ ///
+ /// The progress value between 0 and 1.
+ /// The modified progress value with sine ease-in-out.
+ public static float SineEaseInOutImpl(float progress)
+ {
+ return (float)(Math.Sin((progress * (float)Math.PI) - ((float)Math.PI / 2f)) + 1.0) / 2f;
+ }
+ #endregion
+ }
+}
diff --git a/LemonUI/TinyTween/StopBehavior.cs b/LemonUI/TinyTween/StopBehavior.cs
new file mode 100644
index 0000000..222181a
--- /dev/null
+++ b/LemonUI/TinyTween/StopBehavior.cs
@@ -0,0 +1,17 @@
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Enumeration representing different stop behaviors of a tween.
+ ///
+ public enum StopBehavior
+ {
+ ///
+ /// Represents the "as is" stop behavior of a tween.
+ ///
+ AsIs,
+ ///
+ /// Represents the "force complete" stop behavior of a tween.
+ ///
+ ForceComplete
+ }
+}
diff --git a/LemonUI/TinyTween/Tween.cs b/LemonUI/TinyTween/Tween.cs
new file mode 100644
index 0000000..02fe76c
--- /dev/null
+++ b/LemonUI/TinyTween/Tween.cs
@@ -0,0 +1,172 @@
+using System;
+
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Represents a generic tween with different stop behaviors.
+ ///
+ /// The type of value being tweened.
+ public class Tween : ITween, ITween
+ where T : struct
+ {
+ #region Fields
+ ///
+ /// The lerp function used for the tween.
+ ///
+ private readonly LerpFunc lerpFunc;
+ ///
+ /// The current time of the tween.
+ ///
+ private float currentTime;
+ ///
+ /// The duration of the tween.
+ ///
+ private float duration;
+ ///
+ /// The scale function used for the tween.
+ ///
+ private ScaleFunc scaleFunc;
+ ///
+ /// The state of the tween.
+ ///
+ private TweenState state;
+ ///
+ /// The starting value of the tween.
+ ///
+ private T start;
+ ///
+ /// The ending value of the tween.
+ ///
+ private T end;
+ ///
+ /// The current value of the tween.
+ ///
+ private T value;
+ ///
+ /// Gets the current time of the tween.
+ ///
+ public float CurrentTime => currentTime;
+ ///
+ /// Gets the duration of the tween.
+ ///
+ public float Duration => duration;
+ ///
+ /// Gets the state of the tween.
+ ///
+ public TweenState State => state;
+ ///
+ /// Gets the starting value of the tween.
+ ///
+ public T StartValue => start;
+ ///
+ /// Gets the ending value of the tween.
+ ///
+ public T EndValue => end;
+ ///
+ /// Gets the current value of the tween.
+ ///
+ public T CurrentValue => value;
+ #endregion
+
+ #region Constructors
+ ///
+ /// Initializes a new instance of the Tween class with the specified lerp function.
+ ///
+ /// The lerp function used for the tween.
+ public Tween(LerpFunc lerpFunc)
+ {
+ this.lerpFunc = lerpFunc;
+ state = TweenState.Stopped;
+ }
+ #endregion
+
+ #region Functions
+ ///
+ /// Starts the tween with the specified start and end values, duration, and scale function.
+ ///
+ /// The starting value of the tween.
+ /// The ending value of the tween.
+ /// The duration of the tween.
+ /// The scale function to be used for the tween.
+ /// Thrown when the duration is less than or equal to 0.
+ /// Thrown when the scaleFunc is null.
+ public void Start(T start, T end, float duration, ScaleFunc scaleFunc)
+ {
+ if (duration <= 0f)
+ {
+ throw new ArgumentException("duration must be greater than 0");
+ }
+ if (scaleFunc == null)
+ {
+ throw new ArgumentNullException("scaleFunc");
+ }
+ currentTime = 0f;
+ this.duration = duration;
+ this.scaleFunc = scaleFunc;
+ state = TweenState.Running;
+ this.start = start;
+ this.end = end;
+ UpdateValue();
+ }
+
+ ///
+ /// Pauses the tween if it is currently running.
+ ///
+ public void Pause()
+ {
+ if (state == TweenState.Running)
+ {
+ state = TweenState.Paused;
+ }
+ }
+
+ ///
+ /// Resumes the tween if it is currently paused.
+ ///
+ public void Resume()
+ {
+ if (state == TweenState.Paused)
+ {
+ state = TweenState.Running;
+ }
+ }
+
+ ///
+ /// Stops the tween with the specified stop behavior.
+ ///
+ /// The stop behavior to apply.
+ public void Stop(StopBehavior stopBehavior)
+ {
+ state = TweenState.Stopped;
+ if (stopBehavior == StopBehavior.ForceComplete)
+ {
+ currentTime = duration;
+ UpdateValue();
+ }
+ }
+
+ ///
+ /// Updates the tween with the specified elapsed time.
+ ///
+ /// The elapsed time since the last update.
+ public void Update(float elapsedTime)
+ {
+ if (state == TweenState.Running)
+ {
+ currentTime += elapsedTime;
+ if (currentTime >= duration)
+ {
+ currentTime = duration;
+ state = TweenState.Stopped;
+ }
+ UpdateValue();
+ }
+ }
+
+ private void UpdateValue()
+ {
+ value = lerpFunc(start, end, scaleFunc(currentTime / duration));
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/LemonUI/TinyTween/TweenState.cs b/LemonUI/TinyTween/TweenState.cs
new file mode 100644
index 0000000..48fa5ec
--- /dev/null
+++ b/LemonUI/TinyTween/TweenState.cs
@@ -0,0 +1,21 @@
+namespace LemonUI.TinyTween
+{
+ ///
+ /// Enumeration representing different states of a tween.
+ ///
+ public enum TweenState
+ {
+ ///
+ /// Represents the running state of a tween.
+ ///
+ Running,
+ ///
+ /// Represents the paused state of a tween.
+ ///
+ Paused,
+ ///
+ /// Represents the stopped state of a tween.
+ ///
+ Stopped
+ }
+}