# DART (Dynamic Animation and Robotics Toolkit): a C++23 physics engine you build from source

> DART is a research-focused physics engine for robotics, animation and machine learning, with generalized coordinates, Featherstone dynamics and Python bindings. The main branch is DART 7, an in-progress redesign that the README says is not yet recommended for production use.

**dartsim/dart** — Research-focused C++23 physics engine for robotics, animation, and machine learning, with Python bindings.

- Repository: https://github.com/dartsim/dart
- Website: https://dart.readthedocs.io
- Stars: 1,210 · Forks: 305
- Language: C++
- License: BSD-2-Clause
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/dartsim-dart

## What DART solves, and who is expected to use it

Most simulators hand you a scene and a step function. DART hands you the machinery underneath: kinematics, dynamics, collision and constraint solving, exposed rather than wrapped. The README describes it as providing "transparent kinematics, dynamics, collision, and constraint-solving foundations for users who need more than a black-box simulator." That sentence is the whole pitch, and it also defines the audience. If you are writing a controller and want to query generalized coordinates, mass matrices or contact impulses directly, DART is aimed at you. If you want to drop a robot into a world and watch it walk without touching the equations, a higher-level simulator will get you there faster.

The stated targets are robotics, animation and machine learning. Machine learning appears because differentiable simulation and baseline comparisons need access to intermediate dynamics values, and the repository carries an examples/differentiable_gui directory. Animation appears because articulated rigid bodies with stable integration are the same problem in both fields. The README also claims DART "Powers Gazebo, research labs, and production systems worldwide, with best-effort support for production use." Read that qualifier carefully: best-effort is not a support contract, and the project says so itself.

## Generalized coordinates, Featherstone, and the DART 7 simulation facade

DART models articulated systems in generalized coordinates and integrates motion with Featherstone's Articulated Body Algorithm. That combination is the reason the engine exists in its current form: generalized coordinates avoid the drift and constraint-stiffness problems that come from simulating every joint as a separate constrained rigid body, and the articulated-body recursion computes forward dynamics in linear time with respect to the number of bodies.

The DART 7 API visible in the README is a facade over that core. You construct a `dart.World` with a time step, add bodies with a `RigidBodyOptions` struct, then call `enter_simulation_mode()` to lock the topology before stepping. That last call is the interesting design decision. Locking the model after construction means the solver can assume a fixed tree during stepping, which is exactly the assumption Featherstone's algorithm wants. It also means you cannot add or remove bodies mid-simulation without leaving simulation mode, and the README does not document what happens if you try.

Model loading is unified: URDF, SDF and MJCF all go through a single API. For anyone moving between Gazebo, MuJoCo and ROS description formats, that removes a conversion step that usually costs a day. The C++ side of the DART 7 facade is not fully settled. The README states the "final public header transaction is still in progress" and points readers to docs/design/simulation_cpp_api.md for current source-checkout examples.

## Installing DART 7 from a source checkout and running a first simulation

The README is blunt about the packaging situation: PyPI currently serves the stable DART 6 line as the latest non-yanked `dartpy` package, so the DART 7 Python facade has to come from a source checkout until a non-yanked DART 7 wheel is published. That means pixi, not pip, is the entry point today.

Start by installing the environment from the repository root. This resolves the locked dependency set from pixi.toml and pixi.lock.

```bash
pixi install
```

Then build. The README gives `pixi run build` as the source-checkout path for DART 7.

```bash
pixi run build
```

With the build in place, the documented smoke check sets PYTHONPATH to the build output and runs a Python snippet through pixi. The snippet creates a world, adds a rigid body with default options, locks the topology and steps once.

```bash
PYTHONPATH=build/default/cpp/Release/python pixi run python - <<'PY'
import dartpy as dart

world = dart.World()
body = world.add_rigid_body("box", dart.RigidBodyOptions())
world.enter_simulation_mode()
world.step()
print(f"t = {world.time:.4f} s, box position = {body.translation}")
PY
```

If that runs, you should see a time near 0.0000 s and a translation vector printed. The README treats `AttributeError` on `dart.World` or `add_rigid_body` as a diagnostic signal rather than a bug: it means the environment resolved a stable DART 6 package, and you should switch to the stable documentation. There is also a headless demo path for a slightly larger scene.

```bash
pixi run py-demos -- --scene rigid_body --headless --frames 1
```

The README notes these snippets build a model in code, so they do not depend on sample data files being present. That is a deliberate choice for smoke testing and it makes the check portable across machines.

## The DART 6 versus DART 7 split is the first thing to get right

The most consequential limitation is not technical, it is which branch you are on. The README carries an explicit warning that the main branch tracks DART 7, an in-progress redesign that is "not yet recommended for production use." The same warning points production users to DART 6 LTS on the release-6.20 branch, with documentation at dart.readthedocs.io/en/stable.

This split shows up everywhere. The Python wheel lane tracked for DART 7 builds CPython 3.14 wheels on Linux, macOS and Windows, but those wheels are not what PyPI serves as the latest non-yanked `dartpy`. The pyproject.toml classifier says "Development Status :: 2 - Pre-Alpha" and requires Python >=3.14, which is a narrow interpreter window. The C++ smoke check for the published package lives on release-6.*, and the README says DART 7 C++ artifacts have not been published yet.

