# Physics Backends 3D physics in SimVX runs behind a backend seam: every `PhysicsRoot` builds an isolated `PhysicsWorld`, and which implementation it uses is chosen by a single selection rule. Two backends ship today: | Backend | Package | Notes | |---------|---------|-------| | **BuiltinPhysics** | `simvx-core` (always present) | Pure-Python rigid-body solver. The default. No dependency, runs everywhere including the browser. "Basic tier": approximates some collision/character cases. | | **JoltPhysics** | `simvx-physics-jolt` (opt-in) | Native [Jolt](https://github.com/jrouwe/JoltPhysics) (cffi on desktop, JoltPhysics.js WASM on web). 3D only. Full rigid-body solver, oriented-box collision, characters that push/carry dynamic bodies, high body counts. | `BuiltinPhysics` is the default and needs no setup. The rest of this page is about opting into Jolt. ## Selecting a backend Selection is **explicit**. Installing `simvx-physics-jolt` makes Jolt *available* but does **not** change the default — a solver swap changes gameplay outcomes, so you opt in deliberately. Precedence (highest first): 1. An explicit `PhysicsRoot(backend=...)` on the subtree. 2. The project `physics_backend` setting (`.simvx/config.json`). 3. Otherwise: `BuiltinPhysics`. ### Per-subtree ```python from simvx.core import PhysicsRoot # Every body under this root simulates on Jolt; the rest of the scene is unaffected. root = self.add_child(PhysicsRoot(backend="jolt")) root.add_child(my_dynamic_body) ``` A scene can hold several `PhysicsRoot`s with different backends at once — see `examples/demos/physics_backend_compare.py`, which runs Builtin and Jolt side by side. ### Project-wide Create `.simvx/config.json` at the project root: ```json { "general": { "physics_backend": "jolt" } } ``` Now any body with no explicit `PhysicsRoot(backend=...)` uses Jolt. If the package is not installed, selection falls back to Builtin with a console warning (it never hard-fails). ## What Jolt adds over Builtin - A production rigid-body solver (warm-started contacts, stable stacking). - **Oriented** collision shapes — a rotating box collider actually sweeps, so a spinning paddle herds objects (Builtin's basic tier treats some shapes as axis-aligned). - A character (`CharacterBody3D`) that **pushes and carries** dynamic bodies and is not jammed by them; Builtin's arcade character is one-way (dynamic bodies fall through it). - Throughput for high body counts. 2D is unaffected — Jolt is 3D-only; 2D continues to use Builtin (or the optional `pymunk` backend). ## Installing the desktop backend ```bash # editable / dev install (compiles the vendored Jolt + joltc locally) uv pip install -e packages/physics-jolt --no-build-isolation ``` The package vendors pinned Jolt + joltc C++ sources and builds them via CMake at install time, so an sdist install always works **provided a C++17 compiler and CMake are present** (this is the first SimVX package that requires a compiler; the pure-Python default never does). Useful knobs: - `SIMVX_SKIP_JOLT_BUILD=1` — install the Python without compiling the native extension (Jolt then resolves to unavailable; selection falls back to Builtin). - `SIMVX_REQUIRE_JOLT_NATIVE=1` — fail the install loudly if the native build cannot complete, instead of skipping. A prebuilt **Linux** wheel may be available; it is built with a conservative SIMD baseline (no AVX2) so it runs on older CPUs, at some performance cost. There are no prebuilt macOS/Windows/musl wheels yet (the project runs no CI), so those platforms install from the sdist and need the toolchain above. ## Web export `simvx export web` automatically bundles the JoltPhysics.js (WASM) runtime when the exported game opts into Jolt (it scans the sources for a `backend="jolt"` / `physics_backend` selection). The same explicit-opt-in rule applies; the web default stays BuiltinPhysics (pure Python under Pyodide). ```bash uv run simvx export web examples/demos/waterfall.py -o waterfall.html ``` Web caveats: - Jolt and Pyodide live in separate WASM heaps, so transforms are copied across the boundary once per frame — practical body counts are lower than desktop (a few thousand, not tens of thousands). - No determinism on web (the JoltPhysics.js build has no state recorder). - It is a separate backend that mirrors only the `PhysicsWorld` API, not the desktop build. `examples/demos/jolt_web_showcase.py` is a minimal web Jolt scene; `waterfall.py` and `physics_backend_compare.py` also export to web. ## See also - {doc}`physics` — the collision detection layer. - `examples/demos/waterfall.py` — flagship Jolt showcase (glass mill, spinning paddle, adaptive flow control, framerate tied to the physics tick).