Skip to content

@gameable/net ​

Classes ​

abstract BaseTransport ​

The base every transport extends: the listener lists and the closed latch.

A subclass feeds frames in with deliver, reports the far side going away with finish, and says how to tear down its own pipe in shutdown.

Example ​

ts
import { BaseTransport } from 'gameable/net';
class Echo extends BaseTransport {
  readonly bufferedAmount = 0;
  send(data: string | Uint8Array): void {
    if (!this.isClosed) this.deliver(data);
  }
  protected shutdown(): void {}
}
const echo = new Echo();
echo.onMessage((data) => console.log(data));
echo.send('hello');

Implements ​

Constructors ​

Constructor ​
ts
new BaseTransport(): BaseTransport;
Returns ​

BaseTransport

Properties ​

bufferedAmount ​
ts
abstract readonly bufferedAmount: number;

Bytes queued to send and not yet written out; a sender can skip a binary frame while this is high.

Implementation of ​

Transport.bufferedAmount

Accessors ​

isClosed ​
Get Signature ​
ts
get protected isClosed(): boolean;

Whether the transport has closed, from either end.

Returns ​

boolean

Methods ​

close() ​
ts
close(reason?): void;

Closes the transport. Safe to call twice; the close listeners fire once.

Parameters ​
ParameterTypeDefault value
reasonstring'closed'
Returns ​

void

Implementation of ​

Transport.close

deliver() ​
ts
protected deliver(data): void;

Hands one received frame to every message listener; nothing after close.

Parameters ​
ParameterType
dataTransportData
Returns ​

void

finish() ​
ts
protected finish(reason): void;

Latches closed and fires the close listeners, once however often it is called.

Parameters ​
ParameterType
reasonstring
Returns ​

void

onClose() ​
ts
onClose(cb): void;

Registers a listener for the close, called once with the reason. Registering after close does nothing.

Parameters ​
ParameterType
cb(reason) => void
Returns ​

void

Implementation of ​

Transport.onClose

onMessage() ​
ts
onMessage(cb): void;

Registers a listener for every frame received. Registering after close does nothing.

Parameters ​
ParameterType
cb(data) => void
Returns ​

void

Implementation of ​

Transport.onMessage

send() ​
ts
abstract send(data): void;

Sends one frame. After the transport is closed this does nothing.

Parameters ​
ParameterType
dataTransportData
Returns ​

void

Implementation of ​

Transport.send

shutdown() ​
ts
abstract protected shutdown(reason): void;

Tears down the underlying pipe; called once, by the first close.

Parameters ​
ParameterType
reasonstring
Returns ​

void


abstract FrameCodec ​

Little-endian reads over a byte array, and the frame-kind check every binary frame starts with.

Example ​

ts
class PingCodec extends FrameCodec {
  decode(bytes: Uint8Array): number | null {
    return this.isKind(bytes, 9, 5) ? this.u32(bytes, 1) : null;
  }
}

Extended by ​

Constructors ​

Constructor ​
ts
new FrameCodec(): FrameCodec;
Returns ​

FrameCodec

Methods ​

clampInt() ​
ts
protected clampInt(
   value, 
   min, 
   max
): number;

value rounded and clamped, for an integer wire field.

Parameters ​
ParameterTypeDescription
valuenumberAny number.
minnumberThe least result.
maxnumberThe greatest result.
Returns ​

number

The rounded value in [min, max]; 0 for a non-finite value.

f32() ​
ts
protected f32(bytes, offset): number;

The little-endian 32-bit float at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

The float, which may be NaN or infinite on a hostile frame.

i16() ​
ts
protected i16(bytes, offset): number;

The signed 16-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with two bytes in range.
Returns ​

number

A value in [-32768, 32767].

i32() ​
ts
protected i32(bytes, offset): number;

The signed 32-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

A signed 32-bit value.

i8() ​
ts
protected i8(bytes, offset): number;

The signed byte at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn in-range offset.
Returns ​

number

A value in [-128, 127].

isKind() ​
ts
protected isKind(
   bytes, 
   kind, 
   length, 
   exact?
): boolean;

Whether bytes is a frame of kind and the right length.

Parameters ​
ParameterTypeDefault valueDescription
bytesUint8ArrayundefinedThe received frame.
kindnumberundefinedThe expected first byte.
lengthnumberundefinedThe frame's length, or its least length when exact is false.
exactbooleantrueWhether the length must match exactly.
Returns ​

boolean

True when the length fits and the first byte is kind.

u16() ​
ts
protected u16(bytes, offset): number;

The unsigned 16-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with two bytes in range.
Returns ​

number

A value in [0, 65535].

u32() ​
ts
protected u32(bytes, offset): number;

The unsigned 32-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

An unsigned 32-bit value.

u8() ​
ts
protected u8(bytes, offset): number;

The unsigned byte at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn in-range offset.
Returns ​

number

A value in [0, 255].


InputCodec ​

Encodes and decodes input frames. Owns the one header object decode returns, so a decode allocates nothing.

Example ​

