Silt

Built on WebTransport — UDP-class datagrams, in the browser

Infrastructure for browser multiplayer

Real-time game servers that scale to zero and wake in ~70ms — with rooms, relay, and presence handled, and no netcode to write.

server · room.ts
// your whole server — Silt runs the loop
import type { Room } from "@siltrun/room";

export default {
  tick(state = { players: {} }, inputs) {
    for (const ev of inputs) {
      if (ev.kind === "join")  add(state, ev.id);
      if (ev.kind === "leave") drop(state, ev.id);
      if (ev.kind === "input") move(state, ev);
    }
    return state;  // broadcast to everyone
  },
} satisfies Room<{ players: Record<PlayerId, Drifter> }>;
client · app.tsx
// your frontend — join a room, stream presence
import { joinRoom } from "@siltrun/client";

const room = await joinRoom(url, { id });
// draw peers as their presence datagrams arrive
room.on("presence", (id, s) => draw(id, s));
room.on("join",  (peer) => add(peer.id));
room.on("leave", (id) => remove(id));

// broadcast your own cursor at ~20Hz
setInterval(() => {
  room.presence.set({ x, y, heading });
}, 1000 / 20);
cli · dev
$ siltrun dev room.ts silt room live (compute mode)room infohttp://localhost:4000wt endpointhttps://127.0.0.1:4433determinism✔ ok
reloaded room.tswatching room.ts — edit to reload

Drive the relay yourself — two live browsers on one connection.

Go live and move your cursor in one browser — your motion turns into real presence datagrams that cross the relay into the other browser as they happen. The relay and room read out the actual throughput moving between them. None of it is simulated — it’s the platform running on itself, live.

Now try a real game — Drift is online.

Hit play and you’re flying. Share the URL and anyone who clicks lands in the same arena — no install, no account, no lobby.

  • Dogfight and race other players in real time.
  • Drift’s server runs on Silt — the platform running its own demo.
  • Scales to zero when idle, then wakes on the first packet in ~70ms.

Your first room in three commands.

Scaffold a project, install it, and run it locally. It’s one TypeScript room file, with no netcode to write and no server to stand up.

Every package here is public on npm. Nothing to sign up for.

Three commands, running locally.

terminal
$ npm create siltrun@latest my-room # scaffold a room + client
$ cd my-room && npm install # pull the packages from npm
$ npm run dev # play it locally, in two tabs

Or join a room by URL, set your presence state, listen for everyone else’s.

hello-room.ts
// join a room by URL — one WebTransport connection
import { joinRoom } from "@siltrun/client";

const room = await joinRoom(
  "https://your-relay.example/room/lobby", { id });

// others' positions stream in on the datagram lane
room.on("presence", (peerId, state) => draw(peerId, state));

// broadcast yours — latest-wins, ~20Hz, droppable
room.presence.set({ x, y, heading });
The real @siltrun/client API, published on npm.
The Platform

Deploy realtime servers to the edge — on UDP, not HTTP.

Write a room’s logic like a Cloudflare Worker, get presence and events like Liveblocks — one TypeScript file, no netcode.

Your TypeScript contract runs in a microVM at the edge
Routed by Connection-ID to the room’s microVM
Rooms scale to zero and wake on the first packet — ~70ms server-side restore
One connection, two lanes: droppable ~20Hz presence, ordered events
room.ts
import type { Room } from "@siltrun/room";

const clamp = (v: number) => Math.max(0, Math.min(520, v));

export default {
  tick(state = { ships: {} }, inputs) {
    for (const ev of inputs) {
      if (ev.kind === "join")  state.ships[ev.id] = { x: 260, y: 140 };
      if (ev.kind === "leave") delete state.ships[ev.id];
      if (ev.kind === "input") {
        const s = state.ships[ev.from];
        if (s) { s.tx = clamp(ev.data.x); s.ty = clamp(ev.data.y); }
      }
    }
    for (const id in state.ships) {
      const s = state.ships[id];
      if (s.tx == null || s.ty == null) continue;
      s.x += (s.tx - s.x) * 0.1;
      s.y += (s.ty - s.y) * 0.1;
    }
    return state;
  },
} satisfies Room<State, Cmd>;
$ npx siltrun login  # sign in with GitHub
$ npx siltrun deploy room.ts
https://<name>.silt.run/room/<room>  # limited beta capacity
Cold start

