Library / SDK
xissburg/edyn avatar
xissburg/edyn

Edyn: a real-time physics engine where rigid bodies are just entities with components

Edyn is a real-time physics engine organized as an ECS.

793 stars36 forksC++MIT

At a glance

What is it?
Edyn is a C++17 physics engine built on the EnTT entity component system, where a rigid body has no explicit type and is instead recognised during the update by the combination of components on an entity. The engine is multi-threaded from the ground up, and the design goal is networked and distributed simulation of large dynamic worlds.
Who is it for?
Edyn fits a game or simulation developer who already works in an entity component system and wants a physics solver that fits inside that model rather than beside it, and who needs the solver to scale across threads. It does not fit a project that wants a familiar rigid body API, and it does not fit a codebase without EnTT.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 45 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the name means and what the engine is for

Edyn stands for Entity Dynamics and is a real-time physics engine organised as an ECS, an entity component system, using the EnTT library. The README states the main goals of the library in one sentence, and they are two: to be multi-threaded and to support networked and distributed physics simulation of large dynamic worlds.

Those two goals are what distinguish it from a general purpose physics engine, and they are linked. A simulation large enough to need distribution is usually large enough that a single-threaded solver becomes the bottleneck, so the threading is not a nice-to-have here, it is the enabling feature.

The project is MIT licensed, the primary language is C++, and the last push was on 2026-09-08. The release history shows v1.3.1 in June 2025, v1.3.0 in December 2024 and v1.2.1 in October 2022.

One practical note before anything else: the examples are not in this repository. They live in a separate repository called the Edyn Testbed, which is worth knowing before you start, because the README's examples are illustrative snippets rather than a runnable project you can clone.

Building it with Conan, and the Visual Studio route

Edyn is a compiled library, and the requirements are a compiler with C++17 support, CMake 3.23.0 or above, and Conan 2.0. The only dependency is EnTT, which is installed through Conan.

The build is two commands in the Edyn directory:

code
$ conan install .
$ conan build .

And the library ends up under build/Release/lib/. Conan builds the optimised release version by default, and the README explains how to get the debug version with assertions enabled by specifying the build type and options:

code
$ conan install . -s build_type=Debug
$ conan build . -s build_type=Debug -o '&:enable_assert=True'

The Windows path has an extra step and a warning. After cloning the repository using Git Bash, and with Conan 2.x installed, you run the install and then a CMake configure with the Visual Studio generator:

code
$ conan install .
$ cmake -S . -B build/generators -G "Visual Studio 16 2019" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake

The Edyn.sln solution then appears in the build/generators directory. The README flags a decision you have to make explicitly: whether you want a static or a dynamic library, which is set to dynamic by default in Visual Studio 2019, and switching it means opening the project properties and under Configuration Properties, then C/C++, then Code Generation, then Runtime Library, choosing the multi-threaded debug or multi-threaded runtime library for debug and release builds respectively.

The repository layout is conventional for a CMake C++ library, with CMakeLists.txt at the root, a conanfile.py, cmake, include, src, test, docs and examples directories, plus an AUTHORS.md.

Linking the library into your application

The integration notes are short and specific, and each line is a thing that will bite you if you skip it.

You link against libEdyn, or libEdyn_d for debug builds, which is found in edyn/build/lib/ after the build. On Linux you also have to link pthread. On Windows you additionally have to link winmm.lib, because the library needs the timeGetTime() function.

The winmm requirement is a good example of why the integration section exists at all. Edyn calls into the Windows multimedia timer directly rather than through the standard library, which is a deliberate choice for timing precision, and it means the dependency is invisible until you hit an unresolved symbol at link time.

The include paths also need setting: both edyn/include and edyn/build/include must be added, which is the usual arrangement when one directory holds your own headers and the other holds the ones the build generates.

So the full checklist for a consumer is: build the library, add the two include paths, link libEdyn or libEdyn_d, link pthread on Linux, and link winmm.lib on Windows.

Building a rigid body out of components

This is where the ECS approach shows itself. Typical physics engines offer explicit means to create objects such as rigid bodies, whereas in Edyn object creation is implicit because of the entity component design. A rigid body is created from the bottom up by associating its parts to a single entity:

cpp
entt::registry registry;
auto entity = registry.create();
registry.emplace<edyn::dynamic_tag>(entity);
registry.emplace<edyn::position>(entity, 0, 3, 0);
registry.emplace<edyn::orientation>(entity, edyn::quaternion_axis_angle({0, 1, 0}, edyn::to_radians(30)));
registry.emplace<edyn::linvel>(entity, edyn::vector3_zero);
registry.emplace<edyn::angvel>(entity, 0, 0.314, 0);
auto mass = edyn::scalar{50};
registry.emplace<edyn::mass>(entity, mass);
auto &shape = registry.emplace<edyn::box_shape>(entity, 0.5, 0.2, 0.4); // Box half-extents.
registry.emplace<edyn::inertia>(entity, edyn::moment_of_inertia(shape, mass));
registry.emplace<edyn::material>(entity, 0.2, 0.9); // Restitution and friction.
registry.emplace<edyn::gravity>(entity, edyn::gravity_earth);

Note what is absent. There is no explicit mention of a rigid body in that code. During the physics update, all entities that have a combination of the components assigned above are treated as a rigid body, and their state is updated over time as expected.

The components carry the physics meaning: a dynamic tag marks the entity as simulated rather than static, position and orientation place it, linear and angular velocity give it motion, mass and an inertia tensor derived from the shape give it rotational properties, a material component carries restitution and friction, and gravity selects the acceleration. The shape is a box here with half-extents, and the inertia is computed from the shape and the mass rather than being set by hand, which is the detail that makes the component approach workable: a rigid body's rotational behaviour follows from its geometry automatically.

