Skip to content

@gameable/sdk ​

Classes ​

BodyIndex ​

Maps host body ids back onto entities and ingests frame-input.bodies.

The incoming list is a Float32Array in both modes — jco lifts WIT list<f32> into one, and direct mode hands the guest the host's own buffer (see packages/sdk/src/wit/generated/interfaces/gameable-engine-game.d.ts). It is read purely by index and never copied.

Constructors ​

Constructor ​
ts
new BodyIndex(maxBodies): BodyIndex;
Parameters ​
ParameterTypeDescription
maxBodiesnumberBody-id ceiling.
Returns ​

BodyIndex

Properties ​

bodyToEntity ​
ts
readonly bodyToEntity: Uint32Array;

Body id to entity id. Index 0 is unused: body 0 means "no body".

lastRowCount ​
ts
lastRowCount: number = 0;

Number of rows seen in the most recent ingest.

Methods ​

bind() ​
ts
bind(body, entity): void;

Associate a body with the entity it drives.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
entitynumberEntity id.
Returns ​

void

Nothing.

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

The body id driving an entity, or 0.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
Returns ​

number

The body id, or 0 when the entity has none.

clear() ​
ts
clear(): void;

Forget every body.

Returns ​

void

Nothing.

ingest() ​
ts
ingest(bodies): void;

Copy post-step body transforms into Transform and Velocity.

This does not mark the entity moved, and that is the point. The host owns a body-driven entity's transform: the physics module hands the same rows straight to the adapter after it steps, so the object in the scene is already where the body is. Marking here would send all twelve floats back across the boundary in frame-output.transforms for the host to write a second time — the same numbers, one step later.

What the guest gets is still the truth for gameplay: read Transform.x[e] to aim at something, Velocity to decide whether it is running. A system that overwrites those lanes is authoring a move rather than observing one, and has to say so with markMoved — see markMoved.

Parameters ​
ParameterTypeDescription
bodiesArrayLike<number>The packed rows, stride 15.
Returns ​

void

Nothing.

unbind() ​
ts
unbind(body): void;

Forget a body.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
Returns ​

void

Nothing.


CommandBuffer ​

Builds and owns one frame's commands list.

Constructors ​

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

CommandBuffer

Properties ​

list ​
ts
readonly list: Command[] = [];

The list handed to the host. Reused every frame; never retain it.

Methods ​

addBody() ​
ts
addBody(
   body, 
   entity, 
   kind, 
   shape, 
   hx, 
   hy, 
   hz, 
   px, 
   py, 
   pz, 
   mass, 
   layer, 
   mask, 
   flags
): AddBodyCmd;

Create a rigid body or character controller.

Parameters ​
ParameterTypeDescription
bodynumberGuest-minted body id.
entitynumberEntity the body drives.
kindBodyKindBody class.
shapeShapeKindCollision shape family.
hxnumberHalf-extent / radius lane 0.
hynumberHalf-extent / half-height lane 1.
hznumberHalf-extent lane 2.
pxnumberPosition x.
pynumberPosition y.
pznumberPosition z.
massnumberKilograms; ignored for fixed and kinematic bodies.
layerCollisionLayersWhat this body is.
maskCollisionLayersWhat this body collides with.
flagsBodyFlagsPer-body switches.
Returns ​

AddBodyCmd

The payload, so the caller can tune friction and damping. Round anything written onto it with Math.fround.

applyImpulse() ​
ts
applyImpulse(
   body, 
   x, 
   y, 
   z, 
   atX?, 
   atY?, 
   atZ?
): void;

Apply a one-shot impulse.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
xnumberImpulse x.
ynumberImpulse y.
znumberImpulse z.
atX?numberWorld-space application point x. Omit for the centre of mass.
atY?numberApplication point y.
atZ?numberApplication point z.
Returns ​

void

Nothing.

conversation() ​
ts
conversation(
   entity, 
   action, 
   character?, 
   text?
): void;

Control an optional host conversation module using pooled commands.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedInterviewed entity.
action| "end" | "start" | "ask" | "interrupt" | "microphone-on" | "microphone-off"undefinedLifecycle or text command.
characterstring''Configured character id, never a URL.
textstring''Typed/transcribed question; empty for lifecycle commands.
Returns ​

void

despawn() ​
ts
despawn(entity): void;

Destroy an entity in the host scene.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
Returns ​

void

Nothing.

loadAsset() ​
ts
loadAsset(asset, priority): void;

Ask the host to start loading an asset.

Parameters ​
ParameterTypeDescription
assetnumberAsset handle.
prioritynumberHigher runs first.
Returns ​

void

Nothing.

lookAt() ​
ts
lookAt(
   entity, 
   target, 
   weight
): void;

Aim a character's head and eyes.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
targetVec3 | nullWorld-space point, or null to release the look-at.
weightnumberBlend weight in 0..1.
Returns ​

void

Nothing.

moveCharacter() ​
ts
moveCharacter(
   body, 
   vx, 
   vy, 
   vz, 
   jump, 
   crouch, 
   maxSlopeDeg
): void;

Drive a character body for one step.

Parameters ​
ParameterTypeDescription
bodynumberBody id of a character body.
vxnumberDesired velocity x.
vynumberDesired velocity y.
vznumberDesired velocity z.
jumpbooleanRequest a jump this step.
crouchbooleanRequest a crouch this step.
maxSlopeDegnumberMaximum walkable slope in degrees.
Returns ​

void

Nothing.

playSound() ​
ts
playSound(
   sound, 
   asset, 
   entity, 
   volume, 
   pitch, 
   looping, 
   bus
): void;

Start a sound.

Parameters ​
ParameterTypeDescription
soundnumberGuest-minted sound handle.
assetnumberAudio asset handle.
entitynumber | undefinedEntity to follow, or undefined for a non-positional sound.
volumenumberLinear gain in 0..1.
pitchnumberPlayback-rate multiplier.
loopingbooleanLoop the sound.
busAudioBusMixer bus.
Returns ​

void

Nothing.

removeBody() ​
ts
removeBody(body): void;

Destroy a body.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
Returns ​

void

Nothing.

reset() ​
ts
reset(): void;

Rewind for a new frame. Keeps every pooled object alive.

Returns ​

void

Nothing.

say() ​
ts
say(
   entity, 
   text, 
   audio?, 
   visemes?
): void;

Speak a line.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
textstringSubtitle text.
audio?numberVoice line asset handle.
visemes?stringViseme track as JSON.
Returns ​

void

Nothing.

setAnim() ​
ts
setAnim(
   entity, 
   clip, 
   looping, 
   speed, 
   fadeMs, 
   weight
): void;

Play or cross-fade a clip.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
clipstringClip name inside the entity's asset.
loopingbooleanLoop the clip.
speednumberPlayback rate multiplier.
fadeMsnumberCross-fade duration in milliseconds.
weightnumberTarget layer weight in 0..1.
Returns ​

void

Nothing.

setAsset() ​
ts
setAsset(entity, asset): void;

Attach or detach a renderable.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
assetnumber | undefinedAsset handle, or undefined to detach.
Returns ​

void

Nothing.

setBodyEnabled() ​
ts
setBodyEnabled(body, enabled): void;

Enable or disable a body in the broad phase.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
enabledbooleanWhether the body participates.
Returns ​

void

Nothing.

setBodyTransform() ​
ts
setBodyTransform(
   body, 
   px, 
   py, 
   pz, 
   qx, 
   qy, 
   qz, 
   qw, 
   teleport
): void;

Move a body directly.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
pxnumberPosition x.
pynumberPosition y.
pznumberPosition z.
qxnumberRotation x.
qynumberRotation y.
qznumberRotation z.
qwnumberRotation w.
teleportbooleanClear velocities and skip interpolation.
Returns ​

void

Nothing.

setBodyVelocity() ​
ts
setBodyVelocity(
   body, 
   x, 
   y, 
   z, 
   ax?, 
   ay?, 
   az?
): void;

Overwrite a body's velocity.

Parameters ​
ParameterTypeDescription
bodynumberBody id.
xnumberLinear x.
ynumberLinear y.
znumberLinear z.
ax?numberAngular x, radians per second. Omit to leave spin alone.
ay?numberAngular y.
az?numberAngular z.
Returns ​

void

Nothing.

setCharacterState() ​
ts
setCharacterState(
   entity, 
   state, 
   vx, 
   vy, 
   vz, 
   grounded
): void;

