Multiplayer.
Without networking.

Write multiplayer like React state.
Martini keeps clients in sync, across engines and transports.

Declarative like React • Phaser helper today • Transport agnostic • Swap without refactors

Why Martini

Phaser helper available now • Godot adapter in development • More engines on deck

Declarative like React

Define setup, actions, and ticks like components/hooks for networked state. Martini handles validation and sync.

Fewer race conditions, no manual diffing.

Before vs After

Move from brittle socket plumbing to a declarative API. Martini handles validation, ordering, and sync so you keep focus on the game.

Before (manual)
// Manual sockets + reconnection + routing
const socket = new WebSocket(url);
const handlers = {
  move: ({ id, y }) => {
    const p = players[id];
    if (p) p.y = y;
  },
  join: ({ id }) => players[id] = { id, y: 0 },
  leave: ({ id }) => delete players[id],
};

socket.onopen = () => socket.send(JSON.stringify({ type: "join" }));
socket.onclose = () => setTimeout(() => reconnect(), 1000);

socket.onmessage = (msg) => {
  try {
    const { type, ...payload } = JSON.parse(msg.data);
    handlers[type]?.(payload);
  } catch (e) { console.error(e); }
};

function move(y) {
  socket.send(JSON.stringify({ type: "move", y, t: Date.now() }));
}
  • Manual parsing and routing
  • Race conditions and missing reconnection logic
  • No shared structure for engines or transports
  • Protocol rewrites per transport
After (with Martini)
import { defineGame } from "@martini/core";

const game = defineGame({
  setup: () => ({ players: [] }),
  actions: {
    move: (state, id, y) => {
      const player = state.players.find((p) => p.id === id);
      if (player) player.y = y;
    },
  },
  tick: (state) => { /* game loop */ },
});
  • Declarative setup/actions/tick
  • Swap WebSockets ↔ WebRTC/P2P without refactoring
  • Phaser helper today; Godot adapter in development
  • Ordering, validation, reconnection handled

Quick Start

1

Install

npm install @martini/core @martini/phaser
2

Declare Your Game (~15 lines)

Plain objects for state, actions mutate directly. No classes, no RPC wrappers, no serialization chores.

Step 1

Describe state and actions

Declare setup, actions, and tick with plain objects. No RPC or serialization boilerplate.

setup + actions + tick // declarative game spec
Step 2

Martini syncs it

Validation, diffing, ordering, and reconnects handled across WebSockets or WebRTC/P2P.

transport: websocket | webrtc
Step 3

Clients stay in lockstep

Render with Phaser helper today. Godot adapter is in development, with more engines planned.

onChange(state => render(state))
game.ts
import { defineGame } from '@martini/core';

const game = defineGame({
  setup: () => ({
    players: [],
    ball: { x: 400, y: 300, dx: 2, dy: 2 }
  }),

  actions: {
    move: (state, playerId, y) => {
      const player = state.players.find(p => p.id === playerId);
      if (player) player.y = y;
    }
  },

  tick: (state, dt) => {
    state.ball.x += state.ball.dx;
    state.ball.y += state.ball.dy;
  }
});
3

Pick Engine & Transport

Use the Phaser helper today. Godot and other engine adapters are on the way. Swap WebSockets or P2P without refactoring.

4

Develop faster

First-class DX: web IDE, live previews, and built-in dev tools today, with more helpers coming soon.

Comparison Snapshot

FeatureMartini (Phaser today)ColyseusPhotonRuneManual
Declarative game logic✓RPC / manualRPC / manualCustomx
Engine helper✓ (Phaser)~Per-engine SDKsP2P SDKx
Transport choice✓Server WSServer UDP/WSP2P onlyx
Reconnect & ordering✓ManualManualManualx
Bandwidth optimized✓Full state / manualManualBatchedx
Optimistic updates✓ManualManualManualx
Interpolation/reconciliation helpers✓ManualManualManualx
Swap transports without refactor✓Server onlyServer onlyP2P onlyx
Host-authoritative or P2P✓Server onlyServer onlyP2P onlyx
Schema-free state✓ManualManualManualx
Plugin adapters (Godot planned)✓~~~x
Open source✓VariesNoNox
Local-first friendly✓Server onlyServer onlyP2P onlyx

Build in minutes

Ready to build multiplayer?

Ship real-time games with clean, readable code. Declarative logic, flexible transport, and a Phaser helper today (more adapters coming).