A deterministic 3D physics engine for games. Written in C23, with a plain C API whose headers also compile as C17 and C++17, no dependencies and an MIT license.
Same inputs, same bits, on every supported platform and at every thread count. A snapshot restores a world exactly, and the command journal records a session and replays it byte for byte, verifying every id and backing out atomically when a tape does not fit. Rollback netcode, lockstep multiplayer, replays and server-side verification are a few calls away:
int64_t size = m3World_GetSnapshotSize(world);
int64_t written = 0;
m3World_Snapshot(world, buffer, size, &written);
/* ... mispredicted steps ... */
m3World_Restore(world, buffer, size); // resimulate from here, bit for bit
Maul3D has a 2D sibling, Maul2D. The two are one family: two engines, one set of rules.
| Maul2D | Maul3D | |
|---|---|---|
| World | 2D | 3D |
| Built for | platformers, puzzles, top-down games, machines, water | destruction, vehicles, characters, lockstep multiplayer |
| Beyond rigid bodies | particle fluids, one-way chain terrain, geometry tools | voxel destruction, raycast vehicles, character controller, soft bodies, replay tools |
| Repository | Rawframe-Project/maul2d | this one |
What the family shares:
m2CreateBody and m3CreateBody,
m2World_StartJournal and m3World_StartJournal,
m2World_GetContactEvents and m3World_GetContactEvents.m3World_Explode pushes every body by
the area it shows to the blast, carves voxel chunks and shoves soft
particles, journaled and exact under rollback.m3replay tool records, verifies,
seeks, plays and compares two runs down to the first diverging
frame; m3lockstep runs a two-peer lockstep exchange in one process
and checks both timelines at every checkpoint.cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build
The library needs a C23 compiler: GCC 14, Clang 19 or newer, or
clang-cl on Windows. Configuring with an older one stops with an
error, so where the default compiler is older, as Ubuntu 24.04's
GCC 13 is, name one in the first line with -DCMAKE_C_COMPILER=gcc-14
or -DCMAKE_C_COMPILER=clang-20. MSVC's cl cannot build the library,
but a program built with it can include the public headers, which
are C17 and C++17.
x64 builds use AVX2 and FMA (Haswell, 2013, and later); configure with
-DMAUL3D_SIMD=scalar for a portable build that gives identical
results. An AVX2 build started on a CPU without AVX2 refuses to create
worlds instead of crashing.
cmake --install installs the library, the headers, a CMake package
and a pkg-config file, so find_package(maul3d) and
pkg-config maul3d both work. Build a shared library with
-DMAUL3D_BUILD_SHARED=ON. Every tagged release carries prebuilt
libraries for Linux (x64 and arm64), Windows and macOS.
The samples are small complete programs: a falling
stack that prints the same hash on every machine, the rollback loop,
a car that turns into a tank, and a character on the stairs.
samples/minimal is a standalone project that finds the installed
package.
The interactive testbed builds with -DMAUL3D_BUILD_TESTBED=ON. Its
fourteen scenes cover benchmarks, voxel destruction, three kinds of
vehicle, a playable character, cloth in gusting wind and a
heightfield, with a recording panel that seals the session into an
M3RP replay and verifies it. Hold R and time runs backward.
bindings/ holds the C# binding (one P/Invoke file), which keeps the
same 1.x promise as the C headers, and a Godot starter kit (a
GDExtension node), which follows Godot's versions and is outside it.
CI checks both against the C API: every function they call, and every
struct the C# side mirrors, field by field. Bindings
says how to build and use them.
test/hashes.txt, so twelve cells agree bit for
bit: GCC 14 on x64 and arm64 Linux, Clang 20 on x64 Linux, both on
32-bit x86 Linux, clang-cl on x64 and arm64 Windows, Clang on arm64
macOS, a shared library, Debug builds under AddressSanitizer on the
scalar backend and under ThreadSanitizer, and WebAssembly.The scenes in bench/ (a pyramid, hull and mesh fields, a voxel fort,
a 5000-body city block with destruction and a 10,000-body smoke test)
print their timings. Their final world hashes are pinned in
test/hashes.txt and checked by the Release-only bench test, which
the nightly CI run executes on every platform.
From 1.0.0 the API is settled, and every 1.x release keeps it: a
program that builds against 1.y builds against any later 1.z and means
the same. A minor release adds functions, types, enum values and
fields at the end of a struct, and never removes or renames one; a
patch release only fixes. A change that gives existing inputs a
different result ships as a feat in a minor release, or as a fix
in a patch release when it corrects a result the documentation
already promised, and the changelog says what
changes. A program built against
another minor version's headers is refused at m3CreateWorld with
m3_errorVersion. Defs carry a cookie, so a def that was not set up
with its m3Default...Def function is refused. A snapshot, a journal
tape and a replay file are read only within the minor version that
wrote them, and a snapshot only by a release with the same results;
any other release refuses them with m3_errorVersion, so a host keeps
assets, not state, across an upgrade.
Issues are welcome. Pull requests are accepted for issues a maintainer has approved; see CONTRIBUTING.md. The project is developed with AI coding agents, directed and reviewed by its maintainers; outside contributions follow the AI policy.
The engine's algorithms follow published work: the soft step schedule and soft constraints, the collision, distance and hull methods, the mass properties and the particle model. docs/internals/references.md lists every source. The library itself uses no outside code. The testbed, which is not part of the library, is built on raylib (zlib/libpng license), fetched when the testbed is configured.
MIT. See LICENSE.