Server authority & validation

Authority is a spectrum, and irt.io lets you dial it per entity. At the low end, a validator lets you keep client ownership but still refuse impossible writes. At the high end, a tick loop lets the server simulate the whole game.

Validators

A validator runs on the server for every write to an entity before it’s broadcast. Return the corrected value, or throw to reject.

export default defineRoom(schema, {
  validate: {
    players(prev, next, ctx) {
      // clamp movement to a sane speed — no teleporting
      const maxStep = 12;
      next.x = clamp(next.x, prev.x - maxStep, prev.x + maxStep);
      next.y = clamp(next.y, prev.y - maxStep, prev.y + maxStep);
      return next;
    },
  },
});

The client still owns the value — this is a cheap guardrail, not a takeover.

The tick loop

For continuous simulation (physics, projectiles, timers), give the room a tick. It runs at a fixed rate on the server, holds the authoritative state, and its writes sync to everyone.

export default defineRoom(schema, {
  tick(state, dt) {
    for (const b of Object.values(state.bullets)) {
      b.x += b.vx * dt;
      b.y += b.vy * dt;
      if (offscreen(b)) delete state.bullets[b.id];
    }
  },
});

Client inputs arrive as RPCs or owned writes; the tick turns them into authoritative outcomes.

Reconciliation

When the server corrects a client-owned value, the SDK reconciles it smoothly on the client (no rubber-banding for small corrections). You can opt into client-side prediction per entity for input-sensitive movement.

Next steps

Placeholder content.