MultiplayerBridge
<MultiplayerBridge> bridges the multiplayer context from the parent React tree into the R3F Canvas. This is required when <MultiplayerProvider> is placed outside the <Game> component.
import { MultiplayerBridge } from "@carverjs/multiplayer";Why It's Needed #
CarverJS <Game> renders into an R3F <Canvas>, which uses a separate React reconciler. React contexts from the parent tree — including the MultiplayerContext created by <MultiplayerProvider> — are not automatically available inside the Canvas.
Without <MultiplayerBridge>, hooks like useNetworkEvents, useMultiplayer, and useNetworkState will throw an error when called inside the Canvas because they cannot find the MultiplayerContext.
When to Use #
Use <MultiplayerBridge> when your <MultiplayerProvider> is outside the <Game> component. This is the recommended pattern for games that have lobby/room screens (HTML UI) that need access to multiplayer hooks like useRoom, usePlayers, and useHost before the Canvas is rendered.
You do NOT need <MultiplayerBridge> if your <MultiplayerProvider> is placed inside <Game> (directly in the R3F tree). In that case, the context is already available.
Usage #
import { Game, World, Actor } from "@carverjs/core/components";
import { useGameLoop, useInput } from "@carverjs/core/hooks";
import {
MultiplayerProvider,
MultiplayerBridge,
useRoom,
usePlayers,
useNetworkEvents,
} from "@carverjs/multiplayer";
function App() {
return (
// MultiplayerProvider is OUTSIDE Game — lobby hooks work here
<MultiplayerProvider appId="my-game">
<GameApp />
</MultiplayerProvider>
);
}
function GameApp() {
// These hooks work because we're inside MultiplayerProvider (parent React tree)
const room = useRoom("my-room");
const { players } = usePlayers();
if (room.connectionState !== "connected") {
return <div>Connecting...</div>;
}
return (
<Game mode="2d">
{/* MultiplayerBridge re-provides the context inside the R3F Canvas */}
<MultiplayerBridge>
<World>
<GameScene players={players} />
</World>
</MultiplayerBridge>
</Game>
);
}
function GameScene({ players }) {
// These hooks work because MultiplayerBridge bridges the context into the Canvas
const { broadcast, onEvent } = useNetworkEvents();
useGameLoop((delta) => {
// Game logic using multiplayer events
});
return (
<>
{players.map((p) => (
<Actor key={p.peerId} type="primitive" shape="circle" color="red" />
))}
</>
);
}Props #
| Prop | Type | Description |
|---|---|---|
children | ReactNode | Scene content to render inside the bridged context |
How It Works #
<MultiplayerBridge> reads the MultiplayerContext value from the parent React tree using useContext, then re-provides that same value via a new <MultiplayerContext.Provider> inside the R3F tree. This is a lightweight operation — no data is copied or transformed.
Parent React Tree R3F Canvas Tree
───────────────── ────────────────────────
MultiplayerProvider MultiplayerBridge
└─ context value ──────► └─ re-provides same value
│ │
useRoom (works) useNetworkEvents (works)
usePlayers (works) useMultiplayer (works)Common Patterns #
Pattern 1: Lobby Outside, Game Inside (Recommended) #
<MultiplayerProvider appId="my-game">
{phase === "lobby" && <LobbyScreen />} {/* HTML - useRoom, usePlayers */}
{phase === "game" && (
<Game mode="2d">
<MultiplayerBridge> {/* Bridges context into Canvas */}
<World>
<GameScene /> {/* useNetworkEvents, useMultiplayer */}
</World>
</MultiplayerBridge>
</Game>
)}
</MultiplayerProvider>Pattern 2: Everything Inside Canvas (No Bridge Needed) #
<Game mode="2d">
<MultiplayerProvider appId="my-game"> {/* Already inside Canvas */}
<World>
<GameScene /> {/* Hooks work directly */}
</World>
</MultiplayerProvider>
</Game>