Skip to main content

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.

Corner blending and speed profile

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.

Trapezoidal vs S-curve profiles

(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_radius is the cut-back distance along each adjacent leg of the corner, not an arc radius: a blend replaces the final r of the incoming segment and the first r of 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 via blend_radii) where exact pass-through matters.
  • Corners within ~2.6 degrees of a full reversal (the path doubles back on itself) cannot be blended: Hybrid falls back to a full stop at the waypoint, UseBlending raises a ValidationError.
  • An S-curve trajectory is jerk-limited end to end only with the default Hermite blends. Forcing blend_shape = Parabolic on 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 by T/duration, accelerations quadratically, jerks cubically, so all limits remain satisfied). Durations shorter than the current one raise a ValidationError.

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)

Source distribution for justblend 0.1.0
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)

Table of built distributions (wheels) for justblend 0.1.0
File Actions
justblend-0.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for justblend-0.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
justblend-0.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for justblend-0.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
justblend-0.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details for justblend-0.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
justblend-0.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for justblend-0.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
justblend-0.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details for justblend-0.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
justblend-0.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for justblend-0.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
justblend-0.1.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for justblend-0.1.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Security 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.

Select from 8 files

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 log

A 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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

8 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page