ts
const keys = () => new Uint32Array(KEY_WORDS);
const snapshot: MutableInputSnapshot = {
  down: keys(), pressed: keys(), released: keys(),
  mods: { shift: false, ctrl: false, alt: false, meta: false, capsLock: false, numLock: false },
  mouse: { dx: -12, dy: 0, wheel: 0, buttons: 0, pressed: 0, released: 0 },
  focused: true,
};
const codec = new InputCodec();
const out = new DataView(new ArrayBuffer(INPUT_FRAME_BYTES));
const bytes = codec.encode(out, 1, snapshot);
const header = codec.decode(new Uint8Array(out.buffer, 0, bytes), snapshot); // { seq: 1 }

Extends ​

Constructors ​

Constructor ​
ts
new InputCodec(): InputCodec;
Returns ​

InputCodec

Inherited from ​

FrameCodec.constructor

Methods ​

clampInt() ​
ts
protected clampInt(
   value, 
   min, 
   max
): number;

value rounded and clamped, for an integer wire field.

Parameters ​
ParameterTypeDescription
valuenumberAny number.
minnumberThe least result.
maxnumberThe greatest result.
Returns ​

number

The rounded value in [min, max]; 0 for a non-finite value.

Inherited from ​

FrameCodec.clampInt

decode() ​
ts
decode(bytes, into): InputHeader | null;

Reads one input frame into into.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayExactly one received frame.
intoMutableInputSnapshotThe caller's record, written only when the frame is good.
Returns ​

InputHeader | null

The frame's seq in an object reused by the next call, or null (with into untouched) when bytes is not exactly one input frame or a key array of into is shorter than KEY_WORDS.

encode() ​
ts
encode(
   out, 
   seq, 
   snapshot
): number;

Writes one input frame at the start of out.

Parameters ​
ParameterTypeDescription
outDataViewThe send buffer, owned by the caller.
seqnumberThe input sequence number; acks name it.
snapshotInputSnapshotLikeThe step's input.
Returns ​

number

Bytes written, or 0 (with nothing written) when out is too small.

f32() ​
ts
protected f32(bytes, offset): number;

The little-endian 32-bit float at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

The float, which may be NaN or infinite on a hostile frame.

Inherited from ​

FrameCodec.f32

i16() ​
ts
protected i16(bytes, offset): number;

The signed 16-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with two bytes in range.
Returns ​

number

A value in [-32768, 32767].

Inherited from ​

FrameCodec.i16

i32() ​
ts
protected i32(bytes, offset): number;

The signed 32-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

A signed 32-bit value.

Inherited from ​

FrameCodec.i32

i8() ​
ts
protected i8(bytes, offset): number;

The signed byte at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn in-range offset.
Returns ​

number

A value in [-128, 127].

Inherited from ​

FrameCodec.i8

isKind() ​
ts
protected isKind(
   bytes, 
   kind, 
   length, 
   exact?
): boolean;

Whether bytes is a frame of kind and the right length.

Parameters ​
ParameterTypeDefault valueDescription
bytesUint8ArrayundefinedThe received frame.
kindnumberundefinedThe expected first byte.
lengthnumberundefinedThe frame's length, or its least length when exact is false.
exactbooleantrueWhether the length must match exactly.
Returns ​

boolean

True when the length fits and the first byte is kind.

Inherited from ​

FrameCodec.isKind

u16() ​
ts
protected u16(bytes, offset): number;

The unsigned 16-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with two bytes in range.
Returns ​

number

A value in [0, 65535].

Inherited from ​

FrameCodec.u16

u32() ​
ts
protected u32(bytes, offset): number;

The unsigned 32-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

An unsigned 32-bit value.

Inherited from ​

FrameCodec.u32

u8() ​
ts
protected u8(bytes, offset): number;

The unsigned byte at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn in-range offset.
Returns ​

number

A value in [0, 255].

Inherited from ​

FrameCodec.u8


Quantizer ​

Position and rotation quantisation for the rows codec.

Example ​

ts
const quantizer = new Quantizer();
const mm = quantizer.position(1.2345); // 1235
const word = quantizer.packQuat(0, 0, 0, 1);
quantizer.unpackQuat(word, new Float32Array(4), 0);

Constructors ​

Constructor ​
ts
new Quantizer(): Quantizer;
Returns ​

Quantizer

Methods ​

packQuat() ​
ts
packQuat(
   x, 
   y, 
   z, 
   w
): number;

A rotation to its smallest-three word. The input is normalised first; a zero-length or non-finite quaternion encodes the identity.

Plain rounding of each lane can leave the rebuilt component nearly 2e-3 off, so the encoder tries the eight floor/ceil combinations of the three lanes and keeps the one whose worst component, rebuilt one included, is nearest: under 1e-3 for every rotation in a million-sample sweep.

Parameters ​
ParameterTypeDescription
xnumberQuaternion x.
ynumberQuaternion y.
znumberQuaternion z.
wnumberQuaternion w.
Returns ​

number

The unsigned 32-bit word.

position() ​
ts
position(metres): number;

Metres to whole millimetres.