The update loop, and why components need marking as changed

Because the state is components, the update is a set of views over the registry rather than a call on an object. The README shows three steps: applying gravity acceleration to entities with linear velocity and a gravity component, moving entities by their linear velocity, and rotating entities by their angular velocity.

cpp
// Apply gravity acceleration, increasing linear velocity
auto view = registry.view<edyn::linvel, edyn::gravity, edyn::dynamic_tag>();
for (auto [entity, vel, g] : view.each()) {
  vel += g * dt;
}
// ...
// Move entity with its linear velocity
auto view = registry.view<edyn::position, edyn::linvel, edyn::dynamic_tag>();
for (auto [entity, pos, vel] : view.each()) {
  pos += vel * dt;
}
// ...
// Rotate entity with its angular velocity
auto view = registry.view<edyn::orientation, edyn::angvel, edyn::dynamic_tag>();
for (auto [entity, orn, vel] : view.each()) {
  orn = edyn::integrate(orn, vel, dt);
}

That is illustrative rather than the engine's own integrator, since a real solver does much more than this, but it shows the shape of the API: a view is a typed query over the registry, and the components you put in it determine what the step touches.

Assigning each component to every rigid body individually quickly becomes a daunting task which is prone to errors, so utility functions are provided for common tasks such as creating rigid bodies:

cpp
// Equivalent to example above.
auto def = edyn::rigidbody_def();
def.kind = edyn::rigidbody_kind::rb_dynamic;
def.position = {0, 3, 0};
def.orientation = edyn::quaternion_axis_angle({0, 1, 0}, edyn::to_radians(30));
def.linvel = edyn::vector3_zero;
def.angvel = {0, 0.314, 0};
def.mass = 50;
def.shape = edyn::box_shape{0.5, 0.2, 0.4}; // Shape is optional.
def.material->restitution = 0.2; // Material is also optional.
def.material->friction = 0.9;
def.gravity = edyn::gravity_earth;
auto entity = edyn::make_rigidbody(registry, def);

And you are free to assign other components of your own to the returned entity, or pass an existing entity to make_rigidbody so you can attach your own components to it.

Initialising the workers and keeping them in sync

Edyn is built as a multi-threaded library from the ground up, which requires initialising its worker threads on start-up with edyn::init(), and then attaching it to an entt::registry before setting up the scene:

cpp
#include <entt/entt.hpp>
#include <edyn/edyn.hpp>

entt::registry registry;
edyn::init();
edyn::attach(registry);

// Create rigid bodies as shown above...

// Call `edyn::update()` periodically in your main loop somewhere.
for (;;) {
  edyn::update(registry);
  // Do something with the results, e.g. render scene.
  // ...
}

The comment tells you the contract: call edyn::update() periodically in your main loop, and do something with the results such as rendering the scene.

What update does is spelled out in the next paragraph, and the sequence matters. It processes any pending changes, creates and destroys workers if needed, dispatches messages to workers, reads and processes messages from workers which are merged into the entt::registry, preparing the entities and components to be rendered right after.

And then comes the part that will cost you an afternoon if you miss it. Due to the multi-threaded nature, all changes to relevant components in the main entt::registry need to be propagated to the worker threads, and Edyn does not automatically pick up these changes. You have to notify it, either by calling edyn::refresh() or by assigning an edyn::dirty component to the entity and calling one of its functions such as edyn::dirty::updated().

That is the cost of the threading, and it is the design trade of the whole library. In exchange for the solver running across cores, the caller has to say which entities changed. For a simulation where a few thousand bodies change every frame, that is a per-frame bookkeeping burden the caller owns, and for a networked simulation where state arrives from elsewhere it is the mechanism that makes remote changes visible to the solver.

Editorial conclusion

Edyn fits a game or simulation developer who already works in an entity component system and wants a physics solver that fits inside that model rather than beside it, and who needs the solver to scale across threads. It does not fit a project that wants a familiar rigid body API, and it does not fit a codebase without EnTT. Before adopting it, read the dirty component and refresh mechanism, because component changes in the main registry are not propagated to workers automatically, and note that the examples live in a separate testbed repository, so the quick reference for how the pieces fit together is not in this tree.

Frequently asked questions

What is Edyn and what are its main goals?

Edyn stands for Entity Dynamics and is a real-time physics engine organised as an entity component system using EnTT. The README states the main goals as being multi-threaded and supporting networked and distributed physics simulation of large dynamic worlds.

How do I build Edyn from source?

You need a C++17 compiler, CMake 3.23.0 or above and Conan 2.0, with EnTT installed through Conan. Run `conan install .` and `conan build .` in the Edyn directory, and the library appears under build/Release/lib/. For a debug build with assertions, add `-s build_type=Debug` and the enable_assert option.

How do I create a rigid body in Edyn?

There is no explicit rigid body type. You create an entity and emplace the components for position, orientation, linear and angular velocity, mass, a shape such as a box, an inertia derived from the shape and mass, a material with restitution and friction, gravity and a dynamic tag, and the engine treats entities with that combination as rigid bodies during the update.

What must I link when using Edyn in my application?

Link libEdyn, or libEdyn_d for debug builds, found in edyn/build/lib/. On Linux you also link pthread, and on Windows you additionally link winmm.lib because the library uses the timeGetTime() function. The include paths edyn/include and edyn/build/include must both be added.

How do I keep Edyn's worker threads in sync with my registry changes?

Edyn does not pick up changes to relevant components in the main registry automatically, because it is multi-threaded. You have to notify it, either by calling edyn::refresh() or by assigning an edyn::dirty component to the entity and calling one of its functions such as edyn::dirty::updated().

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. xissburg/edyn on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xissburg-edyn.svg)](https://hysenlabs.com/projects/xissburg-edyn)

Was this useful?