Physics library for Python
  • C++ 69.2%
  • Python 27.1%
  • CMake 3.1%
  • PowerShell 0.4%
  • R 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
github-actions[bot] 854e79aa12
Bump extern/JoltPhysics from 5d5275c to 0f69a6b (#122)
Bumps [extern/JoltPhysics](https://github.com/jrouwe/JoltPhysics) from
`5d5275c` to `0f69a6b`.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0f69a6b8f0"><code>0f69a6b</code></a>
Soft body: Added accessors to access the skinned vertices (<a
href="https://redirect.github.com/jrouwe/JoltPhysics/issues/2199">#2199</a>)</li>
<li><a
href="f3c0ef891a"><code>f3c0ef8</code></a>
Hair unit tests (<a
href="https://redirect.github.com/jrouwe/JoltPhysics/issues/2194">#2194</a>)</li>
<li><a
href="8bc5cdee81"><code>8bc5cde</code></a>
Switch MSYS2 build to use UCRT64 since MINGW64 is deprecated (<a
href="https://redirect.github.com/jrouwe/JoltPhysics/issues/2195">#2195</a>)</li>
<li><a
href="ea4599d504"><code>ea4599d</code></a>
Soft body unit tests (<a
href="https://redirect.github.com/jrouwe/JoltPhysics/issues/2193">#2193</a>)</li>
<li><a
href="9a9a65e6fd"><code>9a9a65e</code></a>
Unit tests for ConvexHullShape and Ragdoll (<a
href="https://redirect.github.com/jrouwe/JoltPhysics/issues/2192">#2192</a>)</li>
<li><a
href="1fa0600db9"><code>1fa0600</code></a>
Script to build and view a coverage report</li>
<li><a
href="fd39e122e2"><code>fd39e12</code></a>
Handling of convex/sphere collision/cast checks against degenerate
triangles ...</li>
<li><a
href="bb3e363058"><code>bb3e363</code></a>
HeightFieldShape unit tests (<a
href="https://redirect.github.com/jrouwe/JoltPhysics/issues/2189">#2189</a>)</li>
<li><a
href="fb915d8a9c"><code>fb915d8</code></a>
Fixed crash in MultithreadedTest</li>
<li><a
href="a199f0f4ce"><code>a199f0f</code></a>
Install the shader headers included by HairSettings.h</li>
<li>See full diff in <a
href="5d5275c380...0f69a6b8f0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2026-11-08 12:24:56 +00:00
.devcontainer fix typo 2026-03-22 06:30:30 +00:00
.github Bump pypa/cibuildwheel from 4.3.4 to 4.3.5 in the actions group 2026-10-30 12:14:17 +00:00
docs Fix known bugs (#121) 2026-11-02 19:50:12 +07:00
extern Bump extern/JoltPhysics from 5d5275c to 0f69a6b 2026-11-08 12:12:22 +00:00
profile add profiler tools 2026-04-24 10:57:56 +07:00
src Fix known bugs (#121) 2026-11-02 19:50:12 +07:00
tests Fix known bugs (#121) 2026-11-02 19:50:12 +07:00
tools Minor refactor (#115) 2026-10-23 00:08:56 +07:00
.clang-format Minor refactor (#115) 2026-10-23 00:08:56 +07:00
.clang-tidy Minor refactor (#115) 2026-10-23 00:08:56 +07:00
.clangd Minor refactor (#115) 2026-10-23 00:08:56 +07:00
.gitignore Minor refactor (#115) 2026-10-23 00:08:56 +07:00
.gitmodules Minor refactor (#115) 2026-10-23 00:08:56 +07:00
CMakeLists.txt Minor refactor (#115) 2026-10-23 00:08:56 +07:00
Invoke-LocalCI.ps1 Minor refactor (#115) 2026-10-23 00:08:56 +07:00
LICENSE license in MIT 2026-02-03 12:52:45 +07:00
pyproject.toml Minor refactor (#115) 2026-10-23 00:08:56 +07:00
README.md Expose allowed degrees of freedom for rigid bodies (#102) 2026-08-06 11:29:25 +07:00
tsan.supp add suppression for mi_segment_alloc 2026-04-13 18:36:48 +07:00

Culverin Physics

PyPI - Version Python Version

Culverin is a middleware bridge between the Jolt Physics engine and the Python Virtual Machine. It is designed for 3D games and simulations that require high performance and multi-threaded execution, for the Python game engine developers.

Key Concepts

  • Free-Threading Support: Designed for Python 3.13t and 3.14t. The engine releases the Global Interpreter Lock (GIL) during physics updates and raycast batches.
  • Shadow Buffers: All body positions, rotations, and velocities are stored in contiguous C-arrays. You can access this data via memoryview, NumPy or any dependency that supports the buffer protocol without the overhead of creating Python objects for every body.
  • Thread-Safe API: The engine uses a priority-based locking system. Simulation steps, state mutations, and queries can run on different threads without causing deadlocks or memory corruption.
  • Generational Handles: Bodies are referenced by 64-bit handles rather than pointers. This ensures that using a handle for a deleted object will not crash the program.
  • Double-Precision Positions: Uses double-precision floats (float64) for world positions to prevent physics jitter in massive open worlds, while using float32 for rotations and velocities to save memory and computing resources.

Features

  • Standard Primitives: Box, Sphere, Capsule, Cylinder, and Plane shapes.
  • Complex Shapes: Support for Convex Hulls, Heightfields (Terrain), and static Meshes.
  • Compound Bodies: Create single bodies composed of multiple child shapes.
  • Character Controller: A virtual character controller with built-in support for climbing stairs, sliding down slopes, and pushing objects.
  • Vehicles: Support for wheeled vehicles and tracked vehicles (tanks) with physical treads and skid-steering.
  • Ragdolls & Skeletons: Multi-body articulated physics with active motorized poses.
  • Allowed Degrees of Freedom: Restrict rigid bodies to specific world-space translation and rotation axes, including 2D-style motion.
  • Constraints: Fixed, Point, Hinge, Slider, Distance, Swing-Twist, and Cone constraints.
  • Queries: Efficient single and batch Raycasting, Shapecasting (sweeps), and Overlap queries.
  • Collision Events: Native event buffer for contact added, persisted, and removed events.
  • Soft Bodies: Support for soft bodies from Jolt Physics, with fine-grained configurations.

Installation

pip install culverin

📚 Documentation

Detailed API references for every class and method are available:

Quick Start

import numpy as np

import culverin

# Initialize the world with a capacity limit
world = culverin.PhysicsWorld(settings={"max_bodies": 1000})

# Create a static ground plane
# a plane normal of default (0.577, 0.577, 0.577) represents an infinite 45-degree tilted ramp.
world.create_body(pos=(0, 0, 0), shape=culverin.SHAPE_PLANE, motion=culverin.MOTION_STATIC)

# Create a dynamic box
handle = world.create_body(
    pos=(0, 10, 0), size=(1, 1, 1), shape=culverin.SHAPE_BOX, motion=culverin.MOTION_DYNAMIC
)

# Simulation loop
for _ in range(1000):
    world.step(1 / 60)

    # Zero-Copy Data Access
    # Wrap the internal engine memory in NumPy without copying a single byte.
    # This gives you O(1) access to all 1,000+ bodies at once.
    positions = np.frombuffer(world.positions, dtype=np.float64).reshape(-1, 4)

    # Print the Y position of our box
    idx = world.get_index(handle)
    print(f"Box Height: {positions[idx, 1]:.2f}m")

Technical Specifications

Spec Standard
Units Metric (1.0 = 1 meter)
Coordinate System Right-Handed (Y-Up)
Angle Units Radians
Quaternion Format (x, y, z, w)
Position Buffer Float64 (Stride 4: x, y, z, pad)
Rotation/Velocity Buffers Float32 (Stride 4: x, y, z, w/pad)
Minimum Python 3.12 (3.13t+ recommended for multi-threading)

Performance & Rendering Note

For maximum performance when updating a renderer (like OpenGL or Vulkan), do not loop through individual handles in Python. Instead, use the interpolating export method:

# Returns a single, tightly packed bytes object of Float32s 
# formatted as [px, py, pz, rx, ry, rz, rw] for every active body.
# The 'alpha' parameter (0.0 to 1.0) interpolates between the previous 
# and current physics steps for buttery-smooth rendering.
render_data = world.get_render_state(alpha=0.5)

To read data for gameplay logic, use numpy.frombuffer(world.positions, dtype=np.float64) and numpy.frombuffer(world.rotations, dtype=np.float32) to wrap the internal engine memory without making copies.