Parameters ​
ParameterTypeDescription
metresnumberA position lane.
Returns ​

number

Millimetres clamped to i32; 0 for a non-finite value.

unpackQuat() ​
ts
unpackQuat(
   packed, 
   out, 
   offset
): void;

A smallest-three word back to out[offset..offset+3] as xyzw. Any 32-bit word decodes to a unit quaternion, hostile ones included.

Parameters ​
ParameterTypeDescription
packednumberThe word off the wire.
outFloat32ArrayReceives x, y, z, w.
offsetnumberWhere x goes in out.
Returns ​

void

unposition() ​
ts
unposition(mm): number;

Millimetres back to metres.

Parameters ​
ParameterTypeDescription
mmnumberA position lane off the wire.
Returns ​

number

Metres.


RowsCodec ​

Encodes and decodes rows frames. Owns the one header object decode returns, so neither direction allocates.

Example ​

ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
  count: 1,
  entity: () => 7,
  flags: () => RowFlag.POSITION | RowFlag.ROTATION,
  position: () => position,
  rotation: () => rotation,
  scale: () => scale,
};
const sink: RowSink = {
  position: new Float32Array(3),
  rotation: new Float32Array(4),
  scale: new Float32Array(3),
  row: (entity) => console.log(entity, sink.position),
};
const codec = new RowsCodec();
const out = new DataView(new ArrayBuffer(codec.frameBytes(rows)));
const bytes = codec.encode(out, 600, 12, rows);
codec.decode(new Uint8Array(out.buffer, 0, bytes), sink); // { frame: 600, ack: 12, count: 1, player: null }

Extends ​

Constructors ​

Constructor ​
ts
new RowsCodec(): RowsCodec;
Returns ​

RowsCodec

Inherited from ​

FrameCodec.constructor

Methods ​

clampInt() ​
ts
protected clampInt(
   value, 
   min, 
   max
): number;

value rounded and clamped, for an integer wire field.

Parameters ​
ParameterTypeDescription
valuenumberAny number.
minnumberThe least result.
maxnumberThe greatest result.
Returns ​

number

The rounded value in [min, max]; 0 for a non-finite value.

Inherited from ​

FrameCodec.clampInt

decode() ​
ts
decode(bytes, sink): RowsHeader | null;

Reads one rows frame, handing each row to sink.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayExactly one received frame.
sinkRowSinkReceives the rows, only once the whole frame has been checked.
Returns ​

RowsHeader | null

The frame's header in an object reused by the next call (its player is the trailer, or null), or null (with the sink never called) when bytes is not exactly one well-formed rows frame: too short for its header or its rows, longer than its rows and not one whole trailer, another kind, a flag bit outside RowFlag or PlayerRowFlag, a non-finite scale or trailer lane, or sink arrays too short.

encode() ​
ts
encode(
   out, 
   frame, 
   ack, 
   rows
): number;

Writes one rows frame at the start of out; a non-finite scale lane is written as 1, one past the f32 range as its limit.

Parameters ​
ParameterTypeDescription
outDataViewThe send buffer, owned by the caller.
framenumberThe authority's fixed-step counter.
acknumberThe last input seq applied for the receiving player; also the trailer's seq.
rowsRowSourceThe rows to write, and rows.player's trailer after them when it is set.
Returns ​

number

Bytes written, or 0 (with nothing written) when out is too small or rows.count is not an integer in [0, MAX_ROWS].

f32() ​
ts
protected f32(bytes, offset): number;

The little-endian 32-bit float at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

The float, which may be NaN or infinite on a hostile frame.

Inherited from ​

FrameCodec.f32

frameBytes() ​
ts
frameBytes(rows): number;

The bytes encode would write; flag bits beyond RowFlag are ignored.

Parameters ​
ParameterTypeDescription
rowsRowSourceThe rows to size.
Returns ​

number

The frame's length.

i16() ​
ts
protected i16(bytes, offset): number;

The signed 16-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with two bytes in range.
Returns ​

number

A value in [-32768, 32767].

Inherited from ​

FrameCodec.i16

i32() ​
ts
protected i32(bytes, offset): number;

The signed 32-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

A signed 32-bit value.

Inherited from ​

FrameCodec.i32

i8() ​
ts
protected i8(bytes, offset): number;

The signed byte at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn in-range offset.
Returns ​

number

A value in [-128, 127].

Inherited from ​

FrameCodec.i8

isKind() ​
ts
protected isKind(
   bytes, 
   kind, 
   length, 
   exact?
): boolean;

Whether bytes is a frame of kind and the right length.

Parameters ​
ParameterTypeDefault valueDescription
bytesUint8ArrayundefinedThe received frame.
kindnumberundefinedThe expected first byte.
lengthnumberundefinedThe frame's length, or its least length when exact is false.
exactbooleantrueWhether the length must match exactly.
Returns ​

boolean

True when the length fits and the first byte is kind.

Inherited from ​

FrameCodec.isKind

u16() ​
ts
protected u16(bytes, offset): number;

The unsigned 16-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with two bytes in range.
Returns ​

number