Scale to zero. Wake in ~70ms.

Your room runs in a Firecracker microVM: nothing to run or pay for while it’s idle, and the first packet wakes it in ~70ms — before the player feels it.

wake trace — one compute room
phase view · widths not to scale
SCALE TO ZEROsnapshot on disk · 0 costfirst packet~70msRESTORELIVEpresence + events · ~20Hz
asleep · 0 cost
end-to-end first join~250–500ms browser → playing
~70ms server-side microVM restore measuredconnect, route, and first tick, browser-side varies with distance
  • Snapshot restore, not a cold boot — resume a frozen VM from a memory image.
  • A real KVM guest per compute room — hardware-isolated, not a shared language isolate.
  • No warm pool — nothing is pre-provisioned sitting idle waiting for traffic.
Compare

Silt versus the alternatives.

Every alternative forces a trade-off; Silt doesn’t. Both lanes over one WebTransport connection, rooms that scale to zero, and none of the QUIC plumbing to run.

capability
Plain WebSocket
ws://
HTTP serverless
CF Workers
Server fleets
Agones
Silt
WebTransport
Unreliable datagram lane
presence · latest-wins · ~20Hz
HOL-blocks under loss
no datagram path
raw UDP, self-run
presence lane
Reliable ordered lane
events · ordered · delivered
the only lane
request/response
DIY
events lane
Both lanes, one connection
the two-lane model
one lane only
one lane at best
DIY, two sockets
core differentiator
True scale-to-zero
nothing running when idle
always-on server
HTTP only
coarse warm fleets
wake-on-packet
Cold wake ~70ms
server-side VM restore, measured
persistent
JS isolates
fleet warmup
~70ms restore
Passes UDP datagrams
end to end, not terminated
TCP only
HTTP front door
raw UDP
QUIC / WebTransport
Zero QUIC / cert / routing
no plumbing to operate
you run it
managed, no UDP
you run the fleet
fully managed
supportedpartial / DIYnot possiblen/a
What we’re building

Ship a multiplayer server like you ship a function.

Push a room’s logic, get a URL, and watch it run — waking on the first player, scaling to zero when the last one leaves.

Live today, and building the rest with you.

Come tell us what you’re building. Want one email at launch and nothing else?Join the launch list.

Roadmap
2026
  • Relay dataplane, compute rooms, and Driftlive todayshipped
  • The SDK and CLI on npm — npm create siltrun scaffolds a roomlive todayshipped
  • Hosted deploy: sign in with GitHub, then siltrun deploy room.ts returns a room URLcapacity-limited during the betashipped
  • A console at console.silt.run: your rooms, their status, and their live statelive todayshipped
  • Metrics in the console: presence throughput and cold-start timesnot built yetplanned
  • Interest management — ~20–25 players/room today, aiming for ~100worlds shard across roomsplanned
  • Scale to thousands of rooms with no infra to runnot even a warm poolplanned
Measured live: ~70ms cold-start restore, ~290-byte presence packets.

Start free today, or back the build.

Web multiplayer should have had real infrastructure years ago. WebTransport finally makes it possible, and Silt is building it. The packages are on npm and free to build with; preorder founding‑member access to help make the rest real.

Where the build is

Relay dataplanemeasured live under load
Drift — the live demoplayable now
@siltrun/client SDKlive on npm
Compute roomslive in the demo
Self-serve hosted deployssign in with GitHub; capacity-limited during the beta
Launch list — free
One email when Silt launches for real. No other mail.

Founding member

What you get
Founding-member status
$49 rate locked for future paid plans
First year of the hobby tier, free at launch
One-time total
A preorder — this funds the build, not a finished product.
$49
Back Silt — $49checkout via Polar

Frequently asked questions

Straight answers to the common questions.