Beryllium.ShapingFunctions
1.6.0
Prefix Reserved
dotnet add package Beryllium.ShapingFunctions --version 1.6.0
NuGet\Install-Package Beryllium.ShapingFunctions -Version 1.6.0
<PackageReference Include="Beryllium.ShapingFunctions" Version="1.6.0" />
<PackageVersion Include="Beryllium.ShapingFunctions" Version="1.6.0" />
<PackageReference Include="Beryllium.ShapingFunctions" />
paket add Beryllium.ShapingFunctions --version 1.6.0
#r "nuget: Beryllium.ShapingFunctions, 1.6.0"
#:package Beryllium.ShapingFunctions@1.6.0
#addin nuget:?package=Beryllium.ShapingFunctions&version=1.6.0
#tool nuget:?package=Beryllium.ShapingFunctions&version=1.6.0
BerylliumShapingFunctions
A collection of 44 shaping (easing) functions for .NET — the curves used to drive animation, interpolation, and
signal shaping. Every function maps an input to an output; inputs are clamped to the [0, 1] range before evaluation.
Every curve starts at exactly 0 and ends at exactly 1, whatever its parameters, so an animation always lands on its end
values; in between, most functions stay within [0, 1] (a few, such as Back and Elastic, intentionally overshoot).
Install
dotnet add package BerylliumShapingFunctions
Quick start
using Beryllium.ShapingFunctions;
// Create a function by its identifier.
BaseShapingFunction ease = ShapingFunctionFactory.Create(ShapingFunctionId.CubicEaseInOut);
float y = ease.CalculateOutput(0.25f); // -> shaped value
// Sample a whole curve.
for (int i = 0; i <= 10; i++)
{
float x = i / 10f;
Console.WriteLine($"{x:0.0} -> {ease.CalculateOutput(x):0.000}");
}
CalculateOutput is a pure function of its input: calling it repeatedly with the same input (and the same parameters)
always returns the same value and never mutates the object.
Parametric functions
Some functions expose tunable parameters through interfaces. Set the parameters, then call
CalculateOutput. Parameter values are clamped to their valid range internally (the integer order N to at least 1,
its default); assigning NaN throws ArgumentOutOfRangeException.
Parameters range over [0, 1], with one exception: outside the two Béziers the curve divides by A, so A is kept
within [0.00001, 0.99999]. Parameters start at the bottom of their range, which makes both Béziers straight lines
until they are configured.
var bezier = ShapingFunctionFactory.Create(ShapingFunctionId.BezierCubic);
if (bezier is IFourParameters p) // BezierCubic takes A, B, C, D (control points)
{
p.A = 0.25f;
p.B = 0.10f;
p.C = 0.25f;
p.D = 1.00f;
}
float y = bezier.CalculateOutput(0.5f);
Parameter interfaces are hierarchical — ITwoParameters : IOneParameter, and so on:
| Interface | Adds parameter |
|---|---|
IOneParameter |
A |
ITwoParameters |
B |
IThreeParameters |
C |
IFourParameters |
D |
INOrder |
N (integer order) |
You can discover a function's shape at runtime without knowing its concrete type:
var fn = ShapingFunctionFactory.Create(id);
ShapingFunctionId fnId = fn.Id; // the id it was created from
ShapingFunctionCategory category = fn.Category; // the category the catalog lists it under
bool parametric = fn.Parametric; // true if it has any tunable parameters (A–D or N)
int paramCount = fn.ParameterCount; // 0..4 (how many of A, B, C, D it uses)
bool hasOrder = fn.HasVariableOrder; // true if it implements INOrder (settable N)
int? order = fn.Order; // fixed polynomial degree, when applicable
string name = fn.Name; // human-readable name
Browsing the catalog
Functions are grouped into categories. Use ShapingFunctionCatalog to enumerate them — handy for building a picker UI:
foreach (ShapingFunctionCategory category in ShapingFunctionCatalog.GetCategories())
{
Console.WriteLine(category);
foreach (ShapingFunctionId id in ShapingFunctionCatalog.GetFunctions(category))
Console.WriteLine($" {id}");
}
ShapingFunctionFactory.Create and ShapingFunctionCatalog.GetFunctions throw
ArgumentOutOfRangeException for Custom (see Custom functions) and for values that are not
defined.
Categories and functions are always returned in the same stable, curated order, and the
ShapingFunctionId / ShapingFunctionCategory enum values are explicit and never renumbered — they are safe to persist
in settings or save files.
Available functions
| Category | Functions |
|---|---|
Back |
BackEaseIn, BackEaseInOut, BackEaseOut |
Bezier |
BezierCubic (4 params), BezierQuadratic (2 params) |
Bounce |
BounceEaseIn, BounceEaseInOut, BounceEaseOut |
Circular |
CircularDoubleSeat (1), CircularDoubleSigmoid (1), CircularEaseIn, CircularEaseInOut, CircularEaseOut |
Elastic |
ElasticEaseIn, ElasticEaseInOut, ElasticEaseOut |
Elliptical |
EllipticalDoubleSeat (2), EllipticalDoubleSigmoid (2) |
Exponential |
ExponentialDoubleSeat (1), ExponentialEaseIn, ExponentialEaseInOut, ExponentialEaseOut, LogisticSigmoid (1) |
Linear |
Linear |
Quadratic |
QuadraticEaseIn, QuadraticEaseInOut, QuadraticEaseOut, QuadraticThroughAGivenPoint (2) |
Cubic |
CubicDoubleSeat (2), CubicEaseIn, CubicEaseInOut, CubicEaseOut |
Quartic |
QuarticEaseIn, QuarticEaseInOut, QuarticEaseOut |
Quintic |
QuinticEaseIn, QuinticEaseInOut, QuinticEaseOut |
Hexic |
BlinnWyvillCosineApproximation |
NOrder |
DoubleOddPolynomialSeat (2 params + N), DoublePolynomialSigmoid (N) |
Sine |
SineEaseIn, SineEaseInOut, SineEaseOut |
Custom functions
Derive from BaseShapingFunction, pass a name (and, optionally, a fixed polynomial degree) to its constructor, and
implement CalculateCore, which receives the input already clamped to [0, 1]:
public sealed class SmoothStep : BaseShapingFunction
{
public SmoothStep()
: base("Smooth Step", 3)
{
}
protected override float CalculateCore(float input)
{
return input * input * (3.0f - 2.0f * input);
}
}
A custom function's Id and Category are ShapingFunctionId.Custom and ShapingFunctionCategory.Custom; the other
ids are reserved for the library's own functions, so each of them always names a function the factory can create. The
factory and the catalog know only the library's own functions, so Custom cannot be passed to
ShapingFunctionFactory.Create and never appears in the catalog; to save and restore a custom function, persist an
identifier of your own.
To make a custom function tunable, implement the parameter interfaces — ParameterCount, Parametric, and
HasVariableOrder follow from them — and clamp values in the setters with the protected ClampParameter helper, which
also rejects NaN.
Building and testing
dotnet test ShapingFunctions.sln
The tests check every curve against a double-precision implementation of its published formula (easings.net, Golan Levin's shaping functions, the Bernstein form of the Béziers) and hold every function to the guarantees above — exact end points, range, monotonicity, parameter clamping — across its parameter space.
Changelog
1.6.0
- Breaking: the
BaseShapingFunction(id, category, name, order)constructor is nowprivate protected, reserving the built-in ids for the library's own functions. Custom functions use the newBaseShapingFunction(name, order)constructor instead; theirIdandCategoryare the newShapingFunctionId.CustomandShapingFunctionCategory.Custommembers (both-1). - Code that lists functions with
Enum.GetValuesnow also seesCustom, which the factory rejects; the catalog lists only creatable functions. - Every function now returns exactly 0 at input 0 and exactly 1 at input 1, for any parameters.
BezierCubicandEllipticalDoubleSigmoidcould miss 1 by an ULP or two. BezierQuadraticcomputes its discriminant without cancellation: forAclose to 1 the end of the curve was off by up to2e-4(as high as1.0002).QuadraticThroughAGivenPointis evaluated without cancellation: forAclose to 0 or 1 it ended up to6e-5below 1 and could dip just before the end.
1.5.5
- Every function exposes its
IdandCategory, and theBaseShapingFunctionconstructor takes them:(id, category, name, order).
1.5.0
A breaking release for code written against 1.2 or earlier:
- The assembly is now
Beryllium.ShapingFunctions.dll(wasShapingFunctions.dll); the package id, namespace, and public type names are unchanged. CalculateOutputis no longer virtual — it clamps the input to[0, 1]and delegates to the newprotected abstract float CalculateCore(float input). Custom functions overrideCalculateCoreand pass their name/order to theBaseShapingFunctionconstructor.- The intermediate base classes (
LinearBase…HexicBase,NOrderBase,TranscendentalBase, and theParametric*tree) were removed; derive fromBaseShapingFunctiondirectly.Name,Order, andParametricare now read-only. Ndefaults to 1 and is clamped to at least 1; assigning NaN to any parameter throwsArgumentOutOfRangeExceptioninstead of being stored.- Several curves return slightly different (more accurate) values:
BezierCubicuses a robust solver (no more NaN or start-of-curve error),BezierQuadraticis exact nearA = 0.5, andLogisticSigmoidis computed in double precision.
License
MIT — see LICENSE.txt.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Beryllium.Math (>= 0.2.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Beryllium.ShapingFunctions:
| Package | Downloads |
|---|---|
|
Beryllium.Audio
Beryllium engine audio manager |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.6.0 | 104 | 9/26/2026 |