Drive a character's locomotion state machine.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
statestringState name, for example `'idle'
vxnumberVelocity x.
vynumberVelocity y.
vznumberVelocity z.
groundedbooleanWhether the character is on the ground.
Returns ​

void

Nothing.

setClipWeights() ​
ts
setClipWeights(
   entity, 
   clips, 
   weights, 
   timeScale
): void;

Set explicit per-clip weights.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
clipsreadonly string[]Clip names.
weightsFloat32Array<ArrayBufferLike> | readonly number[]Positional weights; must match clips in length. Copied into pooled storage, so the caller may reuse its own array freely.
timeScalenumberPlayback rate for the whole layer.
Returns ​

void

Nothing.

setExpression() ​
ts
setExpression(
   entity, 
   space, 
   weights
): void;

Set facial expression coefficients.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
spaceExpressionSpaceCoordinate space the weights are in.
weightsFloat32Array<ArrayBufferLike> | readonly number[]Coefficients; length must match the space. Copied into pooled storage, so the caller may reuse its own array freely.
Returns ​

void

Nothing.

setListener() ​
ts
setListener(
   px, 
   py, 
   pz, 
   qx, 
   qy, 
   qz, 
   qw
): void;

Place the audio listener.

Parameters ​
ParameterTypeDescription
pxnumberPosition x.
pynumberPosition y.
pznumberPosition z.
qxnumberRotation x.
qynumberRotation y.
qznumberRotation z.
qwnumberRotation w.
Returns ​

void

Nothing.

setMaterialParam() ​
ts
setMaterialParam(
   entity, 
   name, 
   value
): void;

Set one material uniform.

The value is copied into a pooled holder, rounded to f32: the host never sees the guest's own object, and a colour built inline costs nothing after the first frame. Only a slot that changes variant allocates.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
namestringUniform name.
valueMaterialValueThe value variant.
Returns ​

void

Nothing.

setParent() ​
ts
setParent(
   entity, 
   parent, 
   keepWorldTransform
): void;

Reparent an entity.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
parentnumber | undefinedNew parent, or undefined for the scene root.
keepWorldTransformbooleanPreserve the world transform across the move.
Returns ​

void

Nothing.

setPointerLock() ​
ts
setPointerLock(locked): void;

Request or release pointer lock.

Parameters ​
ParameterTypeDescription
lockedbooleanWhether the canvas should hold pointer lock.
Returns ​

void

Nothing.

setTimeScale() ​
ts
setTimeScale(scale): void;

Scale simulated time.

Parameters ​
ParameterTypeDescription
scalenumberMultiplier; 1 is real time.
Returns ​

void

Nothing.

spawn() ​
ts
spawn(
   entity, 
   asset, 
   px, 
   py, 
   pz, 
   qx, 
   qy, 
   qz, 
   qw, 
   sx, 
   sy, 
   sz, 
   name?
): void;

Create an entity in the host scene.

Parameters ​
ParameterTypeDescription
entitynumberGuest-minted entity id.
assetnumber | undefinedRenderable asset handle, or undefined for a bare node.
pxnumberPosition x.
pynumberPosition y.
pznumberPosition z.
qxnumberRotation x.
qynumberRotation y.
qznumberRotation z.
qwnumberRotation w.
sxnumberScale x.
synumberScale y.
sznumberScale z.
name?stringDebug label.
Returns ​

void

Nothing.

spawnCharacter() ​
ts
spawnCharacter(
   entity, 
   bundle, 
   px, 
   py, 
   pz, 
   qx, 
   qy, 
   qz, 
   qw
): void;

Instantiate a splat character bundle.

Parameters ​
ParameterTypeDescription
entitynumberGuest-minted entity id.
bundlenumberCharacter bundle asset handle.
pxnumberPosition x.
pynumberPosition y.
pznumberPosition z.
qxnumberRotation x.
qynumberRotation y.
qznumberRotation z.
qwnumberRotation w.
Returns ​

void

Nothing.

stopSound() ​
ts
stopSound(sound, fadeMs): void;

Stop a playing sound.

Parameters ​
ParameterTypeDescription
soundnumberSound handle.
fadeMsnumberFade-out in milliseconds.
Returns ​

void

Nothing.

take() ​
ts
protected take<T>(tag, make): T;

Take the next pooled slot for a tag, appending it to the frame list.

Type Parameters ​
Type Parameter
T
Parameters ​
ParameterTypeDescription
tag| "send" | "set-player-camera" | "set-player-hud" | "save-player-data" | "save-game-data" | "set-player-entity" | "exchange" | "conversation" | "spawn" | "despawn" | "set-asset" | "set-parent" | "set-anim" | "set-material-param" | "add-body" | "remove-body" | "set-body-transform" | "set-body-velocity" | "apply-impulse" | "set-body-enabled" | "move-character" | "spawn-character" | "set-character-state" | "set-clip-weights" | "set-expression" | "look-at" | "say" | "play-sound" | "stop-sound" | "set-listener" | "load-asset" | "set-pointer-lock" | "set-time-scale"The command tag.
make() => TModule-const factory for a fully shaped payload, called only when the pool has to grow.
Returns ​

T

The payload to mutate. Every field must be written: the slot still holds whatever the last command with this tag left behind.


MessageDef ​

One game message: what defineMessage returns. Pass it to ctx.net.messages and ctx.net.send.

Example ​

ts
const Ready = defineMessage('ready', (p): p is true => p === true);
console.log(Ready.name, Ready.maxBytes); // 'ready' 2048

Type Parameters ​

Type Parameter
T

Constructors ​

Constructor ​
ts
new MessageDef<T>(
   name, 
   check, 
   maxBytes
): MessageDef<T>;
Parameters ​
ParameterTypeDescription
namestringThe message name on the wire.
checkMessageCheck<T>The payload's type guard.
maxBytesnumberThe payload cap in UTF-8 bytes of JSON.
Returns ​

MessageDef<T>

Properties ​

check ​
ts
readonly check: MessageCheck<T>;

The payload's type guard.

maxBytes ​
ts
readonly maxBytes: number;

The payload cap in UTF-8 bytes of JSON.

name ​
ts
readonly name: string;

The message name on the wire.


TransformPacker ​

Packs entity transforms into frame-output.transforms.

One row is written per entity whose dirty flags are non-zero, in ascending entity order — deterministic, and cheaper than a bitecs query for the densely packed id space the SDK mints.

Constructors ​

Constructor ​
ts
new TransformPacker(maxEntities): TransformPacker;
Parameters ​
ParameterTypeDescription
maxEntitiesnumberEntity ceiling; the buffer holds this many rows.
Returns ​

TransformPacker

Properties ​

dirty ​
ts
readonly dirty: Uint8Array;

Per-entity transform-flags accumulated since the last pack.

highWater ​
ts
highWater: number = 0;

Highest entity id pack scans to.

It rises when a higher id is marked and falls back to the last dirty id every pack, so a level that spawned 4,000 entities and despawned all but ten does not keep scanning 4,000 slots a frame.

Methods ​

clear() ​
ts
clear(): void;

Forget every pending flag, for example after restore.

Returns ​

void

Nothing.

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

Accumulate dirty flags for one entity.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
flagsnumberAny combination of TRANSFORM_FLAGS.
Returns ​

void

Nothing.

pack() ​
ts
pack(): Float32Array;

Write every dirty entity into the packed buffer and clear the flags.

Returns ​

Float32Array

A memoised subarray of the internal buffer. The same row count always returns the same object, which is what makes a steady-state tick allocation-free; never retain it across frames.

Interfaces ​

AddBodyCmd ​

Create a rigid body or character controller.

Properties ​

angularDamping ​
ts
angularDamping: number;
body ​
ts
body: number;
entity ​
ts
entity: number;
flags ​
ts
flags: BodyFlags;
friction ​
ts
friction: number;
kind ​
ts
kind: BodyKind;
layer ​
ts
layer: CollisionLayers;
linearDamping ​
ts
linearDamping: number;
mask ​
ts
mask: CollisionLayers;
mass ​
ts
mass: number;
position ​
ts
position: Vec3;
restitution ​
ts
restitution: number;
rotation ​
ts
rotation: Quat;
shape ​
ts
shape: Shape;

AnimEventData ​

An animation clip passed a named marker.

Properties ​

clip ​
ts
clip: string;
entity ​
ts
entity: number;
name ​
ts
name: string;
time ​
ts
time: number;

ApplyImpulseCmd ​

Apply a one-shot impulse.

Properties ​

atPoint? ​
ts
optional atPoint?: Vec3;
body ​
ts
body: number;
impulse ​
ts
impulse: Vec3;

AssetDesc ​

Manifest metadata for one asset handle.

Properties ​

hasCollider ​
ts
hasCollider: boolean;
id ​
ts
id: number;
kind ​
ts
kind: AssetKind;
name ​
ts
name: string;
ready ​
ts
ready: boolean;
rig? ​
ts
optional rig?: string;
tags ​
ts
tags: readonly string[];

AssetLoadedEvent ​

An asset finished loading.

Properties ​

asset ​
ts
asset: number;
name ​
ts
name: string;

Axis2 ​

A two-axis reading. Each facade returns its own object, the same one every call.

Properties ​

x ​
ts
x: number;
y ​
ts
y: number;

BodyFlags ​

Per-body behaviour switches. Omitted keys lower as false.

Properties ​

ccd? ​
ts
optional ccd?: boolean;
debugDraw? ​
ts
optional debugDraw?: boolean;
lockRotation? ​
ts
optional lockRotation?: boolean;
noSleep? ​
ts
optional noSleep?: boolean;
reportContacts? ​
ts
optional reportContacts?: boolean;
sensor? ​
ts
optional sensor?: boolean;

BodySpec ​

The physics body a prefab carries.

Properties ​

dims? ​
ts
optional dims?: readonly number[];

Shape dimensions. box: half extents. sphere: [radius]. capsule / cylinder: [radius, halfHeight]. plane: the normal.

flags? ​
ts
optional flags?: BodyFlags;

Per-body switches.

friction? ​
ts
optional friction?: number;

Coulomb friction. Default 0.5.

kind ​
ts
kind: BodyKind;

Body class. 'character' makes a CharacterVirtual controller.

layer? ​
ts
optional layer?: CollisionLayers;

What this body is. Default { defaultLayer: true }.

mask? ​
ts
optional mask?: CollisionLayers;

What this body collides with. Default every layer.

mass? ​
ts
optional mass?: number;

Kilograms; ignored for fixed and kinematic bodies. Default 1.

restitution? ​
ts
optional restitution?: number;

Bounciness in 0..1. Default 0.

shape ​
ts
shape: ShapeKind;

Collision shape family.


CameraState ​

The camera the host should render from this frame.

Properties ​

armLength ​
ts
armLength: number;
far ​
ts
far: number;
follow? ​
ts
optional follow?: number;
fovYDeg ​
ts
fovYDeg: number;
mode ​
ts
mode: CameraMode;
near ​
ts
near: number;
offset ​
ts
offset: Vec3;
position ​
ts
position: Vec3;
projection ​
ts
projection: ProjectionKind;
rotation ​
ts
rotation: Quat;
target? ​
ts
optional target?: Vec3;

CharacterReadyEvent ​

A character bundle finished loading and reported its expression space.

Properties ​

bundle ​
ts
bundle: number;
entity ​
ts
entity: number;
expressionDim ​
ts
expressionDim: number;
space ​
ts
space: ExpressionSpace;

CharacterStore ​

Splat character bundle handle.

Properties ​

bundle ​
ts
bundle: Uint32Array;

Character bundle asset handle.

dirty ​
ts
dirty: Uint8Array;

Non-zero when the host has not yet seen the current value.


CollisionLayers ​

Broad-phase layer set. Omitted keys lower as false.

Properties ​

character? ​
ts
optional character?: boolean;
debris? ​
ts
optional debris?: boolean;
defaultLayer? ​
ts
optional defaultLayer?: boolean;
enemy? ​
ts
optional enemy?: boolean;
pickup? ​
ts
optional pickup?: boolean;
player? ​
ts
optional player?: boolean;
projectile? ​
ts
optional projectile?: boolean;
staticGeometry? ​
ts
optional staticGeometry?: boolean;
trigger? ​
ts
optional trigger?: boolean;
user0? ​
ts
optional user0?: boolean;
user1? ​
ts
optional user1?: boolean;
user2? ​
ts
optional user2?: boolean;
user3? ​
ts
optional user3?: boolean;
user4? ​
ts
optional user4?: boolean;
user5? ​
ts
optional user5?: boolean;
water? ​
ts
optional water?: boolean;

Contact ​

One reported contact between two bodies.

Properties ​

a ​
ts
a: number;
b ​
ts
b: number;
entityA ​
ts
entityA: number;
entityB ​
ts
entityB: number;
impulse ​
ts
impulse: number;
normal ​
ts
normal: Vec3;
phase ​
ts
phase: ContactPhase;
point ​
ts
point: Vec3;

ConversationCmd ​

Structural interview controls; service addresses stay in host configuration.

Properties ​

action ​
ts
action: 
  | "end"
  | "start"
  | "ask"
  | "interrupt"
  | "microphone-on"
  | "microphone-off";
character ​
ts
character: string;
entity ​
ts
entity: number;
text ​
ts
text: string;

ConversationEvent ​

Low-frequency conversation UI/input event. No audio or facial frames cross WIT.

Properties ​

entity ​
ts
entity: number;
kind ​
ts
kind: "error" | "input" | "status" | "subtitle" | "story";
text ​
ts
text: string;

Story events carry the versioned full snapshot as JSON.


DataFacade ​

The ctx.data facade, one per guest. Only the authority writes: on a client every call is a no-op (logged once).

Saving is not free: save serialises the document. Call it when the document changed, not every tick; the room writes at most one per player every 6 s anyway, and always when the player leaves or the room closes.

Example ​

ts
function earn(ctx: GameContext): void {
  for (const [id, p] of ctx.players) {
    const doc = (p.data ?? { coins: 0 }) as { coins: number };
    if (ctx.frame % 600 === 0) ctx.data.save(id, { ...doc, coins: doc.coins + 1 });
  }
  for (const r of ctx.data.results()) if (!r.ok) ctx.net.send('trade-failed', { id: r.id, why: r.reason });
}

Accessors ​

game ​
Get Signature ​
ts
get game(): unknown;
Returns ​

unknown

The game's own saved document, once the room has handed it over; else null.

Methods ​

exchange() ​
ts
exchange(
   a, 
   b, 
   give, 
   take
): number;

Trade between two players, all or nothing: a gives b everything in give and takes from b everything in take (numbers move amounts, lists move items; see applyTransfer). The result arrives as an exchange-result event a tick or more later, in DataFacade.results; on success both players' data already show the trade.

Parameters ​
ParameterTypeDescription
anumberThe first player.
bnumberThe second player.
giveTransferDocWhat a gives b, such as { coins: 5 }.
takeTransferDocWhat a takes from b, such as { owned: ['gem'] }.
Returns ​

number

The exchange's id, or 0 on a client.

results() ​
ts
results(): readonly Pick<ExchangeResultEvent, "id" | "ok" | "reason">[];
Returns ​

readonly Pick<ExchangeResultEvent, "id" | "ok" | "reason">[]

This tick's exchange results, in arrival order; reused, read during the tick.

save() ​
ts
save(player, doc): void;

Keep a player's document. ctx.players.get(player).data is the new document at once; the room writes it to its store (throttled).

Parameters ​
ParameterTypeDescription
playernumberA joined player.
docunknownAny JSON value; at most 64 KB as JSON.
Returns ​

void

saveGame() ​
ts
saveGame(doc): void;

Keep the game's own document (one per game, shared by every room).

Parameters ​
ParameterTypeDescription
docunknownAny JSON value; at most 64 KB as JSON.
Returns ​

void


ExchangeCmd ​

Trade between two players' documents; the result is an exchange-result event.

Properties ​

a ​
ts
a: number;
b ​
ts
b: number;
give ​
ts
give: string;

JSON: what a gives b.

id ​
ts
id: number;

Guest-minted; echoed in the result.

take ​
ts
take: string;

JSON: what a takes from b.


ExchangeResultEvent ​

The outcome of an exchange command, matched by its id.

Properties ​

aData ​
ts
aData: string;

Player a's document after the trade, as the store wrote it (JSON); empty unless ok.

bData ​
ts
bData: string;

Player b's document after the trade (JSON); empty unless ok.

id ​
ts
id: number;
ok ​
ts
ok: boolean;
reason ​
ts
reason: string;

Empty when ok.


FeatureSpec ​

The features a game may declare. A key that is false is the same as absent.

Properties ​

characters? ​
ts
optional characters?: boolean;

The splat character bridge (spawn-character and friends).

multiplayer? ​
ts
optional multiplayer?: boolean | MultiplayerOptions;

Rooms, players and replication.


FirstPersonOptions ​

Options for camera.firstPerson.

Properties ​

eyeHeight? ​
ts
optional eyeHeight?: number;

Eye height above the entity origin, metres. Default 1.7.

fovYDeg? ​
ts
optional fovYDeg?: number;

Vertical field of view in degrees. Default 75.


FollowOptions ​

Options for camera.follow.

Properties ​

distance? ​
ts
optional distance?: number;

Boom length behind the target, metres. Default 4.

fovYDeg? ​
ts
optional fovYDeg?: number;

Vertical field of view in degrees. Default 60.

height? ​
ts
optional height?: number;

Rig-local height offset, metres. Default 1.6.

pitch? ​
ts
optional pitch?: number;

Orbit pitch in radians; positive looks up. Defaults to the accumulator.

yaw? ​
ts
optional yaw?: number;

Orbit yaw in radians about +Y; 0 puts the camera behind the target.

Defaults to the built-in look accumulator. Pass it when the game keeps its own orbit — a third-person camera usually wants a tighter pitch range and its own sensitivity than the first-person one the accumulator is tuned for.


FrameInput ​

One fixed simulation step of host state handed to the guest.

Properties ​

bodies ​
ts
bodies: ArrayLike<number>;

Post-step body transforms, stride 15, sorted ascending by body id.

contacts ​
ts
contacts: readonly Contact[];
dt ​
ts
dt: number;
elapsed ​
ts
elapsed: number;
events ​
ts
events: readonly GameEvent[];
frame ​
ts
frame: number | bigint;

Monotonic fixed-step counter. jco lifts u64 as a bigint on the host and a number in the guest, so both are legal here; the runtime Number()s it once, on the way in.

input ​
ts
input: InputState;
players ​
ts
players: readonly PlayerInput[];

Every player's input in a room, ascending by id. Empty for a single-player game. A held seat (its player dropped) is left out until they are back.


FrameOutput ​

Everything the guest hands back for one fixed step.

Properties ​

camera ​
ts
camera: CameraState;
commands ​
ts
commands: readonly Command[];
hud? ​
ts
optional hud?: string;

HUD JSON, present only on the frames it changed.

localCommands ​
ts
localCommands: readonly Command[];

Applied by the authority after commands; never forwarded to a client.

transforms ​
ts
transforms: Float32Array;

Entity transforms, stride 12. Never empty: see the zero-row rule.


GameConfig ​

The init payload.

Properties ​

devMode ​
ts
devMode: boolean;
fixedHz ​
ts
fixedHz: number;
options? ​
ts
optional options?: string;
seed ​
ts
seed: number | bigint;

Deterministic run seed. A bigint on the host, a number in the guest; the runtime Number()s it once, on the way in.

viewportHeight ​
ts
viewportHeight: number;
viewportWidth ​
ts
viewportWidth: number;

GameContext ​

Everything a system can reach.

The same object is handed to every system on every frame — it is mutated in place, never rebuilt, so never retain it or destructure frame outside the call.

Properties ​

audio ​
ts
readonly audio: object;

Sound playback.

listener() ​
ts
listener(position, rotation): void;

Place the audio listener.

Parameters ​
ParameterTypeDescription
positionVec3Listener position.
rotationQuatListener rotation, xyzw.
Returns ​

void

Nothing.

play() ​
ts
play(asset, options?): number;

Start a sound.

Parameters ​
ParameterTypeDescription
assetstring | numberManifest string id or asset handle.
options?PlayOptionsAttachment, gain, pitch, looping and bus.
Returns ​

number

The guest-minted sound handle, or 0 when the asset is unknown.

stop() ​
ts
stop(sound, fadeMs?): void;

Stop a playing sound.

Parameters ​
ParameterTypeDefault valueDescription
soundnumberundefinedA handle from play.
fadeMsnumber0Fade-out in milliseconds; 0 stops immediately.
Returns ​

void

Nothing.

camera ​
ts
readonly camera: object;

The camera record for this frame.

look ​
Get Signature ​
ts
get look(): object;

Accumulated look angles, in radians. Mutate to snap the view.

Returns ​

object

The live look state.

pitch ​
ts
pitch: number;
sensitivity ​
ts
sensitivity: number;
yaw ​
ts
yaw: number;
state ​
Get Signature ​
ts
get state(): CameraState;

The whole camera record, for games that want every knob.

Returns ​

CameraState

The live record. Mutate it; do not replace it.

firstPerson() ​
ts
firstPerson(entity, options?): void;

Mount the camera at an entity's eyes.

Yaw and pitch come from the built-in look accumulator, which integrates input.mouse.dx/dy once per tick.

Parameters ​
ParameterTypeDescription
entitynumberEntity to mount on.
options?FirstPersonOptionsEye height and field of view.
Returns ​

void

Nothing.

follow() ​
ts
follow(entity, options?): void;

Put the camera on a spring arm behind an entity.

The host owns the arm and its collision; the guest only states the intent. position is the orbit pivot and rotation the direction the player is looking, so a host with no rig still ends up somewhere sensible.

Parameters ​
ParameterTypeDescription
entitynumberEntity to follow.
options?FollowOptionsBoom length, height offset, field of view and orbit angles.
Returns ​

void

Nothing.

lookAt() ​
ts
lookAt(point): void;

Aim the camera at a world point, overriding its rotation.

Parameters ​
ParameterTypeDescription
pointVec3 | nullThe point to look at, or null to use the rotation again.
Returns ​

void

Nothing.

set() ​
ts
set(
   position, 
   rotation, 
   fovYDeg?
): void;

Place the camera explicitly, detaching it from any entity.

Parameters ​
ParameterTypeDefault valueDescription
positionVec3undefinedEye position.
rotationQuatundefinedEye rotation, xyzw.
fovYDegnumber60Vertical field of view in degrees. Default 60.
Returns ​

void

Nothing.

character ​
ts
readonly character: object;

Splat characters.

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

The character bundle handle attached to an entity, or 0.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
Returns ​

number

The bundle asset handle.

lookAt() ​
ts
lookAt(
   entity, 
   target, 
   weight?
): void;

Aim the head and eyes at a world point.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity with a Character component.
targetVec3 | nullundefinedThe point, or null to release and return to the idle.
weightnumber1Blend weight in 0..1. Default 1.
Returns ​

void

Nothing.

say() ​
ts
say(
   entity, 
   text, 
   voice?, 
   visemes?
): void;

Speak a line.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a Character component.
textstringSubtitle text; the host decides whether to show it.
voice?string | numberManifest string id or handle of a voice line.
visemes?stringViseme track as JSON, matching the bundle's space.
Returns ​

void

Nothing.

setClipWeights() ​
ts
setClipWeights(
   entity, 
   clips, 
   weights, 
   timeScale?
): void;

Set explicit per-clip weights on the body layer.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity with a Character component.
clipsreadonly string[]undefinedClip names.
weightsFloat32Array<ArrayBufferLike> | readonly number[]undefinedPositional weights; must be the same length as clips.
timeScalenumber1Playback rate for the whole layer. Default 1.
Returns ​

void

Nothing.

setExpression() ​
ts
setExpression(
   entity, 
   space, 
   weights
): void;

Set facial expression coefficients.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a Character component.
spaceExpressionSpaceCoordinate space: 52 ARKit, 387 GNM, or the 68-float view.
weightsFloat32Array<ArrayBufferLike> | readonly number[]Coefficients; length must match the space.
Returns ​

void

Nothing.

setState() ​
ts
setState(
   entity, 
   state, 
   vx, 
   vy, 
   vz, 
   grounded?
): void;

Drive the locomotion state machine.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity with a Character component.
statestringundefinedState name, for example `'idle'
vxnumberundefinedWorld-space velocity x, drives the locomotion blend.
vynumberundefinedWorld-space velocity y.
vznumberundefinedWorld-space velocity z.
groundedbooleantrueWhether the character is on the ground.
Returns ​

void

Nothing.

config ​
ts
readonly config: GameConfig;

The init config.

contacts ​
ts
readonly contacts: readonly Contact[];

Contacts reported since the previous tick.

data ​
ts
readonly data: DataFacade;

Player documents and the game's own document in the room's store, and trades between two players. The authority writes; a client's calls do nothing.

dt ​
ts
readonly dt: number;

Fixed timestep in seconds.

elapsed ​
ts
readonly elapsed: number;

Simulated seconds since init.

events ​
ts
readonly events: readonly GameEvent[];

Host-side occurrences since the previous tick, in order.

frame ​
ts
readonly frame: number;

Monotonic fixed-step counter, starting at 0.

hud ​
ts
readonly hud: object;

The HUD model.

clear() ​
ts
clear(): void;

Drop the HUD: emit an empty model this frame.

Idempotent — calling it every frame emits {} once, exactly like set.

Returns ​

void

Nothing.

invalidate() ​
ts
invalidate(): void;

Forget what the host has seen, so the next set emits even if the model did not change. Use it after the host reloaded its overlay.

On its own it sends nothing: the next set does. To send an empty model now, call clear().

Returns ​

void

Nothing.

set() ​
ts
set(model): boolean;

Set the HUD model for this frame.

Nested plain objects are compared by value four levels down, so a model rebuilt inline every frame is recognised as unchanged. Arrays and class instances are compared by identity: keep those out of the model, or build them once and mutate nothing.

Parameters ​
ParameterTypeDescription
modelRecord<string, unknown>A JSON-serialisable object.
Returns ​

boolean

True when the model changed and JSON will cross this frame.

input ​
ts
readonly input: object;

Keyboard, mouse and gamepad.

focused ​
Get Signature ​
ts
get focused(): boolean;

Does the canvas have focus? Treat input as neutral when it does not.

Returns ​

boolean

True while the canvas is focused.

mods ​
Get Signature ​
ts
get mods(): InputMods;

Keyboard modifier state.

Returns ​

InputMods

The modifiers for this frame.

mouse ​
Get Signature ​
ts
get mouse(): MouseState;

Pointer position, per-frame delta, wheel and button bitsets.

