An engine-like runtime kernel for React Three Fiber (R3F).
react-three-eris exists because many R3F apps eventually want "game engine" structure:
- deterministic ordering (no scattered
useFramecalls) - fixed-step simulation for authoritative gameplay
- explicit, manually-stepped physics (Rapier)
- clear boundaries between simulation, physics, rendering, and React
This repo is a pnpm workspace monorepo with a small core library plus optional adapters and example apps.
R3F is an excellent renderer and scene authoring layer, but it is not an engine loop.
If every feature owns its own useFrame, you tend to get:
- unpredictable ordering issues ("why is the camera one frame behind?")
- mixed fixed/variable timestep logic
- physics stepping that depends on render framerate
- hard-to-debug feedback loops between React state and simulation
react-three-eris puts a minimal orchestration layer around R3F:
- the engine owns time and phase ordering
- apps register systems to phases
- React mounts a single adapter component (
EngineLoop) to drive the engine - physics is stepped manually inside the fixed loop (physics-authoritative by default)
It stays "framework-light": no scene graph ownership, no UI opinion, no enforced ECS.
The reusable library:
createEngine/Engine: fixed-step scheduler, phase ordering, net hooksPhase,SystemtypesEngineLoop: React Three Fiber adapter (one hook-in)- Physics module boundary with a Rapier implementation (optional)
- Net driver boundary with a noop default (planned for future networking)
Core idea: systems subscribe to exactly one phase:
preFrame: input/net polling, command bufferingfixed: authoritative gameplay step (fixed dt)postPhysicsFixed: interpret contacts/triggers after stepping physicsupdate: variable-rate non-authoritative systemslate: camera/presentation smoothingrenderApply: write to Three objects (receivesalphafor interpolation)
An optional ECS adapter for react-three-eris using miniplex.
Rationale:
- keep the core engine ECS-agnostic
- provide a small bridge for teams that want a lightweight ECS without rewriting the loop
Example app (separate Vite + React + R3F project) that consumes the library via workspace:*.
Demonstrates:
- registering systems instead of
useFramefor simulation - fixed-step movement intent (WASD)
- minimal Rapier setup under engine ownership
react-three-eris/
packages/
eris/
eris-ecs-miniplex-adapter/
basic-character/
tests/
docs/
Package-specific docs live in docs/packages/*.
Requirements:
- Node.js (recent)
- pnpm (see
package.json"packageManager")
Install:
pnpm installRun the example:
pnpm devTypecheck:
pnpm typecheckRun tests (Vitest):
pnpm testThis is early-stage and intentionally minimal. The goal is a solid runtime boundary and phase model that can scale up (netcode, rollback, tooling) without turning the library into a full engine.