# Netcode in Net Forge: authority, prediction, reconciliation and snapshots

> The server runs the simulation and decides what happened. Each browser predicts its own player with the same simulation, reconciles when the server's snapshot arrives, and interpolates everyone else. Inputs are sequence-numbered and sent with redundancy; snapshots are bit-packed deltas.

Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under `@netforge` with source at https://github.com/netnetdev/net-forge.

Source: https://forge.netnet.capital/docs/concepts/netcode-prediction  
Last updated: 2026-10-23. Checked against @netforge/engine 0.2.0.

In a Net Forge game the server runs the simulation and is the only authority on what happened. Each browser predicts its own player with the same simulation code so input feels instant, reconciles to the server's state when a snapshot arrives, and draws every other entity slightly in the past by interpolating between snapshots.

You get all of this by starting from any template; none of it lives in `src/game.ts`.

```sh
npm create netforge@latest my-game -- --template arena --yes
cd my-game
npm run play -- --players 2
```

## The loop, step by step

| Step | Where | What happens |
|---|---|---|
| Sample input | browser | Each frame's input becomes an `InputCommand` with a rising `seq`, quantized so both sides read identical values. |
| Predict | browser | `Predictor.predict` applies it to the local world at once and keeps it until the server acknowledges it. |
| Send | browser | An input packet carries the newest command plus the last few unacknowledged ones (`REDUNDANCY = 4`), so a lost packet costs nothing. |
| Queue | server | A per-player `InputQueue` buffers commands (16 deep, with credits that stop a client from sending faster than real time). |
| Step | server | The room steps the world at a fixed tick (30 Hz by default, 60 Hz in the arena, racer and platformer templates) with every player's command for that tick. |
| Snapshot | server | Each player gets a delta snapshot against the last state they acknowledged, filtered to what is near them, with the `seq` the server last applied. The local host sends 20 a second. |
| Reconcile | browser | `Predictor.reconcile` resets the player to the server's state and replays the commands the server has not applied yet. A disagreement is shown as an offset that fades over about 100 ms instead of a snap. |
| Interpolate | browser | `InterpolationBuffer` holds recent snapshots and samples remote entities between two of them, so other players move smoothly. |

## Why the same simulation matters here

Prediction only works if the client's guess matches what the server will compute. In Net Forge the client predicts with the server's own step function from [@netforge/engine-sim](https://forge.netnet.capital/docs/concepts/simulation-ecs.md), on bit-identical quantized inputs, so a correction happens only when something the client could not know (another player, a hit) changed the outcome. Prediction itself is a well-known technique (Gabriel Gambetta's [Fast-Paced Multiplayer](https://www.gabrielgambetta.com/client-server-game-architecture.html) series is the usual reference, and other frameworks such as [Colyseus](https://docs.colyseus.io/) offer it too). What Net Forge adds is that you never write the step function twice.

## Snapshots on the wire

Snapshots are schema-driven and bit-packed. Each entity kind declares its fields (`EntitySchema`), each field is quantized to its own precision, and a delta snapshot writes only the fields that changed since the acknowledged baseline. `SnapshotHistory` keeps the baselines on the sending side; a receiver asked to decode a delta against a baseline it does not have gets a `BaselineMissingError` instead of a wrong state.

## The SimAdapter seam

Every template exposes its game to the netcode through one interface, `SimAdapter<W, I>`: create a world, add and remove players, step one tick with each player's inputs, snapshot and restore entities, and say how inputs are encoded. The room host, the predictor and the playtest bots all drive the game through it, which is why a board game like the card battler and an action game like the arena shooter share the same netcode. See the [SimAdapter reference](https://forge.netnet.capital/docs/reference/engine-net.md#simadapter).

```ts title=inspect.ts
import type { SimAdapter, InputCommand } from "@netforge/engine/net";
import { REDUNDANCY, DEFAULT_INPUT_QUEUE } from "@netforge/engine/net";

function describe<W, I>(sim: SimAdapter<W, I>): string {
  return `${sim.name} v${sim.version}: ${sim.tickHz} Hz, ${REDUNDANCY} commands per packet, queue ${DEFAULT_INPUT_QUEUE.maxQueue}`;
}

type Move = InputCommand<{ moveX: number; moveZ: number }>;
export type { Move };
console.log(typeof describe);
```

## What runs where

| Piece | Public packages | Hosted Net Forge room server |
|---|---|---|
| Prediction, reconciliation, interpolation, input packets, delta snapshots | yes (`@netforge/engine/net`) | yes |
| Authoritative fixed-tick loop with per-player delta snapshots and area of interest | yes, in `@netforge/kit-play`'s local host | yes |
| Lag compensation (rewinding hitboxes to what the shooter saw) | no; the local host resolves hits against current hitboxes, which is exact at local latency | yes |
| Run logs, replay verification, the referee | no | yes |

The room transport is [Colyseus](https://docs.colyseus.io/): the client uses the Colyseus SDK and the local host is built on `@colyseus/core`.

## FAQ

### Does Net Forge have client-side prediction?

Yes. The local player is predicted with the same simulation the server runs, and reconciled against each snapshot by replaying unacknowledged inputs. Corrections are smoothed over about 100 ms.

### Is Net Forge server-authoritative?

Yes. The server steps the world and decides every hit, kill and pickup. Clients only predict their own player and display what the server sends.

### Does Net Forge do lag compensation?

The hosted room server rewinds hitboxes for hitscan weapons. The local host in `@netforge/kit-play` does not, because on one computer or one network there is almost no latency to compensate.

### How often does the server send snapshots?

The simulation ticks at 30 Hz by default and at 60 Hz in the arena, racer and platformer templates. The local host sends each player a delta snapshot 20 times a second, filtered to the entities near that player.

### Does Net Forge use WebSockets or WebRTC?

WebSockets, through Colyseus's transport.

### Do I need to write netcode for my game?

No. A game is declared in `src/game.ts`, and the template supplies the netcode through its `SimAdapter`. You only touch `@netforge/engine/net` when you write a new template.
