Contributing to forge3d¶
Thank you for your interest in contributing!
Quick start¶
Package name vs import name
The PyPI distribution is named pyforge3d, but you always import forge3d in code.
Workflow¶
- Fork the repo and create a feature branch:
git checkout -b feat/my-feature - Write your changes and corresponding tests
- Make sure the checks below pass
- Open a PR — one PR per logical change
Checks (must all pass)¶
ruff check . && ruff format --check . # lint + format
mypy src/ # type checking
pytest tests/ -q # test suite
Rules¶
Physics code¶
- Every new formula needs a unit test that checks against an analytical solution,
a conservation law (energy / momentum), or a PyBullet/MuJoCo baseline (
validation/directory). - No in-place mutation of arrays. Use
dataclasses.replace(body, vel=new_vel). - Must run correctly under both
ENGINE_BACKEND=numpyandENGINE_BACKEND=jax.
Renderer¶
- Physics core (
math/,dynamics/,collision/,contact/,model/,sim/) must never import renderer code. - The only allowed bridge is
SceneSnapshot(pure data).
Public API¶
- New public concepts require an entry in
__all__insrc/forge3d/__init__.py. - New public concepts need a usage example in
examples/(≤ 15 lines).
Forbidden¶
- External physics engines in
src/forge3d/(MuJoCo, PyBullet, Bullet, etc.). They are allowed only invalidation/for baseline comparison. - GPU/CUDA dependencies for physics or learning code.
Code style¶
- ruff for lint and formatting (line length 100).
- Type annotations on all public functions.
- Comments only when the why is non-obvious.
- No docstrings for trivial getters / setters.
Commit style¶
feat(collision): add sweep-and-prune broad-phase
fix(contact): clamp Baumgarte correction to avoid tunnelling
docs(readme): add App-style game loop example
test(physics): add conservation test for capsule-capsule
Questions?¶
Open an issue or start a Discussion on GitHub.