So the practical failure mode is silent version confusion. You install `dartpy` from PyPI expecting the API in the quick-start snippet, and you get DART 6 instead. The README anticipates this and tells you to check for `dart.World`. It is a reasonable mitigation, but it puts the burden on you rather than on the package metadata.

## Where DART is the wrong tool

DART is a poor fit when you need a packaged, stable Python dependency today. The README's own instruction is to use the source checkout for the DART 7 Python facade, and `pixi run build` compiles C++ with CMake 4.2 or newer and scikit-build-core. That is a heavier setup than `pip install` and it assumes you can build native code on your machine. On a CI runner or a locked-down workstation, that assumption may not hold.

It is also the wrong tool if your problem is not articulated rigid-body dynamics. DART does not present itself as a soft-body, fluid or particle engine, and nothing in the README suggests those workloads. If you need GPU-parallel simulation today, the README describes multi-core, SIMD and accelerator backends as roadmap work, with cross-platform CPU support as the current state. That is a clear boundary, and it is stated rather than implied.

Finally, the production support model is best-effort by the project's own description. If you need a vendor with an SLA, this is not it.

## How DART differs from MuJoCo and Isaac Sim in approach

MuJoCo is the closest comparison and the difference is philosophical. MuJoCo is built around a specific contact model and solver configuration that its authors tuned for speed and stability in reinforcement learning; you get excellent defaults and relatively few knobs to turn. DART exposes the generalized-coordinate formulation and the Featherstone recursion as the primary interface, and its README frames the project as foundations for people writing new algorithms and comparing against baselines. In practice, MuJoCo is the better pick when you want a fast, well-tuned simulator for policy training, and DART is the better pick when the dynamics quantities are the object of study rather than a means to an end.

Isaac Sim sits at the opposite end of the abstraction scale: a full simulation application with GPU acceleration and a large asset and sensor stack. DART does not attempt that scope. The README lists accelerator backends as roadmap rather than shipped capability, and the repository's GUI work is oriented toward verification, with demo capture commands such as `pixi run py-demo-capture -- --scene rigid_solver_compare --frames 24 --width 960 --height 540 --show-ui` producing visual evidence for solver comparisons rather than a general-purpose authoring tool.

## Licence, releases and what an upgrade actually costs

DART is BSD-2-Clause. That is a permissive licence, and it is the same identifier declared in pyproject.toml under `license = "BSD-2-Clause"`. For most users this means you can link against it, ship binaries and keep your own source closed, provided you retain the copyright notice and disclaimer. It does not grant patent rights and it does not come with a warranty. Anyone embedding DART in a commercial product should read the LICENSE file in the repository rather than rely on a summary, and should treat questions about derivative-work boundaries as a matter for their own counsel.

The versioning picture is the real cost driver. Recent releases include v6.19.4 (DART 6.19.4) alongside verification-media tags, and the stable line is documented on the release-6.20 branch. Moving from DART 6 to DART 7 is not a patch upgrade: the Python API changes shape around `dart.World`, `RigidBodyOptions` and `enter_simulation_mode()`, and the C++ headers are still being finalized. pyproject.toml derives the package version from package.xml with a regex, so version bumps are tied to that file. The last push to the repository was on 2026-08-01, so the codebase is moving, but movement is not the same as API stability on a pre-alpha branch.

## Conclusion

Adopt DART if you need the dynamics quantities themselves, not a black-box simulator, and you are willing to run a source checkout: `pixi run build` from the repository is the documented DART 7 path, and the README states the main branch is not yet recommended for production use. Stay on the release-6.20 branch or the conda-forge `dartsim-cpp` package if you need a stable release today, and note that the Python package on PyPI still serves DART 6. Before committing, verify that `import dartpy as dart` exposes `dart.World` and `add_rigid_body`, because the README says a missing `dart.World` means the environment resolved a stable DART 6 package instead of DART 7.

## FAQ

### What does DART stand for in this project?

The README expands it as Dynamic Animation and Robotics Toolkit. The name reflects the three areas the project targets: robotics, animation and machine learning.

### Is DART a physics engine for AI and machine learning?

The README describes DART as a research-focused physics engine for robotics, animation and machine learning. It exposes kinematics, dynamics, collision and constraint solving rather than hiding them behind a black-box simulator, and the repository includes an examples/differentiable_gui directory.

### How do I install DART for Python?

The README says PyPI currently serves the stable DART 6 line as the latest non-yanked dartpy package, so the DART 7 Python facade must come from a source checkout using `pixi run build`. For DART 6 you can use `pip install --pre dartpy`, `pixi add dartpy` or `conda install -c conda-forge dartpy`.

### Which branch of DART should I use in production?

The README states that the main branch tracks DART 7, an in-progress redesign not yet recommended for production use, and directs production users to DART 6 LTS on the release-6.20 branch with documentation at dart.readthedocs.io/en/stable.

### What licence does DART use?

DART is BSD-2-Clause, and pyproject.toml declares `license = "BSD-2-Clause"`. The LICENSE file in the repository is the authoritative text.

### Why does my DART Python script fail with dart.World missing?

The README treats that as a signal that the environment resolved a stable DART 6 package instead of DART 7. It says you should use the stable documentation in that case, since the quick-start snippet targets the DART 7 API.

## Sources

- [Official documentation](https://dart.readthedocs.io)
- [Official README](https://github.com/dartsim/dart#readme)
- [Project repository](https://github.com/dartsim/dart)
- [Release notes](https://github.com/dartsim/dart/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dartsim-dart
