Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
[target.wasm32-unknown-unknown]
runner = "wasm-server-runner"
# Needed for getrandom/uuid: https://github.com/uuid-rs/uuid/issues/792
rustflags = ['--cfg', 'getrandom_backend="wasm_js"']
rustflags = ['--cfg', 'getrandom_backend="wasm_js"']

# macOS: PyO3 cdylibs built with the `extension-module` feature don't link
# against libpython (Python provides those symbols at runtime). `cargo build`
# doesn't know that, so we tell the linker not to fail on the unresolved
# Python symbols. (Maturin handles this for us; this only affects bare
# `cargo build` invocations.)
[target.'cfg(target_os = "macos")']
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
81 changes: 81 additions & 0 deletions .github/workflows/python-bindings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Python bindings

on:
push:
branches: [master]
pull_request:
branches: [master]

env:
CARGO_TERM_COLOR: always

# The four engine packages live under python/rapier-py-{2,3}d{,-f64}; the
# pure-Python testbed under python/rapier-testbed; the shared parity test
# suite under python/tests (imports all four engine packages at once).
jobs:
lint-rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-lint-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-lint-
${{ runner.os }}-cargo-
- name: Cargo fmt
run: cargo fmt --check
- name: Cargo clippy (Python bindings)
run: |
cargo clippy --no-deps \
-p rapier-py-core \
-p rapier-py-2d -p rapier-py-2d-f64 \
-p rapier-py-3d -p rapier-py-3d-f64 \
-- -D warnings

test:
needs: lint-rust
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-py-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-py-
${{ runner.os }}-cargo-
- name: Install tooling
run: |
python -m pip install --upgrade pip
python -m pip install maturin pytest pytest-timeout hypothesis numpy matplotlib
# Build + install all four engine packages into the runner's environment
# so the cross-flavor parity suite can import every variant.
- name: Build & install engine packages
shell: bash
run: |
for crate in rapier-py-2d rapier-py-2d-f64 rapier-py-3d rapier-py-3d-f64; do
python -m pip install --no-build-isolation "./python/$crate"
done
- name: Install testbed (no deps; engine packages already present)
shell: bash
run: python -m pip install --no-deps ./python/rapier-testbed
- name: Smoke (import surface)
run: python -m pytest python/tests/test_smoke.py python/tests/test_math.py python/tests/test_math_2d.py -v
- name: Full parity test suite
run: python -m pytest python/tests/ -q --timeout=120
83 changes: 83 additions & 0 deletions .github/workflows/python-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Python wheels

# Build abi3 wheels for the four engine packages across every supported
# platform and (on a `python-v*` tag) publish them to PyPI via trusted
# publishing.
#
# abi3-py39 means ONE wheel per (package, platform, arch) covers Python 3.9+,
# so there is deliberately no Python-version axis.
#
# NOTE: no sdist is published. The rapier2d/3d engine crates share their
# source via the repo-root `src/` tree (`[lib] path = "../../src/lib.rs"`),
# which lives outside any vendored crate directory, and maturin's sdist
# packer cannot reach parent paths (`..` is rejected in `include`). A source
# build would therefore be incomplete. The wheel matrix below covers all
# mainstream platforms; source builds use a full git checkout of the repo.
# Restoring an sdist is tracked as a follow-up (needs an upstream layout
# change or registry-based engine deps).
on:
push:
branches: [master]
tags: ["python-v*"]
pull_request:
branches: [master]
paths:
- "python/**"
- ".github/workflows/python-wheels.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: wheel ${{ matrix.package.name }} ${{ matrix.platform.target }}
runs-on: ${{ matrix.platform.runner }}
strategy:
fail-fast: false
matrix:
package:
- { dir: rapier-py-3d, name: rapier3d }
- { dir: rapier-py-3d-f64, name: rapier3d-f64 }
- { dir: rapier-py-2d, name: rapier2d }
- { dir: rapier-py-2d-f64, name: rapier2d-f64 }
platform:
- { runner: ubuntu-latest, target: x86_64-unknown-linux-gnu, manylinux: auto }
- { runner: ubuntu-latest, target: aarch64-unknown-linux-gnu, manylinux: auto }
- { runner: ubuntu-latest, target: x86_64-unknown-linux-musl, manylinux: musllinux_1_2 }
- { runner: ubuntu-latest, target: aarch64-unknown-linux-musl, manylinux: musllinux_1_2 }
- { runner: macos-14, target: aarch64-apple-darwin }
- { runner: windows-latest, target: x86_64-pc-windows-msvc }
steps:
- uses: actions/checkout@v4
- name: Build wheel
uses: PyO3/maturin-action@v1
with:
command: build
target: ${{ matrix.platform.target }}
manylinux: ${{ matrix.platform.manylinux }}
args: --release --out dist -m python/${{ matrix.package.dir }}/Cargo.toml
sccache: "true"
- uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.package.name }}-${{ matrix.platform.target }}
path: dist