A value in [0, 65535].

Inherited from ​

FrameCodec.u16

u32() ​
ts
protected u32(bytes, offset): number;

The unsigned 32-bit integer at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn offset with four bytes in range.
Returns ​

number

An unsigned 32-bit value.

Inherited from ​

FrameCodec.u32

u8() ​
ts
protected u8(bytes, offset): number;

The unsigned byte at offset.

Parameters ​
ParameterTypeDescription
bytesUint8ArrayThe frame, already length-checked.
offsetnumberAn in-range offset.
Returns ​

number

A value in [0, 255].

Inherited from ​

FrameCodec.u8


TextFrames ​

Text frame building and parsing for both directions.

Example ​

ts
const frames = new TextFrames();
const text = frames.buildClient({ t: 'ping', at: performance.now() });
const back = text === null ? null : frames.parseClient(text); // { t: 'ping', at: ... }

Constructors ​

Constructor ​
ts
new TextFrames(): TextFrames;
Returns ​

TextFrames

Methods ​

buildClient() ​
ts
buildClient(frame): string | null;

A client frame as JSON text.

Parameters ​
ParameterTypeDescription
frameClientTextThe frame to send.
Returns ​

string | null

The text, or null when a msg payload is over the cap or not JSON, or the frame is over MAX_CLIENT_TEXT_BYTES.

buildServer() ​
ts
buildServer(frame): string | null;

A server frame as JSON text.

Parameters ​
ParameterTypeDescription
frameServerTextThe frame to send.
Returns ​

string | null

The text, or null when a msg payload is over the cap or anything is not JSON.

byteLength() ​
ts
byteLength(text): number;

UTF-8 bytes of text, counted without encoding it. A lone surrogate counts 3, as TextEncoder writes U+FFFD for it.

Parameters ​
ParameterTypeDescription
textstringAny string.
Returns ​

number

Its UTF-8 length.

parseClient() ​
ts
parseClient(text): ClientText | null;

A client frame from its text. The frame is rebuilt from the fields it was checked on, so nothing else the client sent survives.

Parameters ​
ParameterTypeDescription
textstringA received text message.
Returns ​

ClientText | null

The checked frame, or null for anything malformed, mistyped or over the cap.

parseClientDetailed() ​
ts
parseClientDetailed(text): ClientText | ClientTextFailure;

TextFrames.parseClient that says why it refused.

Parameters ​
ParameterTypeDescription
textstringA received text message.
Returns ​

ClientText | ClientTextFailure

The checked frame, or the reason: size (over the cap), depth (nested too deep), json (not JSON), type (no known t) or shape (not an object, or the fields of a known t are wrong).

parseServer() ​
ts
parseServer(text): ServerText | null;

A server frame from its text.

Parameters ​
ParameterTypeDescription
textstringA received text message.
Returns ​

ServerText | null

The checked frame, or null for anything malformed or mistyped.

Interfaces ​

InputHeader ​

What decodeInput read besides the snapshot; reused across calls.

Properties ​

seq ​
ts
seq: number;

InputSnapshotLike ​

One step of input as encodeInput reads it. The host's input snapshot fits this shape as it is; nothing has to be copied into it.

Properties ​

down ​
ts
readonly down: Uint32Array;

Keys held, KEY_WORDS words.

focused ​
ts
readonly focused: boolean;
mods ​
ts
readonly mods: Readonly<WireMods>;
mouse ​
ts
readonly mouse: Readonly<WireMouse>;
pressed ​
ts
readonly pressed: Uint32Array;

Keys that went down this step, KEY_WORDS words.

released ​
ts
readonly released: Uint32Array;

Keys that came up this step, KEY_WORDS words.


MutableInputSnapshot ​

The record decodeInput writes into. The caller owns it and its arrays, so one record can be reused for every frame from a player.

Properties ​

down ​
ts
readonly down: Uint32Array;
focused ​
ts
focused: boolean;
mods ​
ts
readonly mods: WireMods;
mouse ​
ts
readonly mouse: WireMouse;
pressed ​
ts
readonly pressed: Uint32Array;
released ​
ts
readonly released: Uint32Array;

PlayerRow ​

A decoded player trailer. The codec owns one and rewrites it every decode: read it, or copy it, before the next.

Properties ​

entity ​
ts
entity: number;

The entity the player controls.

flags ​
ts
flags: number;

PlayerRowFlag bits.

position ​
ts
readonly position: Float32Array;

Body position xyz, metres, exact f32.

seq ​
ts
seq: number;

The newest input seq the authority had applied for this player when it read the body.

velocity ​
ts
readonly velocity: Float32Array;

Body linear velocity xyz, metres per second.


PlayerRowSource ​

One player's own body as the authority has it after a step, read in place when a rows frame is encoded.

Properties ​

entity ​
ts
readonly entity: number;

The entity the player controls.

flags ​
ts
readonly flags: number;

PlayerRowFlag bits: grounded, teleported.

position ​
ts
readonly position: ArrayLike<number>;

Body position xyz, metres.

velocity ​
ts
readonly velocity: ArrayLike<number>;

