START

The demo app

The public 3D demo. Eight floors, one writer each. The demo's server 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 players on different continents cannot all sit next to the same world. The demo’s own server reads the platform’s country header on the page request and renders the tab with the nearest floor. Control is never on the tap path. ?floor=us forces a floor. India’s floor runs in Singapore, as Fly has no region in India.

Matches and seats

On a public floor a match runs on a clock you pick: 2, 5 or 10 minutes. A private room’s match runs 5 minutes for every member, counted from when it began on the contract. When the clock hits zero you stand up. On a public floor a seat is freed after about 90 seconds without input, 25 seconds after the tab goes to the background, and at once when the tab closes: the page signs your leave() while you sit and hands it to the node as the tab goes.

Private rooms

Create room opens a salon: a lobby behind a code, for 2 to 16 players, in the salon nearest you. Each region has its own salon Room on its own node, and India plays in Singapore’s. A code names its salon (TOKYO-1A2B3C4D; Paris codes are bare, 1A2B3C4D), so a friend anywhere lands in the right one. Send the link, everyone presses Ready, and Begin puts the match on that Room’s floor. A guest who closes the tab before Begin leaves the lobby. One who closes it during the match stands up but stays in the lobby, never ready: after a while the lobby says so and offers a new room.

A salon Room has one floor, so one match plays on it at a time. A match nobody sat down in can be ended by anyone after two minutes, and any match after twenty (expire()). A lobby waiting to begin does it by itself, and so does the demo’s server when it sends a visitor to that salon.

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, and falls back to the eu floor when control cannot tell the region. The public demo picks on its own server instead (see Nearest floor). Your own app has one pair, printed by ship, unless you ship one world per region.

lib/demo.ts
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

app/walk.ts
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]).

components/demo.tsx
<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.