diff --git a/src/Avalonia.Animation/Easing/SplineEasing.cs b/src/Avalonia.Animation/Easing/SplineEasing.cs
new file mode 100644
index 0000000000..7192a77531
--- /dev/null
+++ b/src/Avalonia.Animation/Easing/SplineEasing.cs
@@ -0,0 +1,85 @@
+namespace Avalonia.Animation.Easings
+{
+ ///
+ /// Eases a value
+ /// using a user-defined cubic bezier curve.
+ /// Good for custom easing functions that doesn't quite
+ /// fit with the built-in ones.
+ ///
+ public class SplineEasing : Easing
+ {
+ ///
+ /// X coordinate of the first control point
+ ///
+ private double _x1;
+ public double X1
+ {
+ get => _x1;
+ set
+ {
+ _x1 = value; _internalKeySpline.ControlPointX1 = _x1;
+ }
+ }
+
+ ///
+ /// Y coordinate of the first control point
+ ///
+ private double _y1;
+ public double Y1
+ {
+ get => _y1;
+ set
+ {
+ _y1 = value; _internalKeySpline.ControlPointY1 = _y1;
+ }
+ }
+
+ ///
+ /// X coordinate of the second control point
+ ///
+ private double _x2 = 1.0d;
+ public double X2
+ {
+ get => _x2;
+ set
+ {
+ _x2 = value;
+ _internalKeySpline.ControlPointX2 = _x2;
+ }
+ }
+
+ ///
+ /// Y coordinate of the second control point
+ ///
+ private double _y2 = 1.0d;
+ public double Y2
+ {
+ get => _y2;
+ set
+ {
+ _y2 = value;
+ _internalKeySpline.ControlPointY2 = _y2;
+ }
+ }
+
+ private KeySpline _internalKeySpline;
+
+ public SplineEasing(double x1 = 0d, double y1 = 0d, double x2 = 1d, double y2 = 1d) : base()
+ {
+ this._internalKeySpline = new KeySpline();
+ this.X1 = x1;
+ this.Y1 = y1;
+ this.X2 = x2;
+ this.Y1 = y2;
+ }
+
+ public SplineEasing()
+ {
+ this._internalKeySpline = new KeySpline();
+ }
+
+ ///
+ public override double Ease(double progress) =>
+ _internalKeySpline.GetSplineProgress(progress);
+ }
+}