publish:
name: Publish to PyPI
needs: [build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/python-v')
environment: pypi
permissions:
id-token: write # OIDC for trusted publishing
steps:
- uses: actions/download-artifact@v4
with:
path: dist
pattern: "wheels-*"
merge-multiple: true
- name: Publish all four packages
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist
20 changes: 19 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,22 @@ package-lock.json
.history
.vscode/
*.autosave.json
.claude
.claude

# Python bindings: compiled extension modules that `maturin develop` stages
# next to each package's Python sources (e.g. `_rapier3d.abi3.so`) and the
# Sphinx build output.
python/rapier-py-*/python/**/_rapier*.so
python/rapier-py-*/python/**/_rapier*.pyd
python/rapier-py-*/python/**/_rapier*.dylib
python/docs/_build/
**/__pycache__/
*.pyc
*.egg-info/
dist/
build/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.venv/
venv/
7 changes: 7 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ iit_softfoot = "iit_softfoot"
FoV = "FoV"
# Shepperd's method: named after S. W. Shepperd (quaternion extraction).
Shepperd = "Shepperd"
# Short local identifiers in the Python bindings/tests: `ba` (body a, paired
# with `bb`) and `typ` (a "type" value — `type` is reserved in Rust/Python).
ba = "ba"
typ = "typ"
# Template mesh data in the testbed instancer: `tpos`/`tnrm`/`tidx`
# (template positions/normals/indices). Only `tpos` collides with a word.
tpos = "tpos"

# Case insensitive, matches inside word.
[default.extend-words]
Expand Down
27 changes: 27 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,33 @@ members = [
"crates/rapier3d-meshloader",
"crates/mjcf-rs",
"crates/rapier3d-mjcf",
"python/rapier-py-core",
"python/rapier-py-2d",
"python/rapier-py-2d-f64",
"python/rapier-py-3d",
"python/rapier-py-3d-f64",
]
# Bare `cargo build` / `cargo test` / `cargo clippy` only touches the
# pure-Rust crates. The Python-binding crates need a Python build env
# (pyo3 `extension-module`) and are exercised by the dedicated
# `.github/workflows/python-bindings.yml` workflow via explicit
# `-p rapier-py-*` invocations.
default-members = [
"crates/rapier2d",
"crates/rapier2d-f64",
"crates/rapier_testbed2d",
"crates/rapier_testbed2d-f64",
"examples2d",
"crates/rapier3d",
"crates/rapier3d-f64",
"crates/rapier_testbed3d",
"crates/rapier_testbed3d-f64",
"examples3d",
"examples3d-f64",
"crates/rapier3d-urdf",
"crates/rapier3d-meshloader",
"crates/mjcf-rs",
"crates/rapier3d-mjcf",
]
resolver = "2"

Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,18 @@ The easiest way to get started with Rapier is to:
Their source code are available on the `examples2d/` and `examples3d/` directory.
3. Don't hesitate to ask for help on [Discord](https://discord.gg/vt9DJSW), or by opening an issue on GitHub.

## Python bindings

Python bindings are under development. They ship as four PyPI packages —
`rapier2d`, `rapier3d`, `rapier2d-f64`, `rapier3d-f64` — one per
(dimension, scalar) flavor. See [`python/README.md`](python/README.md) for how
to build the bindings, the docs, and the testbed from a checkout, and
[`python/docs/`](python/docs/) for the API documentation.

## AI coding disclaimer and policy

AI coding is extensively used for the implementation and maintenance of the following crates: `mjcf-rs`, `rapier3d-mjcf`.
AI coding is extensively used for the implementation and maintenance of the following crates: `mjcf-rs`,
`rapier3d-mjcf`, as well as the Python bindings (`python/rapier-py*`), including their tests, examples, and docs.

We actively use AI assistance (with human reviews) for the following tasks:
- Documentation generation.
Expand Down
2 changes: 1 addition & 1 deletion crates/mjcf-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
//!
//! - Simulate anything. Pair this with `rapier3d-mjcf` for that.
//! - Cover MJCF features that are out of scope for `rapier3d-mjcf`. See the
//! `rapier3d-mjcf` planning docs for the complete list.
//! `rapier3d-mjcf` README for the complete list.

#![warn(missing_docs)]

Expand Down
5 changes: 1 addition & 4 deletions crates/rapier3d-mjcf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ robot.insert_using_impulse_joints(&mut bodies, &mut colliders, &mut impulse_join
## Feature matrix

This crate is rolled out in phases. The table tracks what each phase
delivers and the current implementation status. See [`docs/`](docs/) for
the planning rationale.
delivers and the current implementation status.

Legend: ✅ supported · ⚠️ partial / approximated · 📦 preserved as
metadata · ❌ out of scope.
Expand Down Expand Up @@ -172,8 +171,6 @@ convention. (Tracked for a future polish pass.)
- `<compiler coordinate="global">` (deprecated MJCF feature).
- MJCF write-back (the parser is read-only).

See [`docs/04-out-of-scope.md`](docs/04-out-of-scope.md) for rationale.

## Limitations

The mappings noted with ⚠️ above are deliberate trade-offs. In particular:
Expand Down
Loading
Loading