Body linear velocity xyz, metres per second.


PlayerSummary ​

One player as the room lists them.

Properties ​

connected ​
ts
connected: boolean;

False while the seat is held for a reconnect.

id ​
ts
id: number;

The player id, stable for the seat's life.

name ​
ts
name: string;

The display name the player joined with.


RowsHeader ​

What decodeRows read besides the rows; reused across calls.

Properties ​

ack ​
ts
ack: number;
count ​
ts
count: number;
frame ​
ts
frame: number;
player ​
ts
player: PlayerRow | null;

The player trailer, or null when the frame has none.


RowSink ​

Where decoded rows go. Before each row call the decoder writes the lanes the flags name into the sink's own arrays; lanes the row does not carry are left as they were.

Properties ​

position ​
ts
readonly position: Float32Array;

At least three lanes: position xyz, metres.

rotation ​
ts
readonly rotation: Float32Array;

At least four lanes: rotation xyzw.

scale ​
ts
readonly scale: Float32Array;

At least three lanes: scale xyz.

Methods ​

player()? ​
ts
optional player(row): void;

The frame's player trailer, after its last row; never called for a frame without one. A sink that leaves it out ignores the trailer.

Parameters ​
ParameterType
rowPlayerRow
Returns ​

void

row() ​
ts
row(entity, flags): void;

One decoded row; read the arrays now, the next row overwrites them.

Parameters ​
ParameterType
entitynumber
flagsnumber
Returns ​

void


RowSource ​

Rows to encode, addressed by index. Lanes are read only when the row's flags name them, and are read in place: a world record's own arrays can be handed back without a copy.

Properties ​

count ​
ts
readonly count: number;

How many rows to write.

player? ​
ts
readonly optional player?: PlayerRowSource | null;

The receiving player's own body, written as the frame's trailer after the rows; null or absent for a spectator (no entity, or no body). The trailer's seq is the frame's ack.

Methods ​

entity() ​
ts
entity(index): number;

The entity id of row index.

Parameters ​
ParameterType
indexnumber
Returns ​

number

flags() ​
ts
flags(index): number;

The RowFlag bits of row index.

Parameters ​
ParameterType
indexnumber
Returns ​

number

position() ​
ts
position(index): ArrayLike<number>;

Position xyz of row index, metres.

Parameters ​
ParameterType
indexnumber
Returns ​

ArrayLike<number>

rotation() ​
ts
rotation(index): ArrayLike<number>;

Rotation quaternion xyzw of row index.

Parameters ​
ParameterType
indexnumber
Returns ​

ArrayLike<number>

scale() ​
ts
scale(index): ArrayLike<number>;

Scale xyz of row index.

Parameters ​
ParameterType
indexnumber
Returns ​

ArrayLike<number>


Transport ​

A two-way pipe of frames. Text frames are the reliable channel; binary frames (inputs, rows) may be dropped on a lossy link.

Example ​

ts
import type { Transport } from 'gameable/net';
import { loopbackPair } from 'gameable/net/testing';
const [client, server]: [Transport, Transport] = loopbackPair();
server.onMessage((data) => console.log(data));
client.send('{"t":"ping","n":1}');

Properties ​

bufferedAmount ​
ts
readonly bufferedAmount: number;

Bytes queued to send and not yet written out; a sender can skip a binary frame while this is high.

Methods ​

close() ​
ts
close(reason?): void;

Closes the transport. Safe to call twice; the close listeners fire once.

Parameters ​
ParameterType
reason?string
Returns ​

void

onClose() ​
ts
onClose(cb): void;

Registers a listener for the close, called once with the reason. Registering after close does nothing.

Parameters ​
ParameterType
cb(reason) => void
Returns ​

void

onMessage() ​
ts
onMessage(cb): void;

Registers a listener for every frame received. Registering after close does nothing.

Parameters ​
ParameterType
cb(data) => void
Returns ​

void

send() ​
ts
send(data): void;

Sends one frame. After the transport is closed this does nothing.

Parameters ​
ParameterType
dataTransportData
Returns ​

void


WireMods ​

Modifier keys, one bit each on the wire.

Properties ​

alt ​
ts
alt: boolean;
capsLock ​
ts
capsLock: boolean;
ctrl ​
ts
ctrl: boolean;
meta ​
ts
meta: boolean;
numLock ​
ts
numLock: boolean;
shift ​
ts
shift: boolean;

WireMouse ​

The mouse fields the wire carries. Deltas round to whole pixels and clamp to i16, the wheel to i8, the button masks to their low 8 bits.

Properties ​

buttons ​
ts
buttons: number;
dx ​
ts
dx: number;
dy ​
ts
dy: number;
pressed ​
ts
pressed: number;
released ​
ts
released: number;
wheel ​
ts
wheel: number;

Type Aliases ​

ClientText ​

ts
type ClientText = 
  | {
  name: string;
  room: string;
  seat?: {
     id: number;
     secret: string;
  };
  t: "hello";
  token?: string;
  v: number;
}
  | {
  name: string;
  payload: unknown;
  t: "msg";
}
  | {
  at: number;
  t: "ping";
};

