A modern C++ library for creating, managing, and evaluating animation curves built from keyframes and cubic Bézier interpolation.
- Modern C++20 library; builds as a static (default) or shared library
Animationcontainers holding multiple namedChannelcurves- Three interpolation functions per keyframe:
Constant— hold the value until the next keyframe (step)Linear— straight-line interpolationBezier— cubic Bézier interpolation driven by handles
- Rich Bézier handle modes (
HandleMode):Flat,Smooth,Aligned,Free, and the aligned variantsAlignStrict/AlignFlex/AlignAdjustable - Out-of-range extrapolation per channel (
Extend):Hold,Repeat,Mirror - Stable, unique channel identity via
Id(survives copies) - Sampling helpers (
evaluate,evaluate_range,evaluate_range_by_rate) - Comprehensive Catch2 test suite
- A C++20-compatible compiler (MSVC 2022, GCC 11+, Clang 14+)
- CMake 3.25 or newer
Helper scripts are provided that configure, build, and run the tests:
./build.sh # Linux / macOS.\build.ps1 # Windows (PowerShell)Or drive CMake directly:
cmake -B build -S . -DANIM_BUILD_TESTS=ON
cmake --build build
ctest --test-dir buildadd_subdirectory(path/to/anim)
target_link_libraries(your_target PRIVATE anim)After installing the library, use find_package:
find_package(anim REQUIRED)
target_link_libraries(your_target PRIVATE anim::anim_static) # or anim::anim_shared| Option | Default | Description |
|---|---|---|
ANIM_BUILD_STATIC |
ON |
Build the static library. |
ANIM_BUILD_SHARED |
OFF |
Build the shared library. |
ANIM_BUILD_TESTS |
ON standalone, OFF as submodule |
Build the test suite. |
ANIM_BUILD_EXAMPLES |
ON standalone, OFF as submodule |
Build the examples. |
When anim is added with add_subdirectory, tests and examples default to
OFF so they don't build as part of your project.
Include the umbrella header (or the individual headers under anim/):
#include <anim.hpp>Channels are created and owned by an Animation; you don't construct them
directly. Add keyframes with create_keyframe, then evaluate the curve.
#include <anim.hpp>
#include <iostream>
int main() {
anim::Animation animation("demo");
// Channels are created through the animation, which keeps them sorted
// and assigns each a unique id.
anim::Channel& channel = animation.create_channel("value");
// create_keyframe(time, value, function, handle_mode)
channel.create_keyframe(0.0, 0.0, anim::Function::Linear);
channel.create_keyframe(1.0, 1.0); // default: Bezier / Smooth
channel.create_keyframe(2.0, 0.0, anim::Function::Bezier,
anim::HandleMode::Flat);
// Evaluate single times
std::cout << "t=0.5 -> " << channel.evaluate(0.5) << "\n";
std::cout << "t=1.5 -> " << channel.evaluate(1.5) << "\n";
// Evaluate a range: 5 evenly spaced samples from t=0 to t=2
for (double v : channel.evaluate_range(0.0, 2.0, 5)) {
std::cout << v << " ";
}
std::cout << "\n";
return 0;
}Handles are anim::Point values in (time, value) space:
anim::Channel& ch = animation.create_channel("curve");
// create_keyframe(time, value, in_handle, out_handle, function, handle_mode)
ch.create_keyframe(0.0, 0.0,
anim::Point(-0.3, 0.0), // in-handle
anim::Point( 0.3, 0.0), // out-handle
anim::Function::Bezier,
anim::HandleMode::Aligned);anim::Animation transform("transform");
anim::Channel& pos_x = transform.create_channel("position.x");
anim::Channel& pos_y = transform.create_channel("position.y");
pos_x.create_keyframe(0.0, 0.0, anim::Function::Linear);
pos_x.create_keyframe(1.0, 10.0, anim::Function::Linear);
pos_y.create_keyframe(0.0, 0.0);
pos_y.create_keyframe(1.0, 5.0);
double x = transform.channel("position.x").evaluate(0.5);
double y = transform.channel("position.y").evaluate(0.5);Each channel decides how to evaluate times before its first keyframe and after its last:
anim::Channel& ch = animation.create_channel("looping");
ch.create_keyframe(0.0, 0.0, anim::Function::Linear);
ch.create_keyframe(1.0, 1.0, anim::Function::Linear);
ch.set_extend_start(anim::Extend::Repeat); // loop before the start
ch.set_extend_end(anim::Extend::Mirror); // ping-pong after the endWith ANIM_BUILD_EXAMPLES enabled, the examples/ directory builds:
test_anim_integration— a minimal, dependency-free program that exercises the core API (a good starting point for real usage).curve_visualization— an interactive ImGui/ImPlot viewer for inspecting curves and handle modes.
The helper scripts above build the library and tests only. To build and launch the viewer (which fetches GLFW, ImGui and ImPlot on first configure):
./examples/run_example.sh # Linux / macOS.\examples\run_example.ps1 # Windows (PowerShell)The full API reference and guide are published at https://actualize-interactive.github.io/anim/, generated from the in-header documentation with Doxygen and Sphinx. To build the docs locally:
bash docs/build_docs.sh # Linux / macOS — output in docs/build/html.\docs\build_docs.ps1 # Windows (PowerShell)Distributed under the MIT License. See the LICENSE file.
Contributions are welcome — please open an issue or pull request.