Returns ​

MouseState

The mouse state for this frame. Owned by the SDK; never retain it.

axis2() ​
ts
axis2(
   negX, 
   posX, 
   negY, 
   posY
): Axis2;

A two-axis reading built from four keys.

Parameters ​
ParameterTypeDescription
negXstringKey that drives x negative, for example 'A'.
posXstringKey that drives x positive, for example 'D'.
negYstringKey that drives y negative, for example 'S'.
posYstringKey that drives y positive, for example 'W'.
Returns ​

Axis2

A pooled { x, y } with components in -1..1. Never retain it.

gamepad() ​
ts
gamepad(index): 
  | {
  axes: ArrayLike<number>;
  buttons: number;
  connected: boolean;
  index: number;
  pressed: number;
  released: number;
}
  | null;

One connected gamepad.

Parameters ​
ParameterTypeDescription
indexnumberNavigator gamepad index.
Returns ​

| { axes: ArrayLike<number>; buttons: number; connected: boolean; index: number; pressed: number; released: number; } | null

The gamepad, or null when nothing is connected at that index. Owned by the SDK; never retain it.

isDown() ​
ts
isDown(key): boolean;

Is the key held this frame?

Parameters ​
ParameterTypeDescription
keystringA DOM code ('KeyW'), a bare letter/digit ('W', '1') or an alias ('Shift', 'Esc').
Returns ​

boolean

True while the key is down.

mouseDown() ​
ts
mouseDown(button): boolean;

Is a mouse button held?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True while the button is down.

mousePressed() ​
ts
mousePressed(button): boolean;

Did a mouse button go down this frame?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True on the frame the button went down.

mouseReleased() ​
ts
mouseReleased(button): boolean;

Did a mouse button come up this frame?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True on the frame the button came up.

pressed() ​
ts
pressed(key): boolean;

Did the key go down this frame?

Parameters ​
ParameterTypeDescription
keystringA key name.
Returns ​

boolean

True on the frame the key went down.

released() ​
ts
released(key): boolean;

Did the key come up this frame?

Parameters ​
ParameterTypeDescription
keystringA key name.
Returns ​

boolean

True on the frame the key came up.

localPlayer ​
ts
readonly localPlayer: PlayerHandle | null;

The player this page belongs to, on a client; null on the authority and in solo.

net ​
ts
readonly net: NetFacade;

Where this guest runs, game messages in and out, and local-only commands.

physics ​
ts
readonly physics: object;

Physics queries and body commands.

ALL_LAYERS ​
ts
ALL_LAYERS: CollisionLayers;

Every collision layer, for queries that should hit anything.

applyImpulse() ​
ts
applyImpulse(
   entity, 
   x, 
   y, 
   z, 
   atX?, 
   atY?, 
   atZ?
): void;

Apply a one-shot impulse.

With no application point the impulse acts at the centre of mass. Give one — all three coordinates — to apply it off-centre and impart spin.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
xnumberImpulse x, newton-seconds.
ynumberImpulse y.
znumberImpulse z.
atX?numberWorld-space application point x, or omit for the centre of mass.
atY?numberApplication point y.
atZ?numberApplication point z.
Returns ​

void

Nothing.

isGrounded() ​
ts
isGrounded(entity): boolean;

Actual walkable ground contact from the last host physics step. No host call. Unknown, steep and unsupported contacts return false, even at a jump apex.

Parameters ​
ParameterTypeDescription
entitynumberCharacter entity.
Returns ​

boolean

Whether the character is supported by walkable ground.

moveCharacter() ​
ts
moveCharacter(
   entity, 
   vx, 
   vy, 
   vz, 
   jump?, 
   crouch?, 
   maxSlopeDeg?
): void;

Drive a character body for this step.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity whose body was created with kind: 'character'.
vxnumberundefinedDesired world-space velocity x, metres per second.
vynumberundefinedDesired world-space velocity y.
vznumberundefinedDesired world-space velocity z.
jumpbooleanfalseRequest a jump this step.
crouchbooleanfalseRequest a crouch this step.
maxSlopeDegnumber45Maximum walkable slope.
Returns ​

void

Nothing.

overlapSphere() ​
ts
overlapSphere(
   center, 
   radius, 
   maxResults?, 
   mask?, 
   ignoreEntity?
): readonly OverlapHit[];

Bodies overlapping a sphere, nearest first.

Parameters ​
ParameterTypeDefault valueDescription
centerVec3undefinedSphere centre.
radiusnumberundefinedSphere radius in metres.
maxResultsnumber16Cap on returned hits.
mask?CollisionLayersundefinedLayers to consider; defaults to every layer.
ignoreEntity?numberundefinedEntity to skip.
Returns ​

readonly OverlapHit[]

The overlapping bodies.

raycast() ​
ts
raycast(
   origin, 
   direction, 
   maxDistance, 
   mask?, 
   ignoreEntity?
): RayHit | null;

Closest hit along a ray.

Parameters ​
ParameterTypeDescription
originVec3World-space ray origin.
directionVec3Ray direction; need not be normalised.
maxDistancenumberMaximum distance in metres.
mask?CollisionLayersLayers to consider; defaults to every layer.
ignoreEntity?numberEntity to skip, usually the caster.
Returns ​

RayHit | null

The hit, or null on a miss. The hit object comes from the host and is freshly allocated: this call is not allocation-free.

raycastBatch() ​
ts
raycastBatch(rays): readonly (RayHit | null | undefined)[];

Many rays in one round trip. Result index i matches rays[i].

Parameters ​
ParameterTypeDescription
raysreadonly object[]The rays. Build them once and mutate them in place.
Returns ​

readonly (RayHit | null | undefined)[]

One result per ray; undefined or null entries are misses.

setEnabled() ​
ts
setEnabled(entity, enabled): void;

Enable or disable a body in the broad phase.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
enabledbooleanWhether the body participates.
Returns ​

void

Nothing.

setVelocity() ​
ts
setVelocity(
   entity, 
   x, 
   y, 
   z, 
   ax?, 
   ay?, 
   az?
): void;

Overwrite a body's velocity.

Angular velocity is left alone unless all three angular components are given.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
xnumberLinear velocity x.
ynumberLinear velocity y.
znumberLinear velocity z.
ax?numberAngular velocity x, radians per second.
ay?numberAngular velocity y.
az?numberAngular velocity z.
Returns ​

void

Nothing.

teleport() ​
ts
teleport(
   entity, 
   x, 
   y, 
   z
): void;

Teleport a body, clearing its velocities.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
xnumberPosition x.
ynumberPosition y.
znumberPosition z.
Returns ​

void

Nothing.

player ​
ts
readonly player: number;

The entity the declarative player block spawned in a single-player game, or 0. In a room each player has their own: playerEntity(id).

players ​
ts
readonly players: Players;

The room's players by id: everyone joined and not yet left, plus anyone whose input is in this step's frame-input.players. Empty for a single-player game. Rebuilt only when that set changes, never per tick. Also says who the host is (host) and lists the players in id order (list), which a system walks without allocating.

rng ​
ts
readonly rng: Rng;

The seeded generator. Never Math.random.

rules ​
ts
readonly rules: Readonly<Record<string, unknown>>;

The rules object from defineGame, verbatim.

world ​
ts
readonly world: object;

The bitecs world, for query, addComponent and friends.

Methods ​

assetId() ​
ts
assetId(name): number;

Resolve a manifest string id to a handle, cached.

Parameters ​
ParameterType
namestring
Returns ​

number

despawn() ​
ts
despawn(entity): void;

Destroy an entity and its body.

Parameters ​
ParameterType
entitynumber
Returns ​

void

playerEntity() ​
ts
playerEntity(id): number;

The entity definition.player spawned for a room player, or 0.

Parameters ​
ParameterType
idnumber
Returns ​

number

spawn() ​
ts
spawn(
   def, 
   position, 
   rotation?
): number;

Instantiate a prefab.

Parameters ​
ParameterType
defPrefabDef
positionVec3
rotation?Quat
Returns ​

number


GameDataEvent ​

The room's saved game-wide document as JSON.

Properties ​

data ​
ts
data: string;

GameError ​

The error payload of init and restore.

Properties ​

code ​
ts
code: ErrorCode;
message ​
ts
message: string;

GamepadState ​

One gamepad in the standard mapping.

Properties ​

axes ​
ts
axes: ArrayLike<number>;
buttons ​
ts
buttons: number;
connected ​
ts
connected: boolean;
index ​
ts
index: number;
pressed ​
ts
pressed: number;
released ​
ts
released: number;

GameSpec ​

Everything a game declares.

Properties ​

assets? ​
ts
optional assets?: readonly string[];

Manifest string ids to resolve during init and cache.

features? ​
ts
optional features?: FeatureSpec;

Optional engine modules this game needs. See featuresOf.

init? ​
ts
optional init?: (ctx) => void;

Extra setup, run after the declarative spawns.

Parameters ​
ParameterType
ctxGameContext
Returns ​

void

player? ​
ts
optional player?: PlayerSpec;

The player and its camera. Spawned once at init in a single-player game; on the authority of a room, once per joined player instead.

restore? ​
ts
optional restore?: (state) => void;

Read back what snapshot returned.

Parameters ​
ParameterType
stateunknown
Returns ​

void

rules? ​
ts
optional rules?: Record<string, unknown>;

Arbitrary tuning values, handed back as ctx.rules.

shutdown? ​
ts
optional shutdown?: (ctx) => void;

Called once before the guest is torn down.

Parameters ​
ParameterType
ctxGameContext
Returns ​

void

snapshot? ​
ts
optional snapshot?: () => unknown;

Extra state to fold into snapshot(). Must be JSON-serialisable.

Returns ​

unknown

spawns? ​
ts
optional spawns?: readonly SpawnSpec[];

Entities to create during init.

systems? ​
ts
optional systems?: readonly (System | SidedSystem)[];

User systems, run in order after the built-ins. A bare function runs on the authority once features.multiplayer is declared, everywhere otherwise; { run, on } says where explicitly.

update? ​
ts
optional update?: (ctx) => void;

Convenience: one more system, run after systems.

Parameters ​
ParameterType
ctxGameContext
Returns ​

void

world? ​
ts
optional world?: WorldSpec;

World settings.


Guest ​

A guest instance: the five WIT exports plus a liveness flag.

Extends ​

Properties ​

dead ​
ts
readonly dead: boolean;

True once the runtime has given up on user code.

state ​
ts
readonly state: RuntimeState;

The runtime, for tests and tooling.

Methods ​

init() ​
ts
init(config): void;
Parameters ​
ParameterType
configGameConfig
Returns ​

void

Inherited from ​

GuestExports.init

restore() ​
ts
restore(state): void;
Parameters ​
ParameterType
stateArrayLike<number>
Returns ​

void

Inherited from ​

GuestExports.restore

shutdown() ​
ts
shutdown(): void;
Returns ​

void

Inherited from ​

GuestExports.shutdown

snapshot() ​
ts
snapshot(): Uint8Array;
Returns ​

Uint8Array

Inherited from ​

GuestExports.snapshot

tick() ​
ts
tick(input): FrameOutput;
Parameters ​
ParameterType
inputFrameInput
Returns ​

FrameOutput

Inherited from ​

GuestExports.tick


GuestExports ​

The five functions the WIT game interface exports.

Extended by ​

Methods ​

init() ​
ts
init(config): void;
Parameters ​
ParameterType
configGameConfig
Returns ​

void

restore() ​
ts
restore(state): void;
Parameters ​
ParameterType
stateArrayLike<number>
Returns ​

void

shutdown() ​
ts
shutdown(): void;
Returns ​

void

snapshot() ​
ts
snapshot(): Uint8Array;
Returns ​

Uint8Array

tick() ​
ts
tick(input): FrameOutput;
Parameters ​
ParameterType
inputFrameInput
Returns ​

FrameOutput


HealthStore ​

Current and maximum hit points.

Properties ​

current ​
ts
current: Float32Array;
max ​
ts
max: Float32Array;

HostApi ​

The host services a guest may call, in guest-side JS shapes.

This is the SDK's own narrow view of the three gameable:engine import interfaces. packages/sdk/src/wit/entry.ts adapts the real WIT imports to it; gameable/test implements it directly for node tests.

Methods ​

describe() ​
ts
describe(id): AssetDesc | null | undefined;

Metadata for a handle, or nullish when the handle is unknown.

Parameters ​
ParameterType
idnumber
Returns ​

AssetDesc | null | undefined

log() ​
ts
log(level, msg): void;

Route a message to the host logger.

Parameters ​
ParameterType
levelLogLevel
msgstring
Returns ​

void

nowMs() ​
ts
nowMs(): number;

Monotonic milliseconds since engine start. Never feed this to simulation.

Returns ​

number

overlapSphere() ​
ts
overlapSphere(
   center, 
   radius, 
   filter, 
   maxResults
): readonly OverlapHit[];

Bodies overlapping a sphere, nearest first.

Parameters ​
ParameterType
centerVec3
radiusnumber
filterQueryFilter
maxResultsnumber
Returns ​

readonly OverlapHit[]

raycast() ​
ts
raycast(
   origin, 
   direction, 
   maxDistance, 
   filter
): RayHit | null | undefined;

Closest hit along a ray, or nullish on a miss.

Parameters ​
ParameterType
originVec3
directionVec3
maxDistancenumber
filterQueryFilter
Returns ​

RayHit | null | undefined

raycastBatch() ​
ts
raycastBatch(rays): readonly (RayHit | null | undefined)[];

One round trip for many rays; result index i matches rays[i].

Parameters ​
ParameterType
raysreadonly RayQuery[]
Returns ​

readonly (RayHit | null | undefined)[]

resolveId() ​
ts
resolveId(name): number | null | undefined;

Manifest string id to handle, or nullish when the manifest has no entry.

Parameters ​
ParameterType
namestring
Returns ​

number | null | undefined

seed() ​
ts
seed(): number;

The deterministic run seed, as a number (already Number()-coerced).

Returns ​

number


HostFrameInput ​

frame-input in host-side shapes.

jco lifts u64 to bigint on the host and to number in the guest, and the host is free to hand over real typed arrays. Everything else is identical, which is why the guest types accept ArrayLike<number>.

Properties ​

bodies ​
ts
bodies: Float32Array;
contacts ​
ts
contacts: readonly Contact[];
dt ​
ts
dt: number;
elapsed ​
ts
elapsed: number;
events ​
ts
events: readonly GameEvent[];
frame ​
ts
frame: bigint;
input ​
ts
input: InputState;
players ​
ts
players: readonly PlayerInput[];

HostGameConfig ​

game-config in host-side shapes: seed is a bigint.

Properties ​

devMode ​
ts
devMode: boolean;
fixedHz ​
ts
fixedHz: number;
options? ​
ts
optional options?: string;
seed ​
ts
seed: bigint;
viewportHeight ​
ts
viewportHeight: number;
viewportWidth ​
ts
viewportWidth: number;

HudState ​

HUD change detection state.

Properties ​

last ​
ts
last: Record<string, unknown> | null;

Shallow copy of the last model the game set, or null before the first.

pending ​
ts
pending: string | undefined;

JSON to emit this frame, or undefined when the model did not change.


InputMods ​

Keyboard modifier state. Every key is present on input.

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;

InputState ​

Everything the host knows about input for one fixed step.

Properties ​

focused ​
ts
focused: boolean;
gamepads ​
ts
gamepads: readonly GamepadState[];
keys ​
ts
keys: KeyState;
mods ​
ts
mods: InputMods;
mouse ​
ts
mouse: MouseState;

KeyState ​

256 key codes packed into 8 u32 words, one list per edge.

Properties ​

down ​
ts
down: ArrayLike<number>;
pressed ​
ts
pressed: ArrayLike<number>;
released ​
ts
released: ArrayLike<number>;

LoadAssetCmd ​

Ask the host to start loading an asset.

Properties ​

asset ​
ts
asset: number;
priority ​
ts
priority: number;

LookAtCmd ​

Aim a character's head and eyes at a world point.

Properties ​

entity ​
ts
entity: number;
target? ​
ts
optional target?: Vec3;
weight ​
ts
weight: number;

LookState ​

First-person / third-person look accumulator owned by the built-in camera.

Properties ​

pitch ​
ts
pitch: number;
sensitivity ​
ts
sensitivity: number;
yaw ​
ts
yaw: number;

MessageOptions ​

Options for defineMessage.

Example ​

ts
const Chat = defineMessage('chat', (p): p is string => typeof p === 'string', { maxBytes: 256 });

Properties ​

maxBytes? ​
ts
optional maxBytes?: number;

The largest payload, in UTF-8 bytes of its JSON; 1 to 2,048. Default 2,048, the wire cap.


MouseState ​

Pointer position, deltas, wheel and button edges for one frame.

Properties ​

buttons ​
ts
buttons: number;
dx ​
ts
dx: number;
dy ​
ts
dy: number;
locked ​
ts
locked: boolean;
pressed ​
ts
pressed: number;
released ​
ts
released: number;
wheel ​
ts
wheel: number;
x ​
ts
x: number;
y ​
ts
y: number;

MoveCharacterCmd ​

Drive a character body for one step.

Properties ​

body ​
ts
body: number;
crouch ​
ts
crouch: boolean;
desiredVelocity ​
ts
desiredVelocity: Vec3;
jump ​
ts
jump: boolean;
maxSlopeDeg ​
ts
maxSlopeDeg: number;

MultiplayerOptions ​

Options for the multiplayer feature.

Properties ​

maxPlayers? ​
ts
optional maxPlayers?: number;

