justblend
Closed-form N-dimensional trajectory generation with smooth corner blends. General-purpose: joint trajectories, Cartesian paths, CNC tool paths, animation curves -- anywhere you have a list of points in some D-dimensional space and want a velocity/acceleration/jerk-limited smooth trajectory through them.
Highlights
- Closed form, microsecond generation. No optimisation loop, no discretisation: typical multi-waypoint problems generate in roughly 0.05-0.1 ms and match ruckig's per-segment time-optimal durations on polyline motions (see benchmarks).
- Two velocity profiles. Bang-bang trapezoidal for the fastest rest-to-rest motion, or 7-phase jerk-limited S-curve when jerk limits are given.
- Three corner modes, two blend shapes. Stop at every waypoint, blend through corners, or a hybrid that blends where feasible. The cubic-Hermite blend has zero acceleration at its boundaries, so an S-curve trajectory stays jerk-limited through the corner.
- Analytic guarantees. Limits are satisfied by construction; the corner-cut deviation and per-waypoint passage times come back in closed form.
- Boundary speeds and duration stretching for moving-start replanning and speed control.
- C++17 and Python. Static library with clean CMake exports; pybind11 bindings with type stubs.
The output Trajectory is lazy: it owns a list of analytic segments and
can be sampled at any time t in [0, duration] without precomputing a
dense buffer.
(figures regenerate with python docs/generate_readme_figures.py)
Getting started -- C++
#include <justblend/justblend.hpp>
Eigen::MatrixXd waypoints(4, 2);
waypoints << 0.0, 0.0,
1.0, 0.5,
1.5,-0.2,
0.0, 0.0;
justblend::Limits limits;
limits.v_max = (Eigen::VectorXd(2) << 1.5, 1.2).finished();
limits.a_max = (Eigen::VectorXd(2) << 3.0, 2.5).finished();
limits.j_max = (Eigen::VectorXd(2) << 20.0, 18.0).finished();
justblend::GenerationOptions opts;
opts.blend_radius = 0.15;
opts.corner_handling = justblend::CornerHandling::HYBRID;
justblend::SCurveTrajectoryGenerator gen(2);
gen.setLimits(limits);
gen.setOptions(opts);
auto traj = gen.generate(waypoints);
auto s = traj.sample(0.5); // single sample
auto dense = traj.samples(0.002); // uniform dt sweep
Getting started -- Python
import numpy as np
import justblend as jb
waypoints = np.array([[0.0, 0.0], [1.0, 0.5], [1.5, -0.2], [0.0, 0.0]])
limits = jb.Limits(
v_max=np.array([1.5, 1.2]),
a_max=np.array([3.0, 2.5]),
j_max=np.array([20.0, 18.0]),
)
opts = jb.GenerationOptions(
blend_radius=0.15,
corner_handling=jb.CornerHandling.HYBRID,
)
gen = jb.SCurveTrajectoryGenerator(dim=2)
gen.set_limits(limits)
gen.set_options(opts)
traj = gen.generate(waypoints)
s = traj.sample(0.5)
dense = traj.samples(dt=0.002)
arbitrary = traj.samples(np.linspace(0, traj.duration(), 1000))
Corner semantics
blend_radiusis the cut-back distance along each adjacent leg of the corner, not an arc radius: a blend replaces the finalrof the incoming segment and the firstrof the outgoing one.- Blended corners cut the corner -- the trajectory does not pass through a
blended interior waypoint. Use
StrictCorners(or a per-corner radius viablend_radii) where exact pass-through matters. - Corners within ~2.6 degrees of a full reversal (the path doubles back on
itself) cannot be blended:
Hybridfalls back to a full stop at the waypoint,UseBlendingraises aValidationError. - An S-curve trajectory is jerk-limited end to end only with the default
Hermite blends. Forcing
blend_shape = Parabolicon the S-curve generator keeps the velocity and acceleration limits but introduces acceleration steps at blend boundaries, i.e. unbounded jerk there.
All input-validation failures throw justblend::ValidationError, which the
Python bindings raise as a ValueError subclass.
Boundary speeds, timing and deviation queries
generate() accepts optional tangential boundary speeds along the first and
last segment direction; infeasible requests (too fast for the limits or for
the available distance) raise a ValidationError:
auto traj = gen.generate(waypoints, /*v_start=*/0.3, /*v_end=*/0.0);
traj = gen.generate(waypoints, v_start=0.3, v_end=0.0)
GenerationOptions carries velocity_scaling_factor and
acceleration_scaling_factor in (0, 1] (matching MoveIt's semantics):
they scale v_max / a_max at generation time; j_max is never scaled.
The Trajectory exposes timing and corner-cut metadata:
segment_start_times()-- start time of each segment plus the total duration as the last entry.waypoint_times()-- passage time per waypoint; for blended corners this is the time of closest approach (the blend midpoint).corner_deviations()/max_corner_deviation()-- closed-form distance between each blended corner's waypoint and the blend path ((r/4)·|d_out - d_in|for parabolic,(3r/16)·|d_out - d_in|for Hermite blends; zero for non-blend corners). Useful to bound how far the blended trajectory strays from the original polyline.stretched_to(duration)-- uniformly time-dilated copy with exactly the requested total duration (same path; velocities scale byT/duration, accelerations quadratically, jerks cubically, so all limits remain satisfied). Durations shorter than the current one raise aValidationError.
Install -- C++
Requirements: CMake ≥ 3.18, a C++17 compiler, and Eigen 3.3+ (any package
that exposes find_package(Eigen3 NO_MODULE) -- the Debian/Ubuntu
libeigen3-dev package, vcpkg, conan, brew, or a manual install all work).
Build and install to a prefix
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DJUSTBLEND_BUILD_TESTS=OFF \
-DJUSTBLEND_BUILD_EXAMPLES=OFF \
-DJUSTBLEND_BUILD_PYTHON_BINDINGS=OFF
cmake --build build --parallel
cmake --install build --prefix /your/install/prefix # omit --prefix for /usr/local
This installs:
<prefix>/include/justblend/*.hpp<prefix>/lib/libjustblend.a<prefix>/lib/cmake/justblend/justblend{Config,ConfigVersion,Targets}.cmake
Use from another CMake project
After installing, consume justblend with find_package:
find_package(justblend 0.1.0 REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE justblend::justblend)
Then configure your project with -DCMAKE_PREFIX_PATH=/your/install/prefix
(or set justblend_DIR=<prefix>/lib/cmake/justblend).
You don't have to install: justblend also exports its targets from the
build tree, so pointing CMAKE_PREFIX_PATH at the build directory works
just as well.
To vendor justblend as a subdirectory (git submodule, FetchContent, or a
plain copy), drop add_subdirectory(path/to/justblend) into your
CMakeLists.txt -- the same justblend::justblend target becomes
available, and the test / example / Python-binding targets stay OFF by
default when consumed this way.
Run tests and examples
cmake -S . -B build -DJUSTBLEND_BUILD_TESTS=ON -DJUSTBLEND_BUILD_EXAMPLES=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failure
./build/examples/cpp/example_basic_2d
Install -- Python
pip install .
pip install fetches scikit-build-core and pybind11 automatically and
drives the same CMake build under the hood -- no separate C++ install step
needed. Eigen 3.3+ must still be installed on the host.
Benchmarks
justblend is benchmarked against ruckig and toppra on shared scenarios;
instructions, result tables and plots live in
benchmarks/README.md (regenerated by
python benchmarks/run.py).
License
MIT -- see LICENSE.
Metadata
Release files for justblend 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| justblend-0.1.0.tar.gz | 24.2 kB | With provenance | Details for justblend-0.1.0.tar.gz |
Built distributions (wheels)
Total release size: 1.4 MB
Release files / justblend-0.1.0.tar.gz
| Download URL | justblend-0.1.0.tar.gz |
|---|---|
| Size | 24.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cf8ee6163d506a97958bd23de71a759e37c6cff7a45c019cfcf727d31295929a
|
|
BLAKE2b-256 checksum How to use checksums |
711feaf62bcb9f08a5ca9dcbf7578927a2ac0982dcd3cc25cb65d2516b31f25d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 204.7 kB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
1580b8eca418e5b4a641a81c5b4f61fef7189ad595596b9985beeca8d320732c
|
|
BLAKE2b-256 checksum How to use checksums |
cf0b5cccba08c5118b853de94294e7423de6dd9edabf129600cddd55bc444641
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 201.3 kB |
| Tags | CPython 3.14 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
184eca870c213bf68d7da048f99a4012195607dce739eb61b0eb8517aabe5296
|
|
BLAKE2b-256 checksum How to use checksums |
679e01c0aa1e6271f41de315cb882ff8e363162bb7b9c927cb69958ca9dd3077
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 201.0 kB |
| Tags | CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
bbb392bc8be726d3ef46a620ee507dfae0a5ff1e24e7e9f4d325cae01863512a
|
|
BLAKE2b-256 checksum How to use checksums |
93e81561eeef2b405fd5c630fbd04e3b752d2626a41985f48fcd5293ace2b471
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 200.9 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
f1f62ced56754bcd6eff593a7d28f7d537450782d209e61661281b842c5b0f97
|
|
BLAKE2b-256 checksum How to use checksums |
bbbe13b3c4c05a5ab1fb95120d585c4dd1ca495050dc19e4d94ba74fd2de6b33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 199.5 kB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
bb59d5aef635f013f3e9bf98a36f982413747ccf3e6098288c3df027204734a6
|
|
BLAKE2b-256 checksum How to use checksums |
a2d1ae84643ebbfc12a2e56a2b50e2c4c9647cd2c9bb0ec647a62f1c435ec4c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 198.4 kB |
| Tags | CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
c6fdc3589cc975501e919e0b7154f2b16e6653f0f58e895aeb4ece920835c330
|
|
BLAKE2b-256 checksum How to use checksums |
cdace1eb2d3794422255b5c4b872eaabe9eac506409f1158404e52a2598d07b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / justblend-0.1.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | justblend-0.1.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 198.7 kB |
| Tags | CPython 3.9 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
5e9667c8f37ce492a2afe1d764b22347b7b31a2df2d212328b11e424f727ee2c
|
|
BLAKE2b-256 checksum How to use checksums |
2866bdd85d56baac5839812fc7a517c40d3df95fd434c94dc0e3261cfc9310a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logSecurity for justblend 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 8 files in this release have been uploaded with provenance metadata.
Attestation for justblend-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.