diff --git a/source/funkin/util/MathUtil.hx b/source/funkin/util/MathUtil.hx
index 3cb6621a7..c8c4f5109 100644
--- a/source/funkin/util/MathUtil.hx
+++ b/source/funkin/util/MathUtil.hx
@@ -5,6 +5,14 @@ package funkin.util;
  */
 class MathUtil
 {
+  public static var E(get, never):Float;
+
+  static function get_E():Float
+  {
+    // Math.E is not a constant in Haxe, so we'll just define it ourselves.
+    return 2.71828182845904523536; // Approximation.
+  }
+
   /**
    * Perform linear interpolation between the base and the target, based on the current framerate.
    */
@@ -24,8 +32,44 @@ class MathUtil
    * @param value The value to get the logarithm of.
    * @return `log_base(value)`
    */
-  public static function logBase(base:Float, value:Float):Float
+  public static function logBase(base:Float, value:Float)
   {
     return Math.log(value) / Math.log(base);
   }
+
+  /**
+   * @returns `2^x`
+   */
+  public static function exp2(x:Float)
+  {
+    return Math.pow(2, x);
+  }
+
+  /**
+   * Linearly interpolate between two values.
+   * @param base The starting value, when `progress <= 0`.
+   * @param target The ending value, when `progress >= 1`.
+   * @param progress Value used to interpolate between `base` and `target`.
+   */
+  public static function lerp(base:Float, target:Float, progress:Float)
+  {
+    return base + progress * (target - base);
+  }
+
+  /**
+   * Perform a framerate-independent linear interpolation between the base value and the target.
+   * @param current The current value.
+   * @param target The target value.
+   * @param elapsed The time elapsed since the last frame.
+   * @param duration The total duration of the interpolation. Nominal duration until remaining distance is less than `precision`.
+   * @param precision The target precision of the interpolation. Defaults to 1% of distance remaining.
+   * @see https://twitter.com/FreyaHolmer/status/1757918211679650262
+   */
+  public static function smoothLerp(current:Float, target:Float, elapsed:Float, duration:Float, precision:Float = 1 / 100):Float
+  {
+    // var halfLife:Float = -duration / logBase(2, precision);
+    // lerp(current, target, 1 - exp2(-elapsed / halfLife));
+
+    return lerp(current, target, 1 - Math.pow(p, elapsed / duration));
+  }
 }