Seats in a room, ids 0..maxPlayers - 1. Default 8. roomSeats reads it, for the guest's player slots and for the room's door alike.

predict? ​
ts
optional predict?: boolean;

Predict each page's own character body: the page steps its own Jolt world (the level's static colliders and the body its client guest adds for its player) so the player moves on key-down, and the authority's rows correct it. Default false. See the multiplayer concept page.

sendHz? ​
ts
optional sendHz?: number;

Transform rows per second sent to each player. Default 20.


MutableGamepad ​

A gamepad snapshot the SDK owns and reuses every frame.

Properties ​

axes ​
ts
axes: Float32Array;

Standard mapping: lx, ly, rx, ry, left trigger, right trigger.

buttons ​
ts
buttons: number;
connected ​
ts
connected: boolean;
index ​
ts
index: number;
pressed ​
ts
pressed: number;
released ​
ts
released: number;

NetFacade ​

The ctx.net facade, one per guest.

Example ​

ts
function votes(ctx: GameContext): void {
  if (!ctx.net.isAuthority) return;
  for (const vote of ctx.net.messages(Vote)) {
    ctx.net.send('voted', { by: vote.player, for: vote.payload.for });
  }
  ctx.net.local(() => ctx.audio.play('tick')); // never sent to a player
}

Properties ​

stats ​
ts
readonly stats: NetStats;

Counters since init.

Accessors ​

isAuthority ​
Get Signature ​
ts
get isAuthority(): boolean;
Returns ​

boolean

True on the authority and in a single-player game.

localPlayer ​
Get Signature ​
ts
get localPlayer(): number;
Returns ​

number

The player this page belongs to on a client; 0 elsewhere.

role ​
Get Signature ​
ts
get role(): NetRole;
Returns ​

NetRole

Where this guest runs.

Methods ​

beginTick() ​
ts
beginTick(): void;

Start a tick: this tick's messages are read afresh. Runtime only.

Returns ​

void

local() ​
ts
local(fn): void;

Run fn with every command it queues routed to frame-output.local-commands: applied where this guest runs, never sent to a player. Nested calls stay local; a throw still restores the network buffer. Allocates nothing.

Parameters ​
ParameterTypeDescription
fn() => voidThe code whose commands stay local.
Returns ​

void

messages() ​
ts
messages<T>(message): readonly NetMessage<T>[];

This tick's validated messages for one definition, in arrival order.

A payload over the definition's maxBytes, not JSON, or failing its check is dropped and counted in stats.dropped, never thrown at a system; the rest count in stats.received. The list and its entries are pooled and refilled each tick: read them inside the tick, never retain them. Reading the same name twice in a tick counts nothing twice.

A bare name (deprecated) reads the same list without a check, unless the name's definition has been read before in this run; it caps at 2,048 bytes.

Type Parameters ​
Type Parameter
T
Parameters ​
ParameterTypeDescription
messagestring | MessageDef<T>The definition, or a bare message name.
Returns ​

readonly NetMessage<T>[]

The messages, { player, payload }.

reset() ​
ts
reset(): void;

Forget the counters and every cached message list. init only.

Returns ​

void

send() ​
Call Signature ​
ts
send<T>(
   message, 
   payload, 
   options?
): void;

Send a game message: from the authority to one player or all of them, from a client up to the authority (to is ignored there).

Pass a defineMessage definition to check the payload with its guard and cap it at its maxBytes before it leaves; a bare name (deprecated) checks only the 2,048-byte wire cap.

The payload is serialised with JSON.stringify, so a tick that sends allocates that one string; a tick that sends nothing allocates nothing. undefined sends null.

Type Parameters ​
Type Parameter
T
Parameters ​
ParameterTypeDescription
messageMessageDef<T>The definition, or a bare message name.
payloadTAnything JSON-serialisable; at most maxBytes (2,048) as UTF-8 JSON.
options?SendOptionsto one player, and reliable (default true). A payload that does not serialise (a function or a symbol), fails the definition's check, or whose JSON is over the cap sends nothing and counts in stats.unsent; it never throws, since a throwing system fails the tick.
Returns ​

void

Call Signature ​
ts
send(
   name, 
   payload, 
   options?
): void;

Send a game message: from the authority to one player or all of them, from a client up to the authority (to is ignored there).

Pass a defineMessage definition to check the payload with its guard and cap it at its maxBytes before it leaves; a bare name (deprecated) checks only the 2,048-byte wire cap.

The payload is serialised with JSON.stringify, so a tick that sends allocates that one string; a tick that sends nothing allocates nothing. undefined sends null.

Parameters ​
ParameterTypeDescription
namestring-
payloadunknownAnything JSON-serialisable; at most maxBytes (2,048) as UTF-8 JSON.
options?SendOptionsto one player, and reliable (default true). A payload that does not serialise (a function or a symbol), fails the definition's check, or whose JSON is over the cap sends nothing and counts in stats.unsent; it never throws, since a throwing system fails the tick.
Returns ​

void

setPhase() ​
ts
setPhase(word): void;

Say what the room is doing, in a word (lobby, playing, voting), for the public room list beside its code and seats. Authority only: on a client, and in a game with no room, it does nothing. The same word again sends nothing and allocates nothing; a new one sends the reserved message aos:phase, which the room server reads and never forwards to a player.

Parameters ​
ParameterTypeDescription
wordstring1 to 32 ASCII letters, digits or dashes. Anything else sends nothing, counts in stats.unsent and is logged once; it never throws.
Returns ​

void

Example ​
ts
function lobby(ctx: GameContext): void {
  ctx.net.setPhase(started ? 'playing' : 'lobby');
}

NetMessage ​

What messages hands back: one player's message, its payload parsed.

Example ​

ts
for (const m of ctx.net.messages(Vote)) tally(m.player, m.payload.for);

Type Parameters ​

Type Parameter
T

Properties ​

payload ​
ts
readonly payload: T;

The JSON payload, parsed.

player ​
ts
readonly player: number;

The sender.


NetMessageEvent ​

A game message a player sent, delivered to the authority on its next tick.

Named NetMessageEvent rather than the WIT's message-event so it never shadows the DOM's MessageEvent in a page that imports both.

Properties ​

name ​
ts
name: string;
payload ​
ts
payload: string;

JSON.

player ​
ts
player: number;

The sender.


NetStats ​

Counters a game or the debug overlay can read.

Example ​

ts
ctx.hud.set({ dropped: ctx.net.stats.dropped, received: ctx.net.stats.received });

Properties ​

dropped ​
ts
dropped: number;

Messages read and dropped: over their maxBytes, not JSON, or failing their defineMessage check. A payload over 2,048 bytes is dropped by the room before it reaches the guest, and is not counted here.

received ​
ts
received: number;

Messages read and handed to a system.

unsent ​
ts
unsent: number;

ctx.net.send calls since init that sent nothing: the payload failed its check, did not serialise, or was over the cap. Never thrown, because a throw fails the tick and enough of them kill the guest for the room.


OverlapHit ​

One body overlapping a query volume.

Properties ​

body ​
ts
body: number;
depth ​
ts
depth: number;
entity ​
ts
entity: number;
point ​
ts
point: Vec3;

PlayerHandle ​

One player: who they are, the entity definition.player spawned for them, and facades that read their input and write their own camera and HUD.

Example ​

ts
for (const [id, p] of ctx.players) {
  if (p.input.pressed('Space')) jump(p.entity);
  p.hud.set({ name: p.name, id });
}

Properties ​

camera ​
ts
readonly camera: object;

This player's camera: every write queues one set-player-camera per tick.

look ​
Get Signature ​
ts
get look(): object;

Accumulated look angles, in radians. Mutate to snap the view.

Returns ​

object

The live look state.

pitch ​
ts
pitch: number;
sensitivity ​
ts
sensitivity: number;
yaw ​
ts
yaw: number;
state ​
Get Signature ​
ts
get state(): CameraState;

The whole camera record, for games that want every knob.

Returns ​

CameraState

The live record. Mutate it; do not replace it.

firstPerson() ​
ts
firstPerson(entity, options?): void;

Mount the camera at an entity's eyes.

Yaw and pitch come from the built-in look accumulator, which integrates input.mouse.dx/dy once per tick.

Parameters ​
ParameterTypeDescription
entitynumberEntity to mount on.
options?FirstPersonOptionsEye height and field of view.
Returns ​

void

Nothing.

follow() ​
ts
follow(entity, options?): void;

Put the camera on a spring arm behind an entity.

The host owns the arm and its collision; the guest only states the intent. position is the orbit pivot and rotation the direction the player is looking, so a host with no rig still ends up somewhere sensible.

Parameters ​
ParameterTypeDescription
entitynumberEntity to follow.
options?FollowOptionsBoom length, height offset, field of view and orbit angles.
Returns ​

void

Nothing.

lookAt() ​
ts
lookAt(point): void;

Aim the camera at a world point, overriding its rotation.

Parameters ​
ParameterTypeDescription
pointVec3 | nullThe point to look at, or null to use the rotation again.
Returns ​

void

Nothing.

set() ​
ts
set(
   position, 
   rotation, 
   fovYDeg?
): void;

Place the camera explicitly, detaching it from any entity.

Parameters ​
ParameterTypeDefault valueDescription
positionVec3undefinedEye position.
rotationQuatundefinedEye rotation, xyzw.
fovYDegnumber60Vertical field of view in degrees. Default 60.
Returns ​

void

Nothing.

hud ​
ts
readonly hud: object;

This player's HUD: a changed model queues a set-player-hud.

clear() ​
ts
clear(): void;

Drop the HUD: emit an empty model this frame.

Idempotent — calling it every frame emits {} once, exactly like set.

Returns ​

void

Nothing.

invalidate() ​
ts
invalidate(): void;

Forget what the host has seen, so the next set emits even if the model did not change. Use it after the host reloaded its overlay.

On its own it sends nothing: the next set does. To send an empty model now, call clear().

Returns ​

void

Nothing.

set() ​
ts
set(model): boolean;

Set the HUD model for this frame.

Nested plain objects are compared by value four levels down, so a model rebuilt inline every frame is recognised as unchanged. Arrays and class instances are compared by identity: keep those out of the model, or build them once and mutate nothing.

Parameters ​
ParameterTypeDescription
modelRecord<string, unknown>A JSON-serialisable object.
Returns ​

boolean

True when the model changed and JSON will cross this frame.

id ​
ts
readonly id: number;

The player id this slot belongs to.

input ​
ts
readonly input: object;

This player's keys, mouse and gamepads, read like input.

focused ​
Get Signature ​
ts
get focused(): boolean;

Does the canvas have focus? Treat input as neutral when it does not.

Returns ​

boolean

True while the canvas is focused.

mods ​
Get Signature ​
ts
get mods(): InputMods;

Keyboard modifier state.

Returns ​

InputMods

The modifiers for this frame.

mouse ​
Get Signature ​
ts
get mouse(): MouseState;

Pointer position, per-frame delta, wheel and button bitsets.

Returns ​

MouseState

The mouse state for this frame. Owned by the SDK; never retain it.

axis2() ​
ts
axis2(
   negX, 
   posX, 
   negY, 
   posY
): Axis2;

A two-axis reading built from four keys.

Parameters ​
ParameterTypeDescription
negXstringKey that drives x negative, for example 'A'.
posXstringKey that drives x positive, for example 'D'.
negYstringKey that drives y negative, for example 'S'.
posYstringKey that drives y positive, for example 'W'.
Returns ​

Axis2

A pooled { x, y } with components in -1..1. Never retain it.

gamepad() ​
ts
gamepad(index): 
  | {
  axes: ArrayLike<number>;
  buttons: number;
  connected: boolean;
  index: number;
  pressed: number;
  released: number;
}
  | null;

One connected gamepad.

Parameters ​
ParameterTypeDescription
indexnumberNavigator gamepad index.
Returns ​

| { axes: ArrayLike<number>; buttons: number; connected: boolean; index: number; pressed: number; released: number; } | null

The gamepad, or null when nothing is connected at that index. Owned by the SDK; never retain it.

isDown() ​
ts
isDown(key): boolean;

Is the key held this frame?

Parameters ​
ParameterTypeDescription
keystringA DOM code ('KeyW'), a bare letter/digit ('W', '1') or an alias ('Shift', 'Esc').
Returns ​

boolean

True while the key is down.

mouseDown() ​
ts
mouseDown(button): boolean;

Is a mouse button held?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True while the button is down.

mousePressed() ​
ts
mousePressed(button): boolean;

Did a mouse button go down this frame?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True on the frame the button went down.

mouseReleased() ​
ts
mouseReleased(button): boolean;

Did a mouse button come up this frame?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True on the frame the button came up.

pressed() ​
ts
pressed(key): boolean;

Did the key go down this frame?

Parameters ​
ParameterTypeDescription
keystringA key name.
Returns ​

boolean

True on the frame the key went down.

released() ​
ts
released(key): boolean;

Did the key come up this frame?

Parameters ​
ParameterTypeDescription
keystringA key name.
Returns ​

boolean

True on the frame the key came up.

lanes ​
ts
readonly lanes: InputLanes;

The decoded input this handle's input reads. Internal.

present ​
ts
present: boolean = false;

In this step's frame-input.players. Internal.

seq ​
ts
seq: number = 0;

The input sequence number this step consumed.

Accessors ​

connected ​
Get Signature ​
ts
get connected(): boolean;
Returns ​

boolean

True between this player's player-joined and player-left.

data ​
Get Signature ​
ts
get data(): unknown;
Returns ​

unknown

The player's document: the one the room loaded at join, then whatever ctx.data.save or a finished exchange made it; null for none.

entity ​
Get Signature ​
ts
get entity(): number;
Returns ​

number

The entity this player controls: the one definition.player spawned at join, or the last one possessed; 0 for none (also after that entity is despawned).

isHost ​
Get Signature ​
ts
get isHost(): boolean;
Returns ​

boolean

True for the host (ctx.players.host): the first joiner, until they leave; then the lowest seat still joined.

joinedAt ​
Get Signature ​
ts
get joinedAt(): number | null;
Returns ​

number | null

The server's clock when the room loaded this player's document, in ms since the epoch, or null when the room has no store. The guest has no clock of its own (now-ms counts from engine start), so this is the one wall time it gets: add ctx.elapsed since the join to it.

name ​
Get Signature ​
ts
get name(): string;
Returns ​

string

The display name the room gave at join, or ''.

savedAt ​
Get Signature ​
ts
get savedAt(): number | null;
Returns ​

number | null

When the store last wrote the document handed over at join, in ms since the epoch by the server's clock, or null when there was none. Offline time is joinedAt - savedAt.

Methods ​

forgetEntity() ​
ts
forgetEntity(entity): void;

The possessed entity was despawned: the player controls none. The host clears its own mapping on the despawn, so nothing is sent.

Parameters ​
ParameterTypeDescription
entitynumberA despawned entity.
Returns ​

void

integrateLook() ​
ts
integrateLook(): void;

Integrate this step's mouse movement into the look angles, as the built-in accumulator does for the local player. Allocates nothing.

Returns ​

void

join() ​
ts
join(name, data): void;

The player took this seat. Parses the saved document: a join-tick allocation.

Parameters ​
ParameterTypeDescription
namestringThe display name.
datastring | null | undefinedThe room's { doc, savedAt, now } as JSON, when it has a store (a bare document is taken as the doc).
Returns ​

void

leave() ​
ts
leave(): void;

The player left; the caller has already despawned PlayerHandle.entity.

Returns ​

void

possess() ​
ts
possess(entity): void;

Make this player control another entity: a respawn, a vehicle, a class swap. On the authority it queues a set-player-entity, so the room follows the player there (relevancy) and their client learns which entity is theirs. Despawning the entity later leaves the player with none until the next possess.

Parameters ​
ParameterTypeDescription
entitynumberThe entity, or 0 to control none.
Returns ​

void

Example ​
ts
const body = ctx.spawn(Avatar, spawnPoint);
ctx.players.get(id)?.possess(body);
restoreSeat() ​
ts
restoreSeat(
   connected, 
   name, 
   entity, 
   data
): void;

Overwrite who holds this seat from a snapshot. The caller rebuilds the map.

Parameters ​
ParameterTypeDescription
connectedbooleanJoined and not left.
namestringThe display name.
entitynumberThe player's entity in the restored world, or 0.
dataunknownThe saved document, already parsed.
Returns ​

void

setEntity() ​
ts
setEntity(entity): void;

The authority spawned this player's entity at join: possess it (which tells the host). Nothing is sent for 0 (a game with no player prefab).

Parameters ​
ParameterTypeDescription
entitynumberThe entity spawned for this player, or 0.
Returns ​

void


PlayerInput ​

One player's input for a step, as frame-input.players carries it.

Properties ​

input ​
ts
input: InputState;

That player's keys, mouse and gamepads.

player ​
ts
player: number;

The player id. 0 is the single-player player, which travels as frame-input.input.

seq ​
ts
seq: number;

The client's input sequence number this step consumed; 0 when unknown.


PlayerJoinedEvent ​

A player entered the room.

Properties ​

data? ​
ts
optional data?: string;

The player's saved document as JSON, when the room has a store. Absent otherwise (null in a wasm guest, as every incoming option is).

name ​
ts
name: string;
player ​
ts
player: number;

PlayerLeftEvent ​

A player left the room.

Properties ​

player ​
ts
player: number;
reason ​
ts
reason: string;

Why: "left", "timeout", "kicked", ...


Players ​

The room's players: a read-only Map from id to PlayerHandle, plus who the host is and a list to walk without allocating.