A JSON text frame a client sends, discriminated by t.


ServerErrorCode ​

ts
type ServerErrorCode = "room" | "full" | "seat" | "origin" | "budget" | "version" | "ended";

Why the server refused or closed a connection.


ServerText ​

ts
type ServerText = 
  | {
  entity: number;
  frame: number;
  player: number;
  players: PlayerSummary[];
  room?: string;
  secret: string;
  snapshot: unknown;
  t: "welcome";
}
  | {
  ack: number;
  commands: Command[];
  entity: number;
  frame: number;
  t: "cmd";
}
  | {
  players: PlayerSummary[];
  t: "players";
}
  | {
  from: number;
  name: string;
  payload: unknown;
  t: "msg";
}
  | {
  at: number;
  server: number;
  t: "pong";
}
  | {
  code: ServerErrorCode;
  detail?: string;
  t: "error";
};

A JSON text frame the server sends, discriminated by t.

Union Members ​

Type Literal ​
ts
{
  entity: number;
  frame: number;
  player: number;
  players: PlayerSummary[];
  room?: string;
  secret: string;
  snapshot: unknown;
  t: "welcome";
}
entity ​
ts
entity: number;

The entity this player controls, or 0 for none: "which entity is mine".

frame ​
ts
frame: number;
player ​
ts
player: number;
players ​
ts
players: PlayerSummary[];
room? ​
ts
optional room?: string;

The room's code, as the server knows it (the code to share); absent from a server that does not say.

secret ​
ts
secret: string;
snapshot ​
ts
snapshot: unknown;
t ​
ts
t: "welcome";

Type Literal ​
ts
{
  ack: number;
  commands: Command[];
  entity: number;
  frame: number;
  t: "cmd";
}

entity: the entity this player controls now, or 0 (a possess or a despawn changes it).


Type Literal ​
ts
{
  players: PlayerSummary[];
  t: "players";
}

Type Literal ​
ts
{
  from: number;
  name: string;
  payload: unknown;
  t: "msg";
}

Type Literal ​
ts
{
  at: number;
  server: number;
  t: "pong";
}

Type Literal ​
ts
{
  code: ServerErrorCode;
  detail?: string;
  t: "error";
}

TransportData ​

ts
type TransportData = string | Uint8Array;

One frame: JSON text, or the bytes of a binary frame.

Variables ​

AUTHORITY_SENDER ​

ts
const AUTHORITY_SENDER: 4294967295 = 0xffffffff;

