The demo app
The public 3D demo. Eight floors, one writer each. The tab picks the nearest. Do not point your app at that node.
This is the public demo at demo.interludelayer.xyz/room. Two browsers on the same floor, one contract. A step is a call. The other tab sees it because the engine already has it.
Eight floors, not eight replicas. One writer per contract, so a Brazilian and a Parisian cannot share one world at 20 ms. The tab asks control which region is nearest, then uses that floor. Control is never on the tap path. ?floor=us forces a floor.
Ask for the nearest floor
createInterludeClient does not choose a node. The SDK helper nearestFloor() asks control which region is closest, then returns that pair. The public demo does this. Your own app has one pair, printed by ship, unless you ship one world per region.
import { createPublicClient, http } from "viem";
import { monadTestnet } from "viem/chains";
import { createInterludeClient, nearestFloor } from "@interludelayer-sdk/sdk";
import { demoAbi } from "./demo-abi";
const floor = await nearestFloor();
export const interlude = createInterludeClient({
app: floor.app,
abi: demoAbi,
node: floor.node,
base: createPublicClient({
chain: monadTestnet,
transport: http("https://testnet-rpc.monad.xyz"),
}),
});
// Several of your own worlds:
// await nearestFloor({
// eu: { app: "0xYOUR_EU", node: "https://YOUR_EU_NODE" },
// us: { app: "0xYOUR_US", node: "https://YOUR_US_NODE" },
// });A session, then a step
const session = await interlude.openSession({
wallet,
scope: ["join", "move", "jump", "hit", "leave"],
});
await session.send("join");
await session.send("move", [1]);The same thing in React
Bind the hooks next to the client. The canvas only calls join.send() and move.send([dir]).
<InterludeProvider wallet={wallet} scope={["join", "move", "jump", "hit", "leave"]}>
<Floor />
</InterludeProvider>
function Floor() {
const { session, open } = useSession();
const join = useSessionCall("join");
const move = useSessionCall("move");
if (!session) return <button onClick={() => open()}>Enter</button>;
return (
<>
<button onClick={() => join.send()}>Join</button>
<button onClick={() => move.send([1])}>East</button>
</>
);
}Open two tabs on the demo. Walk in both. The other tab sees you before Monad does. That client talks to a public demo node, not to the URL ship prints for your app.