A for...of over the map (or keys(), values(), entries()) makes an iterator, and an entry pair per player, every call: fine in a join handler, not in a system that runs every tick. Walk list with an index there.

Example ​

ts
const players = ctx.players;
for (let i = 0; i < players.list.length; i += 1) {
  const p = players.list[i];
  if (p.isHost && p.input.pressed('Enter')) startRound();
}
const host = players.host === undefined ? undefined : players.get(players.host);

Extends ​

Properties ​

host ​
ts
readonly host: number | undefined;

The host's seat id, or undefined while nobody is joined. The first joiner is the host and stays host until they leave (player-left); only then does it pass to the lowest seat still joined. A newcomer who takes a lower, freed seat does not become host. Snapshots keep it.

A host who drops counts as gone for this alone: while the room holds their seat (they are still joined, but out of the frame's players list), the role passes to the lowest seat in that list, and it stays there when they come back. If nobody else is in the list, the held host keeps it.

list ​
ts
readonly list: readonly PlayerHandle[];

The same players as the map, in id order. The same array for the whole run, updated in place on a join or a leave; never per tick. Read it, do not keep a copy of its contents across ticks.


PlayerSpec ​

The declarative player block.

Properties ​

camera? ​
ts
optional camera?: "firstPerson" | "thirdPerson";

Which built-in camera rig to drive.

distance? ​
ts
optional distance?: number;

Third-person boom length, metres. Default 4.

eyeHeight? ​
ts
optional eyeHeight?: number;

First-person eye height, metres. Default 1.7.

height? ​
ts
optional height?: number;

Third-person height offset, metres. Default 1.6.

prefab? ​
ts
optional prefab?: PrefabDef;

Prefab to spawn for the player.

sensitivity? ​
ts
optional sensitivity?: number;

Radians of look per pixel of mouse movement. Default 0.0025.

spawn? ​
ts
optional spawn?: PlayerSpawn;

Where each seat spawns; see PlayerSpawn. Default [0, 0, 0].


PlayOptions ​

Options for audio.play.

Properties ​

bus? ​
ts
optional bus?: AudioBus;

Mixer bus. Default 'sfx'.

entity? ​
ts
optional entity?: number;

Attach to an entity for positional audio that follows it.

looping? ​
ts
optional looping?: boolean;

Loop until stopped. Default false.

pitch? ​
ts
optional pitch?: number;

Playback-rate multiplier. Default 1.

volume? ​
ts
optional volume?: number;

Linear gain in 0..1. Default 1.


PlaySoundCmd ​

Start a sound.

Properties ​

asset ​
ts
asset: number;
bus ​
ts
bus: AudioBus;
entity? ​
ts
optional entity?: number;
looping ​
ts
looping: boolean;
pitch ​
ts
pitch: number;
position? ​
ts
optional position?: Vec3;
sound ​
ts
sound: number;
volume ​
ts
volume: number;

PrefabDef ​

A prefab, ready to spawn.

Extends ​

Properties ​

asset? ​
ts
optional asset?: string | number;

Renderable asset: a manifest string id, or a handle.

Inherited from ​

PrefabSpec.asset

body? ​
ts
optional body?: BodySpec;

Physics body, if any.

Inherited from ​

PrefabSpec.body

character? ​
ts
optional character?: string | number;

Splat character bundle: a manifest string id, or a handle.

Inherited from ​

PrefabSpec.character

components? ​
ts
optional components?: readonly object[];

Extra bitecs components and tags to add on spawn.

Inherited from ​

PrefabSpec.components

health? ​
ts
optional health?: number;

Starting hit points; adds the Health component when present.

Inherited from ​

PrefabSpec.health

name? ​
ts
optional name?: string;

Debug label shown in the engine overlay.

Inherited from ​

PrefabSpec.name

prefabId ​
ts
readonly prefabId: number;

Stable index, assigned in declaration order.

scale? ​
ts
optional scale?: readonly number[];

Uniform or per-axis scale. Default [1, 1, 1].

Inherited from ​

PrefabSpec.scale


PrefabSpec ​

Everything a prefab can declare.

Extended by ​

Properties ​

asset? ​
ts
optional asset?: string | number;

Renderable asset: a manifest string id, or a handle.

body? ​
ts
optional body?: BodySpec;

Physics body, if any.

character? ​
ts
optional character?: string | number;

Splat character bundle: a manifest string id, or a handle.

components? ​
ts
optional components?: readonly object[];

Extra bitecs components and tags to add on spawn.

health? ​
ts
optional health?: number;

Starting hit points; adds the Health component when present.

name? ​
ts
optional name?: string;

Debug label shown in the engine overlay.

scale? ​
ts
optional scale?: readonly number[];

Uniform or per-axis scale. Default [1, 1, 1].


Quat ​

A unit quaternion in xyzw order (three.js / Jolt order).

Properties ​

w ​
ts
w: number;
x ​
ts
x: number;
y ​
ts
y: number;
z ​
ts
z: number;

QueryFilter ​

Which bodies a physics query considers.

Properties ​

excludeBody? ​
ts
optional excludeBody?: number;
excludeEntity? ​
ts
optional excludeEntity?: number;
layers ​
ts
layers: CollisionLayers;
solidOnly ​
ts
solidOnly: boolean;

RayHit ​

Closest hit along a ray.

Properties ​

body ​
ts
body: number;
distance ​
ts
distance: number;
entity ​
ts
entity: number;
normal ​
ts
normal: Vec3;
point ​
ts
point: Vec3;

RayQuery ​

One ray in a raycastBatch call.

Properties ​

direction ​
ts
direction: Vec3;
filter ​
ts
filter: QueryFilter;
maxDistance ​
ts
maxDistance: number;
origin ​
ts
origin: Vec3;

RenderableStore ​

Renderable asset handle plus host-side flags.

Properties ​

asset ​
ts
asset: Uint32Array;

Manifest asset handle; 0 means "no renderable".

dirty ​
ts
dirty: Uint8Array;

Non-zero when the host has not yet seen the current value.

flags ​
ts
flags: Uint32Array;

Reserved host flags bitset.


Rgba ​

Linear RGBA, components in 0..1.

Properties ​

a ​
ts
a: number;
b ​
ts
b: number;
g ​
ts
g: number;
r ​
ts
r: number;

RigidBodyStore ​

Rigid body handle and classification.

Properties ​

dirty ​
ts
dirty: Uint8Array;

Non-zero when the host has not yet seen the current value.

groundState ​
ts
groundState: Uint8Array;

Post-step contact: 0 unknown, 1 ground, 2 steep, 3 unsupported, 4 air.

handle ​
ts
handle: Uint32Array;

Guest-minted body id; 0 means "no body".

kind ​
ts
kind: Uint8Array;

BODY_KIND index.

shape ​
ts
shape: Uint8Array;

SHAPE_KIND index.


Rng ​

A seeded, serialisable random source.

Methods ​

float() ​
ts
float(): number;

Next float in [0, 1).

Returns ​

number

int() ​
ts
int(n): number;

Next integer in [0, n). Returns 0 when n <= 0.

Parameters ​
ParameterType
nnumber
Returns ​

number

load() ​
ts
load(state): void;

Overwrite the state.

Parameters ​
ParameterType
stateRngState
Returns ​

void

pick() ​
ts
pick<T>(items): T | undefined;

A uniformly chosen element, or undefined when the array is empty.

Type Parameters ​
Type Parameter
T
Parameters ​
ParameterType
itemsArrayLike<T>
Returns ​

T | undefined

range() ​
ts
range(min, max): number;

Next float in [min, max).

Parameters ​
ParameterType
minnumber
maxnumber
Returns ​

number

save() ​
ts
save(out?): RngState;

Copy the state out, into out when given.

Parameters ​
ParameterType
out?RngState
Returns ​

RngState

seed() ​
ts
seed(value): void;

Re-seed from a 32-bit integer.

Parameters ​
ParameterType
valuenumber
Returns ​

void

uint32() ​
ts
uint32(): number;

Next u32.

Returns ​

number


RngState ​

Four-word xoshiro128** state, as it appears in a snapshot.

Properties ​

s0 ​
ts
s0: number;
s1 ​
ts
s1: number;
s2 ​
ts
s2: number;
s3 ​
ts
s3: number;

RuntimeState ​

Everything one guest instance owns.

Properties ​

assetDescs ​
ts
assetDescs: Map<number, AssetDesc | null>;

Asset handle to its description, cached because the manifest is immutable for the life of a run. Per runtime, never module scope: a parity run has a direct guest and a wasm guest, with different hosts, in one realm.

assetIds ​
ts
assetIds: Map<string, number>;

Manifest string id to asset handle, resolved once and cached.

bodyIndex ​
ts
bodyIndex: BodyIndex;
camera ​
ts
camera: CameraState;
carryCommands ​
ts
carryCommands: boolean;

True when the command buffer holds commands built outside tick — the spawns init queued. The next tick keeps them instead of resetting.

commands ​
ts
commands: NetCommandBuffer;

Where the facades queue commands: the network buffer behind frame-output.commands, or localCommands inside ctx.net.local.

config ​
ts
config: GameConfig;
contacts ​
ts
contacts: readonly Contact[];
dead ​
ts
dead: boolean;

Set after repeated user-code failures; the host must rebuild the sandbox.

dt ​
ts
dt: number;
elapsed ​
ts
elapsed: number;
events ​
ts
events: readonly GameEvent[];
failures ​
ts
failures: number;

Consecutive failed ticks.

focused ​
ts
focused: boolean;
frame ​
ts
frame: number;
gamepadCount ​
ts
gamepadCount: number;
gamepads ​
ts
gamepads: MutableGamepad[];
host ​
ts
host: HostApi;
hud ​
ts
hud: HudState;
initialised ​
ts
initialised: boolean;

True once init has completed. Asset resolution warns after this.

inputLanes ​
ts
inputLanes: InputLanes;

The lanes the singleton input reads: this runtime's own (above) in a single-player game and on the authority, the local player's slot on a client.

keysDown ​
ts
keysDown: Uint32Array;
keysPressed ​
ts
keysPressed: Uint32Array;
keysReleased ​
ts
keysReleased: Uint32Array;
localCommands ​
ts
localCommands: NetCommandBuffer;

frame-output.local-commands: applied by the authority, never forwarded.

look ​
ts
look: LookState;
mods ​
ts
mods: InputMods;
mouse ​
ts
mouse: MouseState;
net ​
ts
net: NetConfig;

The net block of game-config.options, read in init.

nextBody ​
ts
nextBody: number;

Next guest-minted body id. Counters start at 1; 0 means "none".

nextSound ​
ts
nextSound: number;

Next guest-minted sound handle.

packer ​
ts
packer: TransformPacker;
player ​
ts
player: number;

The player entity, when the declarative player block created one.

players ​
ts
players: PlayerTable;

frame-input.players, decoded into slots made in init.

rng ​
ts
rng: Rng;
world ​
ts
world: object;

The bitecs world. Typed loosely so the SDK does not leak bitecs generics.


SaveGameDataCmd ​

Persist the room's game-wide document (JSON). Authority only.

Properties ​

data ​
ts
data: string;

SavePlayerDataCmd ​

Persist one player's document (JSON). Authority only.

Properties ​

data ​
ts
data: string;
player ​
ts
player: number;

SayCmd ​

Speak a line, optionally with audio and a viseme track.

Properties ​

audio? ​
ts
optional audio?: number;
entity ​
ts
entity: number;
text ​
ts
text: string;
visemes? ​
ts
optional visemes?: string;

SendCmd ​

Send a game message to one player, every player, or up to the authority.

Properties ​

name ​
ts
name: string;
payload ​
ts
payload: string;

JSON, at most 2,048 bytes.

reliable ​
ts
reliable: boolean;
to? ​
ts
optional to?: number;

One player; absent sends to every player (authority) or to the authority (client).


SendOptions ​

Options for NetFacade.send.

Example ​

ts
ctx.net.send('role', { role: 'murderer' }, { to: 3 });
ctx.net.send('aim', { x: 1 }, { reliable: false }); // every player, may drop

Properties ​

reliable? ​
ts
optional reliable?: boolean;

Ordered and guaranteed. Default true.

to? ​
ts
optional to?: number;

One player; absent sends to every player. Ignored on a client.


SetAnimCmd ​

Play or cross-fade an animation clip on one layer.

Properties ​

clip ​
ts
clip: string;
entity ​
ts
entity: number;
fadeMs ​
ts
fadeMs: number;
looping ​
ts
looping: boolean;
speed ​
ts
speed: number;
weight ​
ts
weight: number;

SetAssetCmd ​

Attach or detach an entity's renderable.

Properties ​

asset? ​
ts
optional asset?: number;
entity ​
ts
entity: number;

SetBodyEnabledCmd ​

Enable or disable a body in the broad phase.

Properties ​

body ​
ts
body: number;
enabled ​
ts
enabled: boolean;

SetBodyTransformCmd ​

Move a body directly.

Properties ​

body ​
ts
body: number;
position ​
ts
position: Vec3;
rotation ​
ts
rotation: Quat;
teleport ​
ts
teleport: boolean;

SetBodyVelocityCmd ​

Overwrite a body's velocities. undefined leaves one untouched.

Properties ​

angular? ​
ts
optional angular?: Vec3;
body ​
ts
body: number;
linear? ​
ts
optional linear?: Vec3;

SetCharacterStateCmd ​

Drive a character's locomotion state machine.

Properties ​

entity ​
ts
entity: number;
grounded ​
ts
grounded: boolean;
state ​
ts
state: string;
velocity ​
ts
velocity: Vec3;

SetClipWeightsCmd ​

Set explicit per-clip weights on a character's body layer.

Properties ​

clips ​
ts
clips: readonly string[];
entity ​
ts
entity: number;
timeScale ​
ts
timeScale: number;
weights ​
ts
weights: Float32Array<ArrayBufferLike> | readonly number[];

SetExpressionCmd ​

Set a character's facial expression coefficients.

Properties ​

entity ​
ts
entity: number;
space ​
ts
space: ExpressionSpace;
weights ​
ts
weights: Float32Array<ArrayBufferLike> | readonly number[];

SetListenerCmd ​

Place the audio listener.

Properties ​

position ​
ts
position: Vec3;
rotation ​
ts
rotation: Quat;
velocity ​
ts
velocity: Vec3;

SetMaterialParamCmd ​

Set one material uniform.

Properties ​

entity ​
ts
entity: number;
name ​
ts
name: string;
value ​
ts
value: MaterialValue;

SetParentCmd ​

Reparent an entity in the scene graph.

Properties ​

entity ​
ts
entity: number;
keepWorldTransform ​
ts
keepWorldTransform: boolean;
parent? ​
ts
optional parent?: number;

SetPlayerCameraCmd ​

The camera one player renders from.

Properties ​

camera ​
ts
camera: CameraState;
player ​
ts
player: number;

SetPlayerEntityCmd ​

Which entity a player controls. The authority sends it when it spawns definition.player for a join and on every PlayerHandle.possess; the host keeps the mapping (relevancy, "which entity is mine" on the client).

Properties ​

entity ​
ts
entity: number;
player ​
ts
player: number;

SetPlayerHudCmd ​

One player's HUD model as JSON.

Properties ​

hud ​
ts
hud: string;
player ​
ts
player: number;

Shape ​

Collision shape description carried by add-body.

Properties ​

asset? ​
ts
optional asset?: number;
halfExtents ​
ts
halfExtents: Vec3;
kind ​
ts
kind: ShapeKind;

SidedSystem ​

A system that says where it runs.

'authority' runs on the room's authority and in a single-player (solo) game; 'client' runs on a player's page and in solo; 'both' runs everywhere. solo is its own authority and its own client, so it runs all three. A bare function is 'authority' once the game declares features.multiplayer, and 'both' otherwise, so a single-player game reads the same as it always did.

Example ​

ts
import { defineGame } from 'gameable';

export default defineGame({
  features: { multiplayer: true },
  systems: [
    (ctx) => { ctx.net.send('tick', ctx.frame); }, // bare: the authority's
    { on: 'client', run: (ctx) => { ctx.hud.set({ ping: ctx.frame }); } },
  ],
});

Properties ​

on ​
ts
on: "authority" | "client" | "both";

Where it runs.

run ​
ts
run: Run;

The system.


SoundEndedEvent ​

A playing sound stopped.

Properties ​

completed ​
ts
completed: boolean;
sound ​
ts
sound: number;

SpawnCharacterCmd ​

Instantiate a splat character bundle.

Properties ​

bundle ​
ts
bundle: number;
entity ​
ts
entity: number;
position ​
ts
position: Vec3;
rotation ​
ts
rotation: Quat;

SpawnCmd ​

Create an entity, optionally with a renderable asset.

Properties ​

asset? ​
ts
optional asset?: number;
entity ​
ts
entity: number;
name? ​
ts
optional name?: string;
parent? ​
ts
optional parent?: number;
position ​
ts
position: Vec3;
rotation ​
ts
rotation: Quat;
scale ​
ts
scale: Vec3;
visible ​
ts
visible: boolean;

SpawnSpec ​

One entry of the declarative spawns list.

Properties ​

position ​
ts
position: readonly number[];

Where, [x, y, z].

prefab ​
ts
prefab: PrefabDef;

What to spawn.

rotation? ​
ts
optional rotation?: readonly number[];

Rotation, [x, y, z, w]. Defaults to identity.


StopSoundCmd ​

Stop a playing sound.

Properties ​

fadeMs ​
ts
fadeMs: number;
sound ​
ts
sound: number;

ThirdPersonClips ​

Optional authored clips; omit to use the animator's standard locomotion blend.

Properties ​

fall ​
ts
fall: string;
idle ​
ts
idle: string;
land ​
ts
land: string;
rise ​
ts
rise: string;
run ​
ts
run: string;
walk ​
ts
walk: string;

TransformStore ​

Position, rotation (xyzw) and scale, one lane per component.

Properties ​

qw ​
ts
qw: Float32Array;
qx ​
ts
qx: Float32Array;
qy ​
ts
qy: Float32Array;
qz ​
ts
qz: Float32Array;
sx ​
ts
sx: Float32Array;
sy ​
ts
sy: Float32Array;
sz ​
ts
sz: Float32Array;
x ​
ts
x: Float32Array;
y ​
ts
y: Float32Array;
z ​
ts
z: Float32Array;

Vec3 ​

A 3-component vector.

Properties ​

x ​
ts
x: number;
y ​
ts
y: number;
z ​
ts
z: number;

VelocityStore ​

Linear and angular velocity in metres and radians per second.

Properties ​

ax ​
ts
ax: Float32Array;
ay ​
ts
ay: Float32Array;
az ​
ts
az: Float32Array;
x ​
ts
x: Float32Array;
y ​
ts
y: Float32Array;
z ​
ts
z: Float32Array;

WorldSpec ​

World-level settings.

Properties ​

gravity? ​
ts
optional gravity?: number | readonly number[];

Gravity in metres per second squared, applied by the built-in velocity system to entities that have Velocity but no RigidBody. Bodies get their gravity from the host physics world instead.

maxEntities? ​
ts
optional maxEntities?: number;

Entity ceiling. Sizes every built-in component array. Default 4096.

Type Aliases ​

AssetId ​

ts
type AssetId = number;

Manifest asset handle, resolved from a string id.


AssetKind ​

ts
type AssetKind = "splat" | "gltf" | "character" | "audio" | "collider" | "data";

Manifest asset family.


AudioBus ​

ts
type AudioBus = "master" | "music" | "sfx" | "voice" | "ui";

Audio mixer bus.


BodyId ​

ts
type BodyId = number;

Rigid body / character controller handle.


BodyKind ​

ts
type BodyKind = "fixed" | "kinematic" | "dynamic" | "character";

Physics body class. fixed is what other engines call static.


CameraMode ​

ts
type CameraMode = "first-person" | "third-person" | "free" | "fixed";

Camera rig family.


Command ​

ts
type Command = 
  | {
  tag: "conversation";
  val: ConversationCmd;
}
  | {
  tag: "spawn";
  val: SpawnCmd;
}
  | {
  tag: "despawn";
  val: Entity;
}
  | {
  tag: "set-asset";
  val: SetAssetCmd;
}
  | {
  tag: "set-parent";
  val: SetParentCmd;
}
  | {
  tag: "set-anim";
  val: SetAnimCmd;
}
  | {
  tag: "set-material-param";
  val: SetMaterialParamCmd;
}
  | {
  tag: "add-body";
  val: AddBodyCmd;
}
  | {
  tag: "remove-body";
  val: BodyId;
}
  | {
  tag: "set-body-transform";
  val: SetBodyTransformCmd;
}
  | {
  tag: "set-body-velocity";
  val: SetBodyVelocityCmd;
}
  | {
  tag: "apply-impulse";
  val: ApplyImpulseCmd;
}
  | {
  tag: "set-body-enabled";
  val: SetBodyEnabledCmd;
}
  | {
  tag: "move-character";
  val: MoveCharacterCmd;
}
  | {
  tag: "spawn-character";
  val: SpawnCharacterCmd;
}
  | {
  tag: "set-character-state";
  val: SetCharacterStateCmd;
}
  | {
  tag: "set-clip-weights";
  val: SetClipWeightsCmd;
}
  | {
  tag: "set-expression";
  val: SetExpressionCmd;
}
  | {
  tag: "look-at";
  val: LookAtCmd;
}
  | {
  tag: "say";
  val: SayCmd;
}
  | {
  tag: "play-sound";
  val: PlaySoundCmd;
}
  | {
  tag: "stop-sound";
  val: StopSoundCmd;
}
  | {
  tag: "set-listener";
  val: SetListenerCmd;
}
  | {
  tag: "load-asset";
  val: LoadAssetCmd;
}
  | {
  tag: "set-pointer-lock";
  val: boolean;
}
  | {
  tag: "set-time-scale";
  val: number;
}
  | NetCommand;

Everything the guest can ask the host to do, applied front to back.


CommandTag ​

ts
type CommandTag = Command["tag"];

Every Command['tag'], useful for exhaustive host-side switches.


ContactPhase ​

ts
type ContactPhase = "begin" | "stay" | "end";

Lifecycle phase of a contact.


Entity ​

ts
type Entity = number;

ECS entity handle. 0 is reserved and means "none".


ErrorCode ​

ts
type ErrorCode = 
  | "init-failed"
  | "tick-failed"
  | "invalid-state"
  | "unsupported"
  | "asset-missing"
  | "snapshot-version-mismatch"
  | "internal";

Machine-readable half of a GameError.


ExpressionSpace ​

ts
type ExpressionSpace = "arkit52" | "gnm" | "gnm68";

Coordinate space for setExpression weights.


FeatureOptions ​

ts
type FeatureOptions = Readonly<Record<string, Readonly<Record<string, unknown>>>>;

Declared features, normalised: every present feature has an options object.


GameDefinition ​

ts
type GameDefinition = Readonly<GameSpec>;

A validated game declaration.


GameEvent ​

ts
type GameEvent = 
  | {
  tag: "conversation-event";
  val: ConversationEvent;
}
  | {
  tag: "asset-loaded";
  val: AssetLoadedEvent;
}
  | {
  tag: "character-ready";
  val: CharacterReadyEvent;
}
  | {
  tag: "sound-ended";
  val: SoundEndedEvent;
}
  | {
  tag: "anim-event";
  val: AnimEventData;
}
  | {
  tag: "resized";
  val: ResizedEvent;
}
  | NetEvent;

A host-side occurrence since the previous tick.


KeyName ​

ts
type KeyName = string;

Any string this table accepts: a DOM code, a bare letter or digit, or one of the friendly aliases.


LogLevel ​

ts
type LogLevel = "trace" | "debug" | "info" | "warn" | "error";

Log severity accepted by env.log.


LogSink ​

ts
type LogSink = (level, msg) => void;

Where prelude console output goes.

Parameters ​

ParameterType
levelLogLevel
msgstring

Returns ​

void


MaterialValue ​

ts
type MaterialValue = 
  | {
  tag: "scalar";
  val: number;
}
  | {
  tag: "boolean";
  val: boolean;
}
  | {
  tag: "color";
  val: Rgba;
}
  | {
  tag: "vector";
  val: Vec3;
}
  | {
  tag: "texture";
  val: AssetId;
};

A material parameter value.


MessageCheck ​

ts
type MessageCheck<T> = (payload) => payload is T;

The game's own type guard for a payload, already parsed from JSON. It must be pure: no wall time, no Math.random, no state, so the authority and every replay agree on what it drops.

Type Parameters ​

Type Parameter
T

Parameters ​

ParameterType
payloadunknown

Returns ​

payload is T


NetCommand ​

ts
type NetCommand = 
  | {
  tag: "send";
  val: SendCmd;
}
  | {
  tag: "set-player-camera";
  val: SetPlayerCameraCmd;
}
  | {
  tag: "set-player-hud";
  val: SetPlayerHudCmd;
}
  | {
  tag: "save-player-data";
  val: SavePlayerDataCmd;
}
  | {
  tag: "save-game-data";
  val: SaveGameDataCmd;
}
  | {
  tag: "set-player-entity";
  val: SetPlayerEntityCmd;
}
  | {
  tag: "exchange";
  val: ExchangeCmd;
};

The net and data members of the command variant.


NetEvent ​

ts
type NetEvent = 
  | {
  tag: "player-joined";
  val: PlayerJoinedEvent;
}
  | {
  tag: "player-left";
  val: PlayerLeftEvent;
}
  | {
  tag: "message";
  val: NetMessageEvent;
}
  | {
  tag: "exchange-result";
  val: ExchangeResultEvent;
}
  | {
  tag: "game-data";
  val: GameDataEvent;
};

The net and data members of the event variant.


NetRole ​

ts
type NetRole = "solo" | "authority" | "client";

Where a guest runs: alone (solo), as the room's authority, or as one player's client.

Example ​

ts
const role: NetRole = ctx.net.role;
if (role === 'client') showLatency();

PlayerSpawn ​

ts
type PlayerSpawn = 
  | readonly number[]
  | readonly readonly number[][]
  | ((seat, ctx) => Vec3);

Where definition.player spawns each seat: one point [x, y, z] for everyone, a list of points (seat i takes list[i % list.length]), or a function of the seat. A single-player game spawns seat 0.

The function runs on the authority at the seat's join, inside the step, so it must be deterministic: read only the seat, ctx.rules, ctx.rng and the world, never the clock or Math.random. It runs before ctx.players is updated for the step, so read the seat, not ctx.players: the map still holds the previous step's players there.

Example ​

ts
import { defineGame, type PlayerSpawn } from 'gameable';

const corners: PlayerSpawn = [[-8, 0, -8], [8, 0, -8], [8, 0, 8], [-8, 0, 8]];
const ring: PlayerSpawn = (seat) => ({ x: Math.cos(seat) * 6, y: 0, z: Math.sin(seat) * 6 });
export default defineGame({ player: { prefab: Hero, spawn: corners } });

ProjectionKind ​

ts
type ProjectionKind = "perspective" | "orthographic";

Camera projection family.


ShapeKind ​

ts
type ShapeKind = 
  | "box"
  | "sphere"
  | "capsule"
  | "cylinder"
  | "plane"
  | "convex-hull"
  | "mesh"
  | "height-field";

Collision shape family.


SoundId ​

ts
type SoundId = number;

Playing-sound handle.


System ​

ts
type System = (ctx) => void;

A system: one plain function, run once per fixed step. In systems it may also be a SidedSystem, { run, on }, that says where it runs.

Parameters ​

ParameterType
ctxGameContext

Returns ​

void


TransferDoc ​

ts
type TransferDoc = Record<string, unknown>;

A player document as a transfer reads it: a plain object.

Variables ​

audio ​

ts
const audio: object;

The audio facade.

Type Declaration ​

listener() ​
ts
listener(position, rotation): void;

Place the audio listener.

Parameters ​
ParameterTypeDescription
positionVec3Listener position.
rotationQuatListener rotation, xyzw.
Returns ​

void

Nothing.

play() ​
ts
play(asset, options?): number;

Start a sound.

Parameters ​
ParameterTypeDescription
assetstring | numberManifest string id or asset handle.
options?PlayOptionsAttachment, gain, pitch, looping and bus.
Returns ​

number

The guest-minted sound handle, or 0 when the asset is unknown.

stop() ​
ts
stop(sound, fadeMs?): void;

Stop a playing sound.

Parameters ​
ParameterTypeDefault valueDescription
soundnumberundefinedA handle from play.
fadeMsnumber0Fade-out in milliseconds; 0 stops immediately.
Returns ​

void

Nothing.

Example ​

ts
import { audio } from 'gameable';

const id = audio.play('shot', { entity: player, volume: 0.8 });
audio.stop(id, 50);

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;

BODY_KINDS ​

ts
const BODY_KINDS: readonly ["fixed", "kinematic", "dynamic", "character"];

Physics body classes, in the index order RigidBody.kind stores.


BODY_STRIDE ​

ts
const BODY_STRIDE: 15 = 15;

Floats per row of frame-input.bodies.


BUILTIN_COMPONENT_NAMES ​

ts
const BUILTIN_COMPONENT_NAMES: readonly ["Transform", "Renderable", "RigidBody", "Character", "Velocity", "Health", "Player", "Enemy", "Pickup"];

Names matching BUILTIN_COMPONENTS, used in snapshot headers.


BUILTIN_COMPONENTS ​

ts
const BUILTIN_COMPONENTS: readonly [TransformStore, RenderableStore, RigidBodyStore, CharacterStore, VelocityStore, HealthStore, Record<string, never>, Record<string, never>, Record<string, never>];

Every built-in component, in the fixed order snapshot serialises them.


camera ​

ts
const camera: object;

The camera facade: writes the frame's camera.

Type Declaration ​

look ​
Get Signature ​
ts
get look(): object;

Accumulated look angles, in radians. Mutate to snap the view.

Returns ​

object

The live look state.

pitch ​
ts
pitch: number;
sensitivity ​
ts
sensitivity: number;
yaw ​
ts
yaw: number;
state ​
Get Signature ​
ts
get state(): CameraState;

The whole camera record, for games that want every knob.

Returns ​

CameraState

The live record. Mutate it; do not replace it.

firstPerson() ​
ts
firstPerson(entity, options?): void;

Mount the camera at an entity's eyes.

Yaw and pitch come from the built-in look accumulator, which integrates input.mouse.dx/dy once per tick.

Parameters ​
ParameterTypeDescription
entitynumberEntity to mount on.
options?FirstPersonOptionsEye height and field of view.
Returns ​

void

Nothing.

follow() ​
ts
follow(entity, options?): void;

Put the camera on a spring arm behind an entity.

The host owns the arm and its collision; the guest only states the intent. position is the orbit pivot and rotation the direction the player is looking, so a host with no rig still ends up somewhere sensible.

Parameters ​
ParameterTypeDescription
entitynumberEntity to follow.
options?FollowOptionsBoom length, height offset, field of view and orbit angles.
Returns ​

void

Nothing.

lookAt() ​
ts
lookAt(point): void;

Aim the camera at a world point, overriding its rotation.

Parameters ​
ParameterTypeDescription
pointVec3 | nullThe point to look at, or null to use the rotation again.
Returns ​

void

Nothing.

set() ​
ts
set(
   position, 
   rotation, 
   fovYDeg?
): void;

Place the camera explicitly, detaching it from any entity.

Parameters ​
ParameterTypeDefault valueDescription
positionVec3undefinedEye position.
rotationQuatundefinedEye rotation, xyzw.
fovYDegnumber60Vertical field of view in degrees. Default 60.
Returns ​

void

Nothing.

Example ​

ts
import { camera } from 'gameable';

camera.firstPerson(player, { eyeHeight: 1.7 });

character ​

ts
const character: object;

The character facade.

Type Declaration ​

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

The character bundle handle attached to an entity, or 0.

Parameters ​
ParameterTypeDescription
entitynumberEntity id.
Returns ​

number

The bundle asset handle.

lookAt() ​
ts
lookAt(
   entity, 
   target, 
   weight?
): void;

Aim the head and eyes at a world point.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity with a Character component.
targetVec3 | nullundefinedThe point, or null to release and return to the idle.
weightnumber1Blend weight in 0..1. Default 1.
Returns ​

void

Nothing.

say() ​
ts
say(
   entity, 
   text, 
   voice?, 
   visemes?
): void;

Speak a line.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a Character component.
textstringSubtitle text; the host decides whether to show it.
voice?string | numberManifest string id or handle of a voice line.
visemes?stringViseme track as JSON, matching the bundle's space.
Returns ​

void

Nothing.

setClipWeights() ​
ts
setClipWeights(
   entity, 
   clips, 
   weights, 
   timeScale?
): void;

Set explicit per-clip weights on the body layer.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity with a Character component.
clipsreadonly string[]undefinedClip names.
weightsFloat32Array<ArrayBufferLike> | readonly number[]undefinedPositional weights; must be the same length as clips.
timeScalenumber1Playback rate for the whole layer. Default 1.
Returns ​

void

Nothing.

setExpression() ​
ts
setExpression(
   entity, 
   space, 
   weights
): void;

Set facial expression coefficients.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a Character component.
spaceExpressionSpaceCoordinate space: 52 ARKit, 387 GNM, or the 68-float view.
weightsFloat32Array<ArrayBufferLike> | readonly number[]Coefficients; length must match the space.
Returns ​

void

Nothing.

setState() ​
ts
setState(
   entity, 
   state, 
   vx, 
   vy, 
   vz, 
   grounded?
): void;

Drive the locomotion state machine.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity with a Character component.
statestringundefinedState name, for example `'idle'
vxnumberundefinedWorld-space velocity x, drives the locomotion blend.
vynumberundefinedWorld-space velocity y.
vznumberundefinedWorld-space velocity z.
groundedbooleantrueWhether the character is on the ground.
Returns ​

void

Nothing.

Example ​

ts
import { character } from 'gameable';

character.setState(npc, 'walk', 0, 0, 1.4, true);
character.lookAt(npc, { x: 0, y: 1.6, z: 0 });

Character ​

ts
const Character: CharacterStore;

Splat character bundle attached to an entity.


conversation ​

ts
const conversation: object;

Structural interview controls; all streams remain in optional host modules.

Type Declaration ​

command() ​
ts
command(
   entity, 
   action, 
   character?, 
   text?
): void;

Queue one control using the reusable command pool.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedInterview entity.
action| "end" | "start" | "ask" | "interrupt" | "microphone-on" | "microphone-off"undefinedLifecycle or question action.
characterstring''Host-configured id.
textstring''Question, if any.
Returns ​

void

Example ​

ts
import { conversation } from 'gameable';
conversation.command(npc, 'start', 'steward');
conversation.command(npc, 'ask', 'steward', 'Who had the study key?');

DEFAULT_MAX_ENTITIES ​

ts
const DEFAULT_MAX_ENTITIES: 4096 = 4096;

Default entity ceiling. Every built-in component array is this long.


DEFAULT_MAX_PLAYERS ​

ts
const DEFAULT_MAX_PLAYERS: 16 = 16;

The highest player id a guest makes a slot for when net.maxPlayers is not in game-config.options.

Example ​

ts
import { DEFAULT_MAX_PLAYERS } from 'gameable';

const options = JSON.stringify({ net: { maxPlayers: DEFAULT_MAX_PLAYERS * 2 } });

DEFAULT_ROOM_SEATS ​

ts
const DEFAULT_ROOM_SEATS: 8 = 8;

Seats in a room when the game declares features.multiplayer without a maxPlayers.

Example ​

ts
import { DEFAULT_ROOM_SEATS, defineGame, roomSeats } from 'gameable';

const game = defineGame({ features: { multiplayer: true } });
roomSeats(game) === DEFAULT_ROOM_SEATS; // true

Enemy ​

ts
const Enemy: Record<string, never> = {};

Tag: a hostile entity.


EXPRESSION_DIMS ​

ts
const EXPRESSION_DIMS: Readonly<Record<ExpressionSpace, number>>;

Coefficient counts each expression space expects.


Health ​

ts
const Health: HealthStore;

Hit points.


hud ​

ts
const hud: object;

The HUD facade: writes the frame's HUD.

Type Declaration ​

clear() ​
ts
clear(): void;

Drop the HUD: emit an empty model this frame.

Idempotent — calling it every frame emits {} once, exactly like set.

Returns ​

void

Nothing.

invalidate() ​
ts
invalidate(): void;

Forget what the host has seen, so the next set emits even if the model did not change. Use it after the host reloaded its overlay.

On its own it sends nothing: the next set does. To send an empty model now, call clear().

Returns ​

void

Nothing.

set() ​
ts
set(model): boolean;

Set the HUD model for this frame.

Nested plain objects are compared by value four levels down, so a model rebuilt inline every frame is recognised as unchanged. Arrays and class instances are compared by identity: keep those out of the model, or build them once and mutate nothing.

Parameters ​
ParameterTypeDescription
modelRecord<string, unknown>A JSON-serialisable object.
Returns ​

boolean

True when the model changed and JSON will cross this frame.

Example ​

ts
import { hud } from 'gameable';

hud.set({ health: 100, ammo: 30 }); // emitted once
hud.set({ health: 100, ammo: 30 }); // unchanged, nothing crosses

input ​

ts
const input: object;

The keyboard, mouse and gamepad facade: the local player's input. That is frame-input.input in a single-player game and on the authority, and the local player's slot of frame-input.players on a client.

Type Declaration ​

focused ​
Get Signature ​
ts
get focused(): boolean;

Does the canvas have focus? Treat input as neutral when it does not.

Returns ​

boolean

True while the canvas is focused.

mods ​
Get Signature ​
ts
get mods(): InputMods;

Keyboard modifier state.

Returns ​

InputMods

The modifiers for this frame.

mouse ​
Get Signature ​
ts
get mouse(): MouseState;

Pointer position, per-frame delta, wheel and button bitsets.

Returns ​

MouseState

The mouse state for this frame. Owned by the SDK; never retain it.

axis2() ​
ts
axis2(
   negX, 
   posX, 
   negY, 
   posY
): Axis2;

A two-axis reading built from four keys.

Parameters ​
ParameterTypeDescription
negXstringKey that drives x negative, for example 'A'.
posXstringKey that drives x positive, for example 'D'.
negYstringKey that drives y negative, for example 'S'.
posYstringKey that drives y positive, for example 'W'.
Returns ​

Axis2

A pooled { x, y } with components in -1..1. Never retain it.

gamepad() ​
ts
gamepad(index): 
  | {
  axes: ArrayLike<number>;
  buttons: number;
  connected: boolean;
  index: number;
  pressed: number;
  released: number;
}
  | null;

One connected gamepad.

Parameters ​
ParameterTypeDescription
indexnumberNavigator gamepad index.
Returns ​

| { axes: ArrayLike<number>; buttons: number; connected: boolean; index: number; pressed: number; released: number; } | null

The gamepad, or null when nothing is connected at that index. Owned by the SDK; never retain it.

isDown() ​
ts
isDown(key): boolean;

Is the key held this frame?

Parameters ​
ParameterTypeDescription
keystringA DOM code ('KeyW'), a bare letter/digit ('W', '1') or an alias ('Shift', 'Esc').
Returns ​

boolean

True while the key is down.

mouseDown() ​
ts
mouseDown(button): boolean;

Is a mouse button held?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True while the button is down.

mousePressed() ​
ts
mousePressed(button): boolean;

Did a mouse button go down this frame?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True on the frame the button went down.

mouseReleased() ​
ts
mouseReleased(button): boolean;

Did a mouse button come up this frame?

Parameters ​
ParameterTypeDescription
buttonnumberA MOUSE_BUTTONS value, or a raw bit mask.
Returns ​

boolean

True on the frame the button came up.

pressed() ​
ts
pressed(key): boolean;

Did the key go down this frame?

Parameters ​
ParameterTypeDescription
keystringA key name.
Returns ​

boolean

True on the frame the key went down.

released() ​
ts
released(key): boolean;

Did the key come up this frame?

Parameters ​
ParameterTypeDescription
keystringA key name.
Returns ​

boolean

True on the frame the key came up.

Example ​

ts
import { input } from 'gameable';

const move = input.axis2('A', 'D', 'S', 'W'); // x = strafe, y = forward
if (input.pressed('Space')) jump();
if (input.mouseDown(1)) fire();

IS_COMPONENT_GUEST ​

ts
const IS_COMPONENT_GUEST: boolean;

True when this realm looks like the QuickJS component guest rather than V8.

Decided once, before anything is polyfilled: a realm with neither console nor TextEncoder is componentize-qjs. It is the only realm whose Math.random the prelude is allowed to replace — patching the global in V8 would reach vitest, Vite and the host application too.


KEY_BITS ​

ts
const KEY_BITS: 256 = 256;

Number of key bits the WIT key-state bitsets can carry.


KEY_COUNT ​

ts
const KEY_COUNT: number = KEY_NAMES.length;

Number of key names currently assigned.


KEY_NAMES ​

ts
const KEY_NAMES: readonly string[];

Every key name in index order. The array index is the bit index.

Do not reorder; append only.


KEY_WORDS ​

ts
const KEY_WORDS: number;

Number of u32 words in one key-state bitset.


LAYER_KEYS ​

ts
const LAYER_KEYS: readonly ["defaultLayer", "staticGeometry", "player", "enemy", "projectile", "pickup", "trigger", "character", "debris", "water", "user0", "user1", "user2", "user3", "user4", "user5"];

Every WIT collision-layers member, in declaration order.

Bit i of the physics module's numeric layer/mask is member i of this list. It is a contract between the guest, which writes the flags record, and the host, which folds it into a bitmask — so both sides import this one list rather than keeping a copy each.

Example ​

ts
import { LAYER_KEYS } from 'gameable';

const bit = LAYER_KEYS.indexOf('enemy'); // 3

MOUSE_BUTTONS ​

ts
const MOUSE_BUTTONS: Readonly<{
  BACK: 8;
  FORWARD: 16;
  LEFT: 1;
  MIDDLE: 4;
  RIGHT: 2;
}>;

Mouse button bit positions, matching mouse-state.buttons.


PACKAGE ​

ts
const PACKAGE: "@gameable/sdk";

Package identity marker.

Example ​

ts
import { PACKAGE } from 'gameable';

console.log(PACKAGE); // 'gameable'

physics ​

ts
const physics: object;

Physics queries and body commands.

Type Declaration ​

ALL_LAYERS ​
ts
ALL_LAYERS: CollisionLayers;

Every collision layer, for queries that should hit anything.

applyImpulse() ​
ts
applyImpulse(
   entity, 
   x, 
   y, 
   z, 
   atX?, 
   atY?, 
   atZ?
): void;

Apply a one-shot impulse.

With no application point the impulse acts at the centre of mass. Give one — all three coordinates — to apply it off-centre and impart spin.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
xnumberImpulse x, newton-seconds.
ynumberImpulse y.
znumberImpulse z.
atX?numberWorld-space application point x, or omit for the centre of mass.
atY?numberApplication point y.
atZ?numberApplication point z.
Returns ​

void

Nothing.

isGrounded() ​
ts
isGrounded(entity): boolean;

Actual walkable ground contact from the last host physics step. No host call. Unknown, steep and unsupported contacts return false, even at a jump apex.

Parameters ​
ParameterTypeDescription
entitynumberCharacter entity.
Returns ​

boolean

Whether the character is supported by walkable ground.

moveCharacter() ​
ts
moveCharacter(
   entity, 
   vx, 
   vy, 
   vz, 
   jump?, 
   crouch?, 
   maxSlopeDeg?
): void;

Drive a character body for this step.

Parameters ​
ParameterTypeDefault valueDescription
entitynumberundefinedEntity whose body was created with kind: 'character'.
vxnumberundefinedDesired world-space velocity x, metres per second.
vynumberundefinedDesired world-space velocity y.
vznumberundefinedDesired world-space velocity z.
jumpbooleanfalseRequest a jump this step.
crouchbooleanfalseRequest a crouch this step.
maxSlopeDegnumber45Maximum walkable slope.
Returns ​

void

Nothing.

overlapSphere() ​
ts
overlapSphere(
   center, 
   radius, 
   maxResults?, 
   mask?, 
   ignoreEntity?
): readonly OverlapHit[];

Bodies overlapping a sphere, nearest first.

Parameters ​
ParameterTypeDefault valueDescription
centerVec3undefinedSphere centre.
radiusnumberundefinedSphere radius in metres.
maxResultsnumber16Cap on returned hits.
mask?CollisionLayersundefinedLayers to consider; defaults to every layer.
ignoreEntity?numberundefinedEntity to skip.
Returns ​

readonly OverlapHit[]

The overlapping bodies.

raycast() ​
ts
raycast(
   origin, 
   direction, 
   maxDistance, 
   mask?, 
   ignoreEntity?
): RayHit | null;

Closest hit along a ray.

Parameters ​
ParameterTypeDescription
originVec3World-space ray origin.
directionVec3Ray direction; need not be normalised.
maxDistancenumberMaximum distance in metres.
mask?CollisionLayersLayers to consider; defaults to every layer.
ignoreEntity?numberEntity to skip, usually the caster.
Returns ​

RayHit | null

The hit, or null on a miss. The hit object comes from the host and is freshly allocated: this call is not allocation-free.

raycastBatch() ​
ts
raycastBatch(rays): readonly (RayHit | null | undefined)[];

Many rays in one round trip. Result index i matches rays[i].

Parameters ​
ParameterTypeDescription
raysreadonly object[]The rays. Build them once and mutate them in place.
Returns ​

readonly (RayHit | null | undefined)[]

One result per ray; undefined or null entries are misses.

setEnabled() ​
ts
setEnabled(entity, enabled): void;

Enable or disable a body in the broad phase.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
enabledbooleanWhether the body participates.
Returns ​

void

Nothing.

setVelocity() ​
ts
setVelocity(
   entity, 
   x, 
   y, 
   z, 
   ax?, 
   ay?, 
   az?
): void;

Overwrite a body's velocity.

Angular velocity is left alone unless all three angular components are given.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
xnumberLinear velocity x.
ynumberLinear velocity y.
znumberLinear velocity z.
ax?numberAngular velocity x, radians per second.
ay?numberAngular velocity y.
az?numberAngular velocity z.
Returns ​

void

Nothing.

teleport() ​
ts
teleport(
   entity, 
   x, 
   y, 
   z
): void;

Teleport a body, clearing its velocities.

Parameters ​
ParameterTypeDescription
entitynumberEntity with a body.
xnumberPosition x.
ynumberPosition y.
znumberPosition z.
Returns ​

void

Nothing.

Example ​

ts
import { physics, Transform } from 'gameable';

const hit = physics.raycast(eye, forward, 100);
if (hit) console.log('hit entity', hit.entity, 'at', hit.distance);

Pickup ​

ts
const Pickup: Record<string, never> = {};

Tag: something the player can pick up.


Player ​

ts
const Player: Record<string, never> = {};

Tag: the entity the player controls.


Renderable ​

ts
const Renderable: RenderableStore;

Renderable asset attached to an entity.


RigidBody ​

ts
const RigidBody: RigidBodyStore;

Physics body attached to an entity.


SHAPE_KINDS ​

ts
const SHAPE_KINDS: readonly ["box", "sphere", "capsule", "cylinder", "plane", "convex-hull", "mesh", "height-field"];

Collision shapes, in the index order RigidBody.shape stores.


SNAPSHOT_VERSION ​

ts
const SNAPSHOT_VERSION: 3 = 3;

Bumped whenever the byte layout changes. Mismatches refuse to restore.


TAG_ORDINAL ​

ts
const TAG_ORDINAL: Record<CommandTag, number>;

Every command tag mapped to its pool index.

Written out rather than derived so the compiler checks it: Record over the CommandTag union rejects both a missing tag and one that is not in the WIT variant. packages/wasm-host/src/apply.test.ts pins the same list from the host side.

Example ​

ts
import { TAG_ORDINAL } from 'gameable';

console.log(TAG_ORDINAL['set-time-scale']); // 24

Transform ​

ts
const Transform: TransformStore;

World transform of an entity. Position, rotation (xyzw), scale.


TRANSFORM_ALL ​

ts
const TRANSFORM_ALL: number;

POSITION | ROTATION | SCALE, what a freshly spawned entity needs.


TRANSFORM_FLAGS ​

ts
const TRANSFORM_FLAGS: Readonly<{
  DESTROYED: 32;
  POSITION: 1;
  ROTATION: 2;
  SCALE: 4;
  TELEPORT: 16;
  VISIBLE: 8;
}>;

Meaning of lane 1 of a transform row, matching WIT transform-flags.


TRANSFORM_STRIDE ​

ts
const TRANSFORM_STRIDE: 12 = 12;

Floats per row of frame-output.transforms.


Velocity ​

ts
const Velocity: VelocityStore;

Guest-integrated velocity, for entities the host physics does not own.

Functions ​

activeRuntime() ​

ts
function activeRuntime(): RuntimeState;

The runtime the SDK facades are currently bound to.

Returns ​

RuntimeState

The active runtime.

Throws ​

When called outside init, a system, update or shutdown.


applyTransfer() ​

ts
function applyTransfer(
   docA, 
   docB, 
   give, 
   take
): 
  | {
  a: TransferDoc;
  b: TransferDoc;
}
  | null;

Trade between two player documents: a gives b everything in give, and takes from b everything in take. A number field moves that amount (the giver must have at least that much); a list field moves those items (the giver must hold each one; an object item matches by value, whatever its key order). A missing document counts as {}.

Parameters ​

ParameterTypeDescription
docAunknownPlayer a's document, or null.
docBunknownPlayer b's document, or null.
giveunknownWhat a gives b, such as { coins: 5 }.
takeunknownWhat a takes from b, such as { owned: ['gem'] }.

Returns ​

| { a: TransferDoc; b: TransferDoc; } | null

Both new documents (the inputs are untouched), or null when the trade is impossible.

Example ​

ts
import { applyTransfer } from 'gameable';

applyTransfer({ coins: 10 }, { owned: ['gem'] }, { coins: 4 }, { owned: ['gem'] });
// { a: { coins: 6, owned: ['gem'] }, b: { owned: [], coins: 4 } }

assetId() ​

ts
function assetId(name): number;

Resolve a manifest string id to an asset handle, caching the result.

Parameters ​

ParameterTypeDescription
namestringThe manifest string id, for example 'arena'.

Returns ​

number

The handle, or 0 when the manifest has no such entry.

Example ​

ts
import { assetId } from 'gameable';

const arena = assetId('arena');

commandPoolSize() ​

ts
function commandPoolSize(): number;

Total pooled command slots created since the module loaded.

Tests assert this stops growing once a game reaches its steady state.

Returns ​

number

The number of slots ever allocated.

Example ​

ts
const before = commandPoolSize();
for (let i = 0; i < 100; i += 1) guest.tick(input);
console.log(commandPoolSize() === before); // true, in a steady state

configureEcs() ​

ts
function configureEcs(n): void;

Resize every built-in component array.

Call this before defineGame runs any system — the runtime calls it from init out of world.maxEntities. The component objects keep their identity, so bitecs registrations survive; only the arrays inside are replaced, so never cache Transform.x across a call.

Parameters ​

ParameterTypeDescription
nnumberThe new entity ceiling. Values below 2 are clamped to 2.

Returns ​

void

Nothing.


createGuest() ​

ts
function createGuest(host, definition): Guest;

Create a guest from a host and a game definition.

Parameters ​

ParameterTypeDescription
hostHostApiThe host services, in guest-side JS shapes.
definitionGameDefinitionThe result of defineGame.

Returns ​

Guest

The five WIT exports, plus dead and state.

Example ​

ts
import { createGuest } from 'gameable';
import { createMockHost, createFrameInput } from 'gameable/test';

const guest = createGuest(createMockHost(), game);
guest.init({ seed: 1, fixedHz: 60, viewportWidth: 1, viewportHeight: 1, devMode: true });
const out = guest.tick(createFrameInput({ frame: 0 }));

createRng() ​

ts
function createRng(initialSeed?): Rng;

Create a seeded xoshiro128** generator.

Parameters ​

ParameterTypeDefault valueDescription
initialSeednumber1A 32-bit seed. 0 is remapped so the state is never all zero.

Returns ​

Rng

A generator whose whole state is four integers.


createThirdPersonController() ​

ts
function createThirdPersonController(clips?): object;

Create one allocation-free camera-relative controller. Call reset in game init; update from a guest system. Tuning comes from ctx.rules: walkSpeed, runSpeed, acceleration, deceleration, jumpSpeed, landingSeconds, moveTurnRate, idleTurnRate, idleTurnThreshold and camera pitch/distance/height.

update drives the single player: ctx.player from ctx.input, with ctx.camera. updatePlayers drives a room on its authority: each player's own entity (PlayerHandle.entity, so a possess moves the controller too) from that player's own input, with that player's own camera. Each seat has its own state, made the first time the seat is seen and reset whenever the seat's entity changes (a join, a respawn, a possess).

Parameters ​

ParameterTypeDescription
clips?ThirdPersonClipsOptional complete base-layer clip mapping, configured once.

Returns ​

Persistent state, reset and update functions.

reset ​
ts
reset: (ctx) => void;

Reset the single player's state and look; forget every seat.

Parameters ​
ParameterTypeDescription
ctxGameContextThe init context.
Returns ​

void

state ​
ts
state: object = locomotionState;
state.airborne ​
ts
airborne: number = 0;
state.descending ​
ts
descending: boolean = false;
state.facing ​
ts
facing: number = Math.PI;
state.grounded ​
ts
grounded: boolean = false;
state.landing ​
ts
landing: number = 0;
state.pitch ​
ts
pitch: number = 0;
state.speed ​
ts
speed: number = 0;
state.state ​
ts
state: string = IDLE;
state.turning ​
ts
turning: boolean = false;
state.vx ​
ts
vx: number = 0;
state.vz ​
ts
vz: number = 0;
state.yaw ​
ts
yaw: number = 0;
stateOf ​
ts
stateOf: (player) => 
  | {
  airborne: number;
  descending: boolean;
  facing: number;
  grounded: boolean;
  landing: number;
  pitch: number;
  speed: number;
  state: string;
  turning: boolean;
  vx: number;
  vz: number;
  yaw: number;
}
  | undefined;
Parameters ​
ParameterTypeDescription
playernumberA player id.
Returns ​

| { airborne: number; descending: boolean; facing: number; grounded: boolean; landing: number; pitch: number; speed: number; state: string; turning: boolean; vx: number; vz: number; yaw: number; } | undefined

That seat's state, or undefined before it was first driven.

update ​
ts
update: (ctx, freeze) => void;

Drive the single player one step.

Parameters ​
ParameterTypeDefault valueDescription
ctxGameContextundefinedThe frame context.
freezebooleanfalseTrue to hold the player still.
Returns ​

void

updatePlayers ​
ts
updatePlayers: (ctx, freeze) => void;

Drive every room player's own entity one step, from their own input.

Parameters ​
ParameterTypeDefault valueDescription
ctxGameContextundefinedThe frame context, on the authority.
freezeboolean | ((player) => boolean)falseTrue to hold everyone still, or a test per player (hoist it: a function made per frame allocates), such as "this player is talking".
Returns ​

void

Example ​

ts
const controller = createThirdPersonController();
// In init: controller.reset(ctx); in a system:
if (ctx.net.role === 'solo') controller.update(ctx);
else controller.updatePlayers(ctx);

defineGame() ​

ts
function defineGame(spec): GameDefinition;

Declare a game.

Parameters ​

ParameterTypeDescription
specGameSpecThe declaration.

Returns ​

GameDefinition

The frozen definition, ready for createGuest or a build.

Example ​

ts
import { defineGame, prefab } from 'gameable';

const Player = prefab({
  body: { shape: 'capsule', dims: [0.3, 0.9], kind: 'character' },
});

export default defineGame({
  assets: ['arena'],
  world: { gravity: -9.81 },
  player: { prefab: Player, spawn: [0, 1, 0], camera: 'firstPerson' },
  systems: [(ctx) => { ctx.hud.set({ frame: ctx.frame }); }],
});

defineMessage() ​

ts
function defineMessage<T>(
   name, 
   check, 
   options?
): MessageDef<T>;

Declare a game message. Call it at module scope, once per name: a second definition with the same name before the next init throws.

A received payload that is over maxBytes, does not parse, fails check or makes check throw is dropped and counted in ctx.net.stats.dropped; a system never sees it.

Type Parameters ​

Type Parameter
T

Parameters ​

ParameterTypeDescription
namestringThe message name; unique within the game.
checkMessageCheck<T>The game's own type guard. Pure: no clock, no randomness.
options?MessageOptionsmaxBytes, default 2,048 (the wire cap).

Returns ​

MessageDef<T>

The definition.

Throws ​

On a duplicate name, an empty name, a name starting with aos: (reserved for the engine, as ctx.net.setPhase's aos:phase), or a maxBytes that is not a whole number from 1 to 2,048.

Example ​

ts
import { defineMessage, hasKeys } from 'gameable';

const hasFor = hasKeys('for');
export const Vote = defineMessage(
  'vote',
  (p): p is { for: number } => hasFor(p) && typeof p.for === 'number',
  { maxBytes: 64 },
);

describeAsset() ​

ts
function describeAsset(idOrName): AssetDesc | null;

Metadata for an asset handle or manifest name.

Parameters ​

ParameterTypeDescription
idOrNamestring | numberA handle from assetId, or a manifest string id.

Returns ​

AssetDesc | null

The description, or null when the asset is unknown.

Example ​

ts
import { describeAsset } from 'gameable';

const desc = describeAsset('myra');
if (desc?.kind === 'character') console.log('rig backend', desc.rig);

despawn() ​

ts
function despawn(entity): void;

Destroy an entity, its body and its host-side representation.

Parameters ​

ParameterTypeDescription
entitynumberThe entity id.

Returns ​

void

Nothing.

Example ​

ts
import { despawn } from 'gameable';

despawn(enemy);

featuresOf() ​

ts
function featuresOf(definition): FeatureOptions;

Normalise a game's features block.

Parameters ​

ParameterTypeDescription
definitionGameDefinitionThe defineGame result.

Returns ​

FeatureOptions

A frozen table: feature name to its options; true becomes {}, false is dropped.

Example ​

ts
import { defineGame, featuresOf } from 'gameable';

const game = defineGame({ features: { characters: true, multiplayer: { maxPlayers: 6 } } });
console.log(featuresOf(game)); // { characters: {}, multiplayer: { maxPlayers: 6 } }

getActiveRuntime() ​

ts
function getActiveRuntime(): RuntimeState | null;

The runtime currently executing, or null outside a guest call.

Returns ​

RuntimeState | null

The active runtime.


getMaxEntities() ​

ts
function getMaxEntities(): number;

How many entities the built-in component arrays currently hold.

Returns ​

number

The configured entity ceiling.


hasKeys() ​

ts
function hasKeys<K>(...keys): (x) => x is Record<K, unknown>;

A guard for a record with every one of keys as an own property (any value, even undefined); extra keys are allowed. Make it once, at module scope: the guard it returns allocates nothing per call.

Type Parameters ​

Type Parameter
K extends string

Parameters ​

ParameterTypeDescription
...keysK[]The keys a payload must have.

Returns ​

The guard.

(x) => x is Record<K, unknown>

Example ​

ts
const hasItemSlot = hasKeys('item', 'slot');
const Pick = defineMessage(
  'pick',
  (p): p is { item: string; slot: number } =>
    hasItemSlot(p) && typeof p.item === 'string' && typeof p.slot === 'number',
);

isRecord() ​

ts
function isRecord(x): x is Record<string, unknown>;

A plain JSON object: not null, not an array.

Parameters ​

ParameterTypeDescription
xunknownA parsed payload.

Returns ​

x is Record<string, unknown>

True for an object record.

Example ​

ts
const Move = defineMessage('move', (p): p is { x: number } => isRecord(p) && typeof p.x === 'number');

keyIndex() ​

ts
function keyIndex(name): number;

Bit index for a key name, or -1 when the name is unknown. Names are case-sensitive, except that a bare letter or F-key also answers in lower case ('w', 'f1'). Allocates nothing.

Parameters ​

ParameterTypeDescription
namestringA DOM KeyboardEvent.code, a bare letter/digit, or an alias.

Returns ​

number

The bit index in 0..255, or -1.


keyIndex2() ​

ts
function keyIndex2(name): number;

Second bit index for names that cover a left/right pair ('Shift'), or -1. Case-sensitive, like the aliases it covers. Allocates nothing.

Parameters ​

ParameterTypeDescription
namestringA key name or alias.

Returns ​

number

The second bit index, or -1 when the name maps to one key.


loadAsset() ​

ts
function loadAsset(idOrName, priority?): void;

Ask the host to start loading an asset.

Parameters ​

ParameterTypeDefault valueDescription
idOrNamestring | numberundefinedA handle or manifest string id.
prioritynumber0Higher runs first. Default 0.

Returns ​

void

Nothing.

Example ​

ts
import { loadAsset } from 'gameable';

loadAsset('boss-arena', 10);

markMoved() ​

ts
function markMoved(entity, flags?): void;

Tell the packer an entity's Transform changed.

spawn and the built-in velocity integration mark for you. Two cases they do not cover: a system that writes Transform.x[e] (or any other lane) by hand, and a body-driven entity, whose transform the host now owns outright — BodyIndex.ingest copies the physics rows in for the guest to read and deliberately does not mark them. Either way, nothing notices the write, the row is never packed and the host never moves the object. Call this after such a write. To move a physics body, send a command (setBodyTransform) rather than writing the lane.

Parameters ​

ParameterTypeDefault valueDescription
entitynumberundefinedEntity id. Out-of-range ids are ignored.
flagsnumberTRANSFORM_ALLWhich lanes changed; defaults to position, rotation and scale.

Returns ​

void

Nothing.

Example ​

ts
import { Transform, TRANSFORM_FLAGS, markMoved } from 'gameable';

Transform.y[e] = Transform.y[e] + 0.1;
markMoved(e, TRANSFORM_FLAGS.POSITION);

maxEntities() ​

ts
function maxEntities(): number;

The entity ceiling the built-in components are currently sized for.

Returns ​

number

The configured maximum.

Example ​

ts
import { maxEntities } from 'gameable';

console.log(maxEntities()); // 4096

prefab() ​

ts
function prefab(spec): PrefabDef;

Declare a prefab.

Safe at module scope: nothing is resolved until the first spawn.

Parameters ​

ParameterTypeDescription
specPrefabSpecWhat the entity is made of.

Returns ​

PrefabDef

The prefab, ready to spawn.

Example ​

ts
import { prefab } from 'gameable';

export const Crate = prefab({
  asset: 'crate',
  body: { shape: 'box', dims: [0.5, 0.5, 0.5], kind: 'dynamic', mass: 20 },
});

prefabRegistry() ​

ts
function prefabRegistry(): readonly PrefabDef[];

Every prefab declared so far, in declaration order.

Returns ​

readonly PrefabDef[]

The registry, for tooling and tests.


quatFromYawPitch() ​

ts
function quatFromYawPitch(
   out, 
   yaw, 
   pitch
): void;

Write a yaw/pitch pair into a quaternion, in the engine's Y-up convention.

Parameters ​

ParameterTypeDescription
outQuatQuaternion to overwrite.
yawnumberYaw in radians, around +Y.
pitchnumberPitch in radians, around the camera's local +X.

Returns ​

void

Nothing; out is mutated.


readKeyBit() ​

ts
function readKeyBit(words, index): boolean;

Read one bit out of an 8-word key bitset.

Parameters ​

ParameterTypeDescription
wordsArrayLike<number>The bitset, exactly KEY_WORDS long.
indexnumberA bit index from keyIndex.

Returns ​

boolean

True when the bit is set.


readSnapshot() ​

ts
function readSnapshot(rt, state): unknown;

Restore a state previously produced by writeSnapshot from the same build.

Parameters ​

ParameterTypeDescription
rtRuntimeStateThe runtime to overwrite.
stateArrayLike<number>The bytes.

Returns ​

unknown

The user state from defineGame({ snapshot }), if any.

Throws ​

A GameError-shaped object when the magic or version does not match.


requireRuntime() ​

ts
function requireRuntime(): RuntimeState;

The runtime currently executing.

Returns ​

RuntimeState

The active runtime.

Throws ​

When called outside init, tick or shutdown.


resetBuiltinStores() ​

ts
function resetBuiltinStores(): void;

Zero every built-in component array without changing its length.

Returns ​

void

Nothing.


resetPrefabRegistry() ​

ts
function resetPrefabRegistry(): void;

Reset prefab numbering. Tests only — a game never calls this.

Returns ​

void

Nothing.


roomSeats() ​

ts
function roomSeats(definition): number | undefined;

The seats a game declares: features.multiplayer.maxPlayers. Seats are ids 0..seats - 1. The guest makes exactly that many player slots and ignores (with one warning) a join or input past them; a room built by createEngineRoomGame refuses the next joiner with full. Both read this function, so the two cannot disagree.

Parameters ​

ParameterTypeDescription
definitionGameDefinitionThe defineGame result.

Returns ​

number | undefined

The seat count, DEFAULT_ROOM_SEATS for multiplayer: true, or undefined when the game does not declare features.multiplayer.

Throws ​

When maxPlayers is not a whole number from 1 to 4097.

Example ​

ts
import { defineGame, roomSeats } from 'gameable';

const game = defineGame({ features: { multiplayer: { maxPlayers: 6 } } });
roomSeats(game); // 6: seats 0 to 5

roomSendHz() ​

ts
function roomSendHz(definition): number;

The rows rate a game declares, checked: features.multiplayer.sendHz, from 1 to 60 per second (60 is the simulation rate, so more would repeat rows).

Parameters ​

ParameterTypeDescription
definitionGameDefinitionThe defineGame result.

Returns ​

number

The declared rate, or 20 when none is declared.

Throws ​

When sendHz is declared but is not a number from 1 to 60.

Example ​

ts
import { defineGame, roomSendHz } from 'gameable';

roomSendHz(defineGame({ features: { multiplayer: { sendHz: 10 } } })); // 10
roomSendHz(defineGame({ features: { multiplayer: true } })); // 20

setActiveRuntime() ​

ts
function setActiveRuntime(next): RuntimeState | null;

Install the runtime the facades resolve against.

Parameters ​

ParameterTypeDescription
nextRuntimeState | nullThe runtime, or null when leaving a guest call.

Returns ​

RuntimeState | null

The previously active runtime, so calls can nest.


setLogSink() ​

ts
function setLogSink(next): void;

Point prelude console at the host logger.

The runtime calls this at the top of init. Any lines buffered before then are flushed in order, so module-scope logging is not silently lost.

Parameters ​

ParameterTypeDescription
nextLogSink | nullThe sink, or null to go back to buffering.

Returns ​

void

Nothing.


setRandomSource() ​

ts
function setRandomSource(next): void;

Route Math.random at the seeded SDK generator.

The runtime calls this from init. Until then Math.random() throws with RANDOM_MESSAGE, which is far kinder than a game that silently replays the same "random" sequence on every instantiation.

Only effective in the component guest; see IS_COMPONENT_GUEST.

Parameters ​

ParameterTypeDescription
next(() => number) | nullThe seeded generator, or null to re-arm the guard.

Returns ​

void

Nothing.


spawn() ​

ts
function spawn(
   def, 
   position, 
   rotation?
): number;

Instantiate a prefab.

Mints the entity id, writes the built-in components and queues the spawn / add-body / spawn-character commands the host needs.

Parameters ​

ParameterTypeDefault valueDescription
defPrefabDefundefinedA prefab from prefab().
positionVec3undefinedWorld position.
rotationQuatIDENTITYWorld rotation, xyzw. Defaults to identity.

Returns ​

number

The new entity id.

Example ​

ts
import { spawn } from 'gameable';

const crate = spawn(Crate, { x: 0, y: 2, z: -5 });

utf8Decode() ​

ts
function utf8Decode(
   b, 
   start?, 
   end?
): string;

Decode UTF-8 bytes without TextDecoder.

Parameters ​

ParameterTypeDefault valueDescription
bArrayLike<number>undefinedThe bytes. Any ArrayLike<number> works, including the plain Array jco hands the guest.
startnumber0First byte to read.
end?numberundefinedOne past the last byte to read; defaults to b.length.

Returns ​

string

The decoded string.


utf8Encode() ​

ts
function utf8Encode(s): Uint8Array;

Encode a JavaScript string as UTF-8 without TextEncoder.

Parameters ​

ParameterTypeDescription
sstringThe string to encode.

Returns ​

Uint8Array

A freshly allocated UTF-8 byte array.


writeKeyBit() ​

ts
function writeKeyBit(
   words, 
   index, 
   value
): void;

Set or clear one bit in an 8-word key bitset, in place.

Parameters ​

ParameterTypeDescription
wordsUint32ArrayThe bitset, exactly KEY_WORDS long.
indexnumberA bit index from keyIndex.
valuebooleanTrue to set the bit, false to clear it.

Returns ​

void

Nothing; words is mutated.


writeSnapshot() ​

ts
function writeSnapshot(rt, userState?): Uint8Array;

Serialise the whole guest state.

Parameters ​

ParameterTypeDescription
rtRuntimeStateThe runtime to serialise.
userState?unknownExtra state from defineGame({ snapshot }).

Returns ​

Uint8Array

A freshly allocated byte string. Opaque to the host.