The sender id of a message from the authority itself. Room seats start at 0, so the authority is not 0: this is past every player id and still a u32 (the WIT's message-event.player). Keep ids unsigned: in an Int32Array this reads back as -1.

Example ​

ts
import { AUTHORITY_SENDER } from 'gameable';

const fromServer = (from: number): boolean => from === AUTHORITY_SENDER;

FrameKind ​

ts
const FrameKind: object;

The first byte of every binary frame.

Type Declaration ​

INPUT ​
ts
readonly INPUT: 1 = 1;

Client to server: one step of one player's input.

ROWS ​
ts
readonly ROWS: 2 = 2;

Server to client: the transform rows of one send.


INPUT_FRAME_BYTES ​

ts
const INPUT_FRAME_BYTES: number;

Bytes of an input frame: kind, seq, three key sets, mods, mouse, focused.


MAX_CLIENT_TEXT_BYTES ​

ts
const MAX_CLIENT_TEXT_BYTES: number;

The largest text frame a client may send, in UTF-8 bytes: a full payload plus room for the envelope (t, the message name, a hello's fields).


MAX_JSON_DEPTH ​

ts
const MAX_JSON_DEPTH: 32 = 32;

The deepest nesting of arrays and objects a text frame may carry; a deeper frame is refused before JSON.parse sees it.


MAX_PAYLOAD_BYTES ​

ts
const MAX_PAYLOAD_BYTES: 2048 = 2048;

The largest message payload, in UTF-8 bytes of its JSON, on ctx.net.send and on the wire.


MAX_ROWS ​

ts
const MAX_ROWS: 65535 = 0xffff;

The most rows one frame can carry (count is a u16).


PLAYER_ROW_FLAG_MASK ​

ts
const PLAYER_ROW_FLAG_MASK: number;

Every flag bit a player trailer may set; a frame with any other bit is refused.


PLAYER_TRAILER_BYTES ​

ts
const PLAYER_TRAILER_BYTES: number;

Bytes of a rows frame's player trailer: tag u8, entity u32, seq u32, position 3 x f32, velocity 3 x f32, flags u8.


PLAYER_TRAILER_TAG ​

ts
const PLAYER_TRAILER_TAG: 1 = 1;

The first byte of a rows frame's player trailer, after its last row.


PlayerRowFlag ​

ts
const PlayerRowFlag: object;

What a player trailer's flags byte says about the body, OR-ed together.

Type Declaration ​

GROUNDED ​
ts
readonly GROUNDED: 1 = 1;

The character body stood on walkable ground after the step.

TELEPORT ​
ts
readonly TELEPORT: 2 = 2;

The authority teleported the body since the last rows this player was sent (a respawn, a set-body-transform with teleport): a predicting client snaps to it instead of counting a correction.


PROTOCOL_VERSION ​

ts
const PROTOCOL_VERSION: 1 = 1;

The protocol version a client sends in hello; a mismatch is refused.


ROW_FLAG_MASK ​

ts
const ROW_FLAG_MASK: number;

Every flag bit a row may set; a frame with any other bit is refused.


RowFlag ​

ts
const RowFlag: object;

Which lanes a transform row carries, OR-ed together in its flags byte.

Type Declaration ​

POSITION ​
ts
readonly POSITION: 1 = 1;

Position: three i32 millimetres.

ROTATION ​
ts
readonly ROTATION: 2 = 2;

Rotation: one u32, smallest-three.

SCALE ​
ts
readonly SCALE: 4 = 4;

Scale: three f32, exact and signed.

TELEPORT ​
ts
readonly TELEPORT: 16 = 16;

No lanes: the entity teleported since the last rows this player was sent; snap to this pose instead of interpolating to it. The same bit as TRANSFORM_FLAGS.TELEPORT.

VISIBLE ​
ts
readonly VISIBLE: 8 = 8;

No lanes: the entity was hidden at spawn and is now shown (the server's world record only ever turns visibility on). The same bit as the engine's TRANSFORM_FLAGS.VISIBLE, so a client can pass it through.


ROWS_HEADER_BYTES ​

ts
const ROWS_HEADER_BYTES: number;

Bytes of a rows frame before its first row: kind, frame, ack, count.

Functions ​

buildClientText() ​

ts
function buildClientText(frame): string | null;

A client frame as JSON text, or null when a msg payload is over MAX_PAYLOAD_BYTES.

Parameters ​

ParameterTypeDescription
frameClientTextThe frame to send.

Returns ​

string | null

The text, or null.

Example ​

ts
const text = buildClientText({ t: 'hello', v: 1, room: 'lobby', name: 'Ana' });
// '{"t":"hello","v":1,"room":"lobby","name":"Ana"}'

buildServerText() ​

ts
function buildServerText(frame): string | null;

A server frame as JSON text, or null when a msg payload is over MAX_PAYLOAD_BYTES.

Parameters ​

ParameterTypeDescription
frameServerTextThe frame to send.

Returns ​

string | null

The text, or null.

Example ​

ts
const text = buildServerText({ t: 'pong', at: 12.5, server: Date.now() });

createInputCodec() ​

ts
function createInputCodec(): InputCodec;

A new input codec with its own reusable header.

Returns ​

InputCodec

The codec.

Example ​

ts
const codec = createInputCodec();

createRowsCodec() ​

ts
function createRowsCodec(): RowsCodec;

A new rows codec with its own reusable header.

Returns ​

RowsCodec

The codec.

Example ​

ts
const codec = createRowsCodec();

createTextFrames() ​

ts
function createTextFrames(): TextFrames;

A new text frame builder and parser.

Returns ​

TextFrames

The builder.

Example ​

ts
const frames = createTextFrames();
frames.parseServer('{"t":"pong","at":1,"server":2}'); // { t: 'pong', at: 1, server: 2 }

decodeInput() ​

ts
function decodeInput(bytes, into): InputHeader | null;

Reads one input frame into into; see InputCodec.decode. The returned object is shared by every call: read seq before the next decode.

Parameters ​

ParameterTypeDescription
bytesUint8ArrayExactly one received frame.
intoMutableInputSnapshotThe caller's record.

Returns ​

InputHeader | null

{ seq }, or null for a malformed frame.

Example ​

ts
const keys = () => new Uint32Array(KEY_WORDS);
const snapshot: MutableInputSnapshot = {
  down: keys(), pressed: keys(), released: keys(),
  mods: { shift: false, ctrl: false, alt: false, meta: false, capsLock: false, numLock: false },
  mouse: { dx: -12, dy: 0, wheel: 0, buttons: 0, pressed: 0, released: 0 },
  focused: true,
};
const out = new DataView(new ArrayBuffer(INPUT_FRAME_BYTES));
const message = new Uint8Array(out.buffer, 0, encodeInput(out, 42, snapshot));
const lastSeq = decodeInput(message, snapshot)?.seq; // 42

decodeRows() ​

ts
function decodeRows(bytes, sink): RowsHeader | null;

Reads one rows frame into sink; see RowsCodec.decode. The returned object is shared by every call: read it before the next decode.

Parameters ​

ParameterTypeDescription
bytesUint8ArrayExactly one received frame.
sinkRowSinkReceives the rows.

Returns ​

RowsHeader | null

{ frame, ack, count }, or null for a malformed frame.

Example ​

ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
  count: 1,
  entity: () => 7,
  flags: () => RowFlag.POSITION | RowFlag.ROTATION,
  position: () => position,
  rotation: () => rotation,
  scale: () => scale,
};
const sink: RowSink = {
  position: new Float32Array(3),
  rotation: new Float32Array(4),
  scale: new Float32Array(3),
  row: (entity) => console.log(entity, sink.position),
};
const out = new DataView(new ArrayBuffer(rowsFrameBytes(rows)));
const message = new Uint8Array(out.buffer, 0, encodeRows(out, 600, 12, rows));
const newest = decodeRows(message, sink)?.frame; // 600

encodeInput() ​

ts
function encodeInput(
   out, 
   seq, 
   snapshot
): number;

Writes one input frame at the start of out; see InputCodec.encode.

Parameters ​

ParameterTypeDescription
outDataViewThe send buffer, owned by the caller.
seqnumberThe input sequence number.
snapshotInputSnapshotLikeThe step's input.

Returns ​

number

Bytes written, or 0 when out is too small.

Example ​

ts
const keys = () => new Uint32Array(KEY_WORDS);
const snapshot: MutableInputSnapshot = {
  down: keys(), pressed: keys(), released: keys(),
  mods: { shift: false, ctrl: false, alt: false, meta: false, capsLock: false, numLock: false },
  mouse: { dx: -12, dy: 0, wheel: 0, buttons: 0, pressed: 0, released: 0 },
  focused: true,
};
const out = new DataView(new ArrayBuffer(INPUT_FRAME_BYTES));
const frame = new Uint8Array(out.buffer, 0, encodeInput(out, 1, snapshot)); // 111 bytes to send

encodeRows() ​

ts
function encodeRows(
   out, 
   frame, 
   ack, 
   rows
): number;

Writes one rows frame at the start of out; see RowsCodec.encode.

Parameters ​

ParameterTypeDescription
outDataViewThe send buffer, owned by the caller.
framenumberThe authority's fixed-step counter.
acknumberThe last input seq applied for the receiving player.
rowsRowSourceThe rows to write.

Returns ​

number

Bytes written, or 0 when out is too small.

Example ​

ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
  count: 1,
  entity: () => 7,
  flags: () => RowFlag.POSITION | RowFlag.ROTATION,
  position: () => position,
  rotation: () => rotation,
  scale: () => scale,
};
const out = new DataView(new ArrayBuffer(1024));
const bytes = encodeRows(out, 600, 12, rows);
const frame = new Uint8Array(out.buffer, out.byteOffset, bytes); // the bytes to send

packQuat() ​

ts
function packQuat(
   x, 
   y, 
   z, 
   w
): number;

Packs a rotation into its smallest-three word; see Quantizer.packQuat.

Parameters ​

ParameterTypeDescription
xnumberQuaternion x.
ynumberQuaternion y.
znumberQuaternion z.
wnumberQuaternion w.

Returns ​

number

The unsigned 32-bit word.

Example ​

ts
const word = packQuat(0, 0, Math.SQRT1_2, Math.SQRT1_2);

parseClientText() ​

ts
function parseClientText(text): ClientText | null;

A client frame from its text, or null for anything malformed or over the cap.

Parameters ​

ParameterTypeDescription
textstringA received text message.

Returns ​

ClientText | null

The checked frame, or null.

Example ​

ts
const frame = parseClientText('{"t":"ping","at":12.5}');
const at = frame?.t === 'ping' ? frame.at : null; // 12.5

parseServerText() ​

ts
function parseServerText(text): ServerText | null;

A server frame from its text, or null for anything malformed.

Parameters ​

ParameterTypeDescription
textstringA received text message.

Returns ​

ServerText | null

The checked frame, or null.

Example ​

ts
const frame = parseServerText('{"t":"error","code":"full"}');
const full = frame?.t === 'error' && frame.code === 'full'; // true

rowsFrameBytes() ​

ts
function rowsFrameBytes(rows): number;

The bytes encodeRows would write for rows; size the send buffer with it.

Parameters ​

ParameterTypeDescription
rowsRowSourceThe rows to size.

Returns ​

number

The frame's length.

Example ​

ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
  count: 1,
  entity: () => 7,
  flags: () => RowFlag.POSITION | RowFlag.ROTATION,
  position: () => position,
  rotation: () => rotation,
  scale: () => scale,
};
const out = new DataView(new ArrayBuffer(rowsFrameBytes(rows))); // 11 + 21 bytes

unpackQuat() ​

ts
function unpackQuat(
   packed, 
   out, 
   offset
): void;

Unpacks a smallest-three word into out at offset; see Quantizer.unpackQuat.

Parameters ​

ParameterTypeDescription
packednumberThe word off the wire.
outFloat32ArrayReceives x, y, z, w.
offsetnumberWhere x goes in out.

Returns ​

void

Example ​

ts
const q = new Float32Array(4);
unpackQuat(packQuat(0, 0, 0, 1), q, 0); // q = [0, 0, 0, 1]

utf8ByteLength() ​

ts
function utf8ByteLength(text): number;

UTF-8 bytes of text, counted without encoding it.

Parameters ​

ParameterTypeDescription
textstringAny string.

Returns ​

number

Its UTF-8 length.

Example ​

ts
utf8ByteLength('€'); // 3