{"id":51541964,"url":"https://github.com/forge18/love-rapier","last_synced_at":"2026-07-09T14:30:45.151Z","repository":{"id":365071429,"uuid":"1270474491","full_name":"forge18/love-rapier","owner":"forge18","description":"A LuaJIT FFI binding to Rapier2D — full-featured 2D rigid-body physics for LÖVE.","archived":false,"fork":false,"pushed_at":"2026-06-15T18:55:00.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T19:32:49.562Z","etag":null,"topics":["2d-physics","ffi","game-development","love2d","lua","luajit","physics","physics-engine","rapier","rapier2d","rigid-body-dynamics"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/forge18.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-15T18:44:15.000Z","updated_at":"2026-06-15T18:55:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/forge18/love-rapier","commit_stats":null,"previous_names":["forge18/love-rapier"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/forge18/love-rapier","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forge18%2Flove-rapier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forge18%2Flove-rapier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forge18%2Flove-rapier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forge18%2Flove-rapier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/forge18","download_url":"https://codeload.github.com/forge18/love-rapier/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forge18%2Flove-rapier/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35303290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2d-physics","ffi","game-development","love2d","lua","luajit","physics","physics-engine","rapier","rapier2d","rigid-body-dynamics"],"created_at":"2026-07-09T14:30:42.646Z","updated_at":"2026-07-09T14:30:45.140Z","avatar_url":"https://github.com/forge18.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# love-rapier\n\nA [LÖVE](https://love2d.org) 2D physics binding for **[Rapier2D](https://rapier.rs)** via LuaJIT FFI.\n\n\u003e **⚠️ Alpha.** The binding is feature-complete — the full Rapier2D surface is bound — and the test\n\u003e suite runs in CI on macOS, Linux, and Windows. But it's new and hasn't been battle-tested across\n\u003e all platforms in real projects yet. Expect rough edges; please report anything you hit.\n\n## Overview\n\nRapier runs as a native shim (a small Rust `cdylib`); the Lua side is a thin, idiomatic wrapper. No\n`love.physics` / Box2D involved.\n\nThe reason to use it over Box2D is **determinism**: with Rapier's `enhanced-determinism`, a given\nsequence of steps yields bit-identical results across runs and platforms — the foundation for\nlockstep simulation, replays, and rollback netcode — plus more performance headroom. The shim pins\n`rapier2d = 0.33`.\n\nRun `love .` from this repo for a demo (drive a ball; it collides with walls and other balls).\n\n## Functionality\n\nThe Rapier 2D surface is bound in full. By area:\n\n- **Bodies** — dynamic / fixed / kinematic; linear \u0026 angular velocity, impulses, forces and torque\n  (including at-a-point), damping, gravity scale, CCD / soft-CCD, sleeping, axis locks, full-pose\n  set, mass and custom mass properties.\n- **Colliders** — ball, cuboid, capsule, triangle, segment, polyline, convex hull, heightfield;\n  friction / restitution / density / mass, sensors, collision \u0026 solver groups, parent offsets,\n  in-place shape swap, configurable events.\n- **Queries** — raycast (plus surface normal, plus group filtering), point, shape-cast, point\n  projection, circle / shape overlap, narrow-phase contacts \u0026 intersections, and contact-manifold\n  geometry (normal, point, depth).\n- **Joints** — fixed, revolute, prismatic, rope, spring — as impulse *or* multibody — with motors\n  and limits.\n- **Character controller** — kinematic move-and-slide for any shape, with a grounded report.\n- **Events** — collision, sensor, and contact-force events.\n- **Physics hooks** — contact / intersection pair-filter callbacks.\n- **Serialization** — full-world snapshot / restore (deterministic save states; rollback netcode).\n- **Debug render** — Rapier's own debug line geometry.\n\nThe complete method-by-method reference is in **[docs/api.md](docs/api.md)**.\n\n\u003e **Not available in 2D: gyroscopic forces.** `RigidBody::enable_gyroscopic_forces` is gated\n\u003e `#[cfg(feature = \"dim3\")]` in Rapier's shared codebase, so it's compiled out of `rapier2d`\n\u003e entirely — the method doesn't exist in the 2D build, and no 2D binding can expose it. It's a\n\u003e 3D-only effect (precession of a spinning body); 2D angular motion is a single scalar axis where it\n\u003e has no meaning.\n\n## Setup\n\nIt's a native binding, so a consuming game needs two things:\n\n1. **The Lua module** — copy `rapier/` into your project so `require(\"rapier.system\")` resolves.\n   It's a folder module, so your require path must include `?/init.lua` (LÖVE's default already does).\n2. **The native library** for each platform you ship, placed at `lib/native/\u003cplatform\u003e/`:\n   - `macos-arm64/librapier_shim.dylib`, `macos-x86_64/librapier_shim.dylib`\n   - `linux-x64/librapier_shim.so`\n   - `windows-x64/rapier_shim.dll`\n\n   Prebuilt binaries are attached to each GitHub Release (and committed under `lib/native/`). The\n   loader (`rapier/ffi.lua`) resolves `\u003csource\u003e/lib/native/\u003cplatform\u003e/\u003clibname\u003e` — under LÖVE that's\n   `love.filesystem.getSource()`, otherwise the cwd (or `$RAPIER_ROOT`).\n\n## Usage\n\nThe `rapier.system` adapter adds a fixed-timestep loop, event dispatch, and debug drawing:\n\n```lua\nlocal Physics = require(\"rapier.system\")\n\nfunction love.load()\n  phys = Physics.new({ fixedDt = 1/60 })\n  phys:addStatic(400, 300, { kind = \"cuboid\", hx = 60, hy = 60 })       -- map geometry\n  player = phys:newActor(\"dynamic\", 150, 150, { kind = \"ball\", radius = 16 })\n  phys:onCollision(function(e) --[[ e.a, e.b colliders; e.started; e.sensor ]] end)\nend\n\nfunction love.update(dt)\n  phys.world:setLinvel(player, vx, vy)   -- or :applyImpulse / :drive(force) for steering\n  phys:update(dt)                        -- fixed-timestep accumulator; dispatches events\nend\n\nfunction love.draw() phys:debugDraw() end\n```\n\nFor the raw world without the adapter, use `require(\"rapier\")` directly:\n`local world = require(\"rapier\").newWorld()`. See [docs/api.md](docs/api.md).\n\nOne gotcha: spatial queries reflect the broad phase **as of the last `step()`** — query a\nfreshly-built, never-stepped world and it sees nothing, so step once first (a running game steps\nevery frame).\n\n## Building\n\nThe shim is a Rust crate (`native/rapier_shim`). `scripts/build-native.sh` cross-builds all four\nplatforms from one host — native cargo for macOS, mingw-w64 for Windows, `cargo-zigbuild` for Linux —\ninto `lib/native/\u003cplatform\u003e/`. Requires Rust, `cargo-zigbuild` + zig, and mingw-w64. Build a single\nplatform with e.g. `scripts/build-native.sh macos-arm64`.\n\n**Tests** (`tests/`) are integration-level — they load the real compiled binary over FFI and exercise\nthe whole surface (forces, collisions, sensors, queries, joints, the character controller, hooks,\nsnapshot/restore, and bit-identical determinism). They run under **LuaJIT** from the repo root:\n\n```sh\nscripts/build-native.sh macos-arm64   # build the host shim first\nluajit tests/run.lua                  # dependency-free runner (no luarocks/busted needed)\n```\n\n(The tests are also busted-compatible — `busted` runs them too — but the bundled runner needs nothing\nbut LuaJIT, which sidesteps luarocks's manifest not loading under LuaJIT.)\n\nCI (`.github/workflows/build.yml`) runs the suite on **all four platforms** — each building and\nexecuting its own native binary — and gates the release build on it.\n\n## License\n\nlove-rapier (the wrapper + shim) is MIT — see `LICENSE`. The compiled binary links **Rapier2D**,\nwhich is Apache-2.0; retain its notice when redistributing the binaries.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforge18%2Flove-rapier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforge18%2Flove-rapier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforge18%2Flove-rapier/lists"}