Skip to content

Premade actors ​

Generated by tools/docs/gen-actors.mjs. Do not edit.

Import premade classes from gameable before loading a level. Props override class defaults; asset strings are manifest ids.

Shared prop groups ​

Each group uses the first registered default for each prop. Actor tables list differences; a group link applies only to props supported by that actor.

Door kit ​

PropTypeDefaultRangeMeaning
widthnumber1min 0; metresClosed doorway width.
heightnumber2.1min 0; metresClosed doorway height.
thicknessnumber0.1min 0; metresLeaf thickness.
rangenumber2min 0; metresPlanar reach and maximum vertical separation in metres.
facingDegreesnumber75min 0; max 180; degreesMaximum angle from camera forward, degrees.
actionstring"E"—Input action/key; E also accepts Tap.
oncebooleanfalse—Allow use once per player.
enabledbooleantrue—Whether the actor can apply its behaviour.
assetstring""—Manifest mesh id; empty means no mesh.
promptstring"E: open"—HUD prompt for the nearest eligible interaction.
secondsnumber0.6min 0; secondsTime to move fully open or closed.
startOpenbooleanfalse—Start at the fully open pose.
autoCloseSecondsnumber0min 0; secondsWait after opening; zero disables automatic closing.
lockedBystring""—Inventory item required to unlock; empty means unlocked.
consumeKeybooleanfalse—Remove one key on successful unlock.
stayOpenbooleanfalse—Once opened, never close or offer interaction again.
openPromptstring"E: open"—Prompt while closed or closing.
closePromptstring"E: close"—Prompt while open or opening.
lockedPromptstring"Locked"—Prompt when the player lacks the required key.
lockedMessagestring""—Notice on locked interaction; empty disables it.
openSoundstring""—Manifest audio id on opening; empty is silent.
closeSoundstring""—Manifest audio id on closing; empty is silent.
lockedSoundstring""—Manifest audio id on locked interaction; empty is silent.
colourcolor[0.45,0.28,0.13]min 0; max 1Linear RGB panel colour.
lookenum"wood"wood, metal, noneBuilt-in painted panel detail; asset overrides this.
opensWhenarray[]—Named actors whose signals must all be on.
toggledByenum"interact"interact, signal, proximityInteraction, all named signals, or nearby players.

LevelSettings ​

Level class: LevelSettings. Category: Markers.

Level-wide settings; at most one per level.

PropTypeDefaultRangeMeaning
killHeightnumber | false | nullnullmetresKill plane: null = lowest placed actor minus 50 m (off if nothing is placed); false = off.

Events:

None.

Components:

  • root: scene
json
{
  "class": "LevelSettings",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "killHeight": null
  }
}

PlayerStart ​

Level class: PlayerStart. Category: Markers.

Player spawn marker; yaw comes from its root transform.

PropTypeDefaultRangeMeaning
tagstring""—Added to instance tags at construction.
seatnumber | nullnull—Preferred player seat; null is not seat-specific.

Events:

None.

Components:

  • root: scene
json
{
  "class": "PlayerStart",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "tag": "",
    "seat": null
  }
}

TargetPoint ​

Level class: TargetPoint. Category: Markers.

Named destination with no collision or behaviour.

PropTypeDefaultRangeMeaning
tagstring""—Added to instance tags at construction.

Events:

None.

Components:

  • root: scene
json
{
  "class": "TargetPoint",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "tag": ""
  }
}

TriggerBox ​

Level class: TriggerBox. Category: Volumes.

Overlap marker.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]metresBox half sizes [x,y,z], metres, read at spawn.

Events:

  • onTrigger: Dispatches named enter and exit listeners for eligible actors and players.

Components:

  • root: box
json
{
  "class": "TriggerBox",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ]
  }
}

TriggerSphere ​

Level class: TriggerSphere. Category: Volumes.

Overlap marker.

PropTypeDefaultRangeMeaning
radiusnumber1min 0; metresRadius in metres, read at spawn.

Events:

  • onTrigger: Dispatches named enter and exit listeners for eligible actors and players.

Components:

  • root: sphere
json
{
  "class": "TriggerSphere",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "radius": 1
  }
}

TriggerCapsule ​

Level class: TriggerCapsule. Category: Volumes.

Overlap marker.

PropTypeDefaultRangeMeaning
radiusnumber0.5min 0; metresRadius in metres, read at spawn.
halfHeightnumber1min 0; metresCapsule straight-section half height, metres.

Events:

  • onTrigger: Dispatches named enter and exit listeners for eligible actors and players.

Components:

  • root: capsule
json
{
  "class": "TriggerCapsule",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "radius": 0.5,
    "halfHeight": 1
  }
}

BlockingVolume ​

Level class: BlockingVolume. Category: Volumes.

Invisible fixed box; dimensions are half extents in metres, read at spawn.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]metresBox half sizes [x,y,z], metres, read at spawn.

Events:

None.

Components:

  • root: box
json
{
  "class": "BlockingVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ]
  }
}

KillVolume ​

Level class: KillVolume. Category: Volumes.

Recover vehicles through their circuit or spawn policy, respawn players, destroy other actors.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]metresBox half sizes [x,y,z], metres, read at spawn.

Events:

None.

Components:

  • root: box
json
{
  "class": "KillVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ]
  }
}

DamageVolume ​

Level class: DamageVolume. Category: Volumes.

Interval damage: one interval's damage on entry, then every interval seconds.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]metresBox half sizes [x,y,z], metres, read at spawn.
damagePerSecondnumber10min 0; damage/secondDamage rate; each hit deals rate × interval.
intervalnumber1min 0; secondsSeconds between hits, clamped to at least one fixed step.
typestring""—Game-defined damage category.
enabledbooleantrue—Whether the actor can apply its behaviour.

Events:

None.

Components:

  • root: box
json
{
  "class": "DamageVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ],
    "damagePerSecond": 10,
    "interval": 1,
    "type": "",
    "enabled": true
  }
}

PhysicsVolume ​

Level class: PhysicsVolume. Category: Volumes.

Highest-priority overlapping volume controls bodyless gravity and falling speed.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]metresBox half sizes [x,y,z], metres, read at spawn.
gravityScalenumber1—Gravity multiplier.
terminalVelocitynumber55min 0; metres/secondMaximum falling speed in metres/second for bodyless Velocity entities.
waterbooleanfalse—Halves requested horizontal character speed; no character buoyancy.
prioritynumber0—Highest overlapping priority wins; earlier spawn breaks ties.

Events:

None.

Components:

  • root: box
json
{
  "class": "PhysicsVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ],
    "gravityScale": 1,
    "terminalVelocity": 55,
    "water": false,
    "priority": 0
  }
}

ForceField ​

Level class: ForceField. Category: World.

Radial physics force source with an optional initial impulse.

PropTypeDefaultRangeMeaning
radiusnumber5min 0; metresEffect radius.
impulseStrengthnumber10newton-secondsOne-shot impulse magnitude.
forceStrengthnumber0newtonsContinuous force magnitude.
falloffenum"constant"constant, linearDistance attenuation.
fireOnBeginPlaybooleanfalse—Fire once on the first authority step.
activebooleantrue—Enable continuous force.

Events:

None.

Components:

  • root: scene
  • force: scene
json
{
  "class": "ForceField",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "radius": 5,
    "impulseStrength": 10,
    "forceStrength": 0,
    "falloff": "constant",
    "fireOnBeginPlay": false,
    "active": true
  }
}

AudioVolume ​

Level class: AudioVolume. Category: World.

Solo pawn reverb box; skipped in rooms because authority has no single listener. Exclusively owns audio.fx on each named bus.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]min 0; metresBox half sizes.
reverbenum"room"dry, room, hall, cave, underwater, radio, muffled, arenaBus effect preset.
busenum"sfx"master, music, sfx, voice, uiMixer bus exclusively owned by this module.
fadeMsnumber300min 0; millisecondsTransition duration.
prioritynumber0—Higher priority wins; ties use spawn order.

Events:

None.

Components:

  • root: box
json
{
  "class": "AudioVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ],
    "reverb": "room",
    "bus": "sfx",
    "fadeMs": 300,
    "priority": 0
  }
}

PhysicsJoint ​

Level class: PhysicsJoint. Category: World.

Physics joint between named actor roots or an actor and the world.

PropTypeDefaultRangeMeaning
kindenum"hinge"hinge, slider, point, fixed, distanceJoint family.
actorAstring""—First body actor name; empty uses own root.
actorBstring""—Second body actor name; empty anchors to world.
axisvec3[0,1,0]—Constraint-local axis.
minnumber | nullnulldegrees (hinge), metres (slider/distance)Lower limit; null with null max means free.
maxnumber | nullnulldegrees (hinge), metres (slider/distance)Upper limit; null with null min means free.
motorModeenum"off"off, velocity, positionInitial motor control mode.
motorTargetnumber0degrees or metres; per second for velocityInitial motor coordinate or velocity target.
motorMaxForcenumber0min 0; newtons or newton-metresMotor force or torque cap; zero uses host default.

Events:

None.

Components:

  • root: scene
  • constraint: scene
json
{
  "class": "PhysicsJoint",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "kind": "hinge",
    "actorA": "",
    "actorB": "",
    "axis": [
      0,
      1,
      0
    ],
    "min": null,
    "max": null,
    "motorMode": "off",
    "motorTarget": 0,
    "motorMaxForce": 0
  }
}

Level class: NavigationBounds. Category: Volumes.

Shared navigation grid over the union of axis-aligned bounds volumes.

PropTypeDefaultRangeMeaning
halfExtentsvec3[10,10,10]min 0.001; metresAxis-aligned XZ footprint and vertical bake range.
cellSizenumber0.5min 0.001; metresGrid cell width.
agentRadiusnumber0.4min 0.001; metresObstacle clearance radius.
maxClimbnumber0.4min 0.001; metresMaximum traversable height change.
maxSlopenumber45min 0.001; max 90; degreesMaximum ground slope.
buildenum"physics"physics, flatBake colliders or supply flat ground.

Events:

None.

Components:

  • root: scene
json
{
  "class": "NavigationBounds",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      10,
      10,
      10
    ],
    "cellSize": 0.5,
    "agentRadius": 0.4,
    "maxClimb": 0.4,
    "maxSlope": 45,
    "build": "physics"
  }
}

Level class: NavigationModifier. Category: Volumes.

Axis-aligned blocking or costly navigation area, removed on destruction.

PropTypeDefaultRangeMeaning
halfExtentsvec3[1,1,1]min 0; metresBlocked half sizes; navigation uses the XZ footprint.
areaClassenum"null"null, costlyNull blocks; costly multiplies entry cost (overlaps take the max).
costnumber3min 1Cell entry multiplier for costly areas.

Events:

None.

Components:

  • root: scene
json
{
  "class": "NavigationModifier",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "halfExtents": [
      1,
      1,
      1
    ],
    "areaClass": "null",
    "cost": 3
  }
}

Level class: NavigationLink. Category: Volumes.

One-way or two-way navigation connection; AI teleports between its endpoints.

PropTypeDefaultRangeMeaning
endvec3[2,0,0]metresRelative endpoint, including teleport landing height.
bidirectionalbooleantrue—Allow traversal in both directions.
costnumber2min 0; metresAbsolute traversal cost.

Events:

None.

Components:

  • root: scene
json
{
  "class": "NavigationLink",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "end": [
      2,
      0,
      0
    ],
    "bidirectional": true,
    "cost": 2
  }
}

PostProcessVolume ​

Level class: PostProcessVolume. Category: Volumes.

Local post overrides inside a box, composed by ascending priority; requires features: { vfx: true }. Null settings do not override.

PropTypeDefaultRangeMeaning
unboundbooleanfalse—Apply everywhere.
halfExtentsvec3[1,1,1]min 0; metresBox half size.
prioritynumber0—Higher priorities override lower priorities; ties use spawn order.
blendRadiusnumber0min 0; max 0; metresV1 supports zero only (hard boundary).
bloomnumber | nullnullmin 0Bloom strength.
bloomThresholdnumber | nullnullmin 0Bloom threshold in linear light.
bloomRadiusnumber | nullnullmin 0Bloom radius.
exposurenumber | nullnullmin 0Exposure multiplier.
toneMappingenum | nullnullnone, aces, agx, neutralTone mapping operator.
contrastnumber | nullnullmin 0Contrast multiplier.
saturationnumber | nullnullmin 0Saturation multiplier.
tintvec3 | nullnullmin 0Linear RGB grade.
vignettenumber | nullnullmin 0; max 1Vignette strength.
fogColorvec3 | nullnullmin 0Linear RGB fog color.
fogDensitynumber | nullnullmin 0Exponential fog density.

Events:

None.

Components:

  • root: box
json
{
  "class": "PostProcessVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "unbound": false,
    "halfExtents": [
      1,
      1,
      1
    ],
    "priority": 0,
    "blendRadius": 0,
    "bloom": null,
    "bloomThreshold": null,
    "bloomRadius": null,
    "exposure": null,
    "toneMapping": null,
    "contrast": null,
    "saturation": null,
    "tint": null,
    "vignette": null,
    "fogColor": null,
    "fogDensity": null
  }
}

HeightFog ​

Level class: HeightFog. Category: World.

Exponential fog composed before volume post overrides; no height falloff. Requires features: { vfx: true }.

PropTypeDefaultRangeMeaning
fogDensitynumber0.02min 0Exponential fog density.
fogColorvec3[0.5,0.55,0.6]min 0Fog linear RGB color.

Events:

None.

Components:

  • root: scene
json
{
  "class": "HeightFog",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "fogDensity": 0.02,
    "fogColor": [
      0.5,
      0.55,
      0.6
    ]
  }
}

Pickup ​

Level class: Pickup. Category: Gameplay.

Player reward with optional spinning and bobbing mesh.

PropTypeDefaultRangeMeaning
giveobject | object | object | enum{"heal":25}—Reward; item rewards require a shared inventory.
respawnSecondsnumber0secondsDelay before becoming collectible again; zero or negative means never.
spinnumber90degrees/secondRotation about +Y, degrees/second.
bobnumber0.1min 0; metresVertical amplitude in metres; one cycle per second.
assetstring""—Manifest mesh id; empty means no mesh.

Events:

  • onPickedUp: Called when a player successfully collects the reward.

Components:

  • root: sphere
  • spin: scene
json
{
  "class": "Pickup",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "give": {
      "heal": 25
    },
    "respawnSeconds": 0,
    "spin": 90,
    "bob": 0.1,
    "asset": ""
  }
}

Interactable ​

Level class: Interactable. Category: Gameplay.

Ready interaction point; derive a class with onInteract for game-specific behavior.

PropTypeDefaultRangeMeaning
promptstring"E: interact"—HUD prompt for the nearest eligible interaction.
rangenumber2min 0; metresPlanar reach and maximum vertical separation in metres.
facingDegreesnumber75min 0; max 180; degreesMaximum angle from camera forward, degrees.
actionstring"E"—Input action/key; E also accepts Tap.
oncebooleanfalse—Allow use once per player.
enabledbooleantrue—Whether the actor can apply its behaviour.
assetstring""—Manifest mesh id; empty means no mesh.

Events:

  • onInteract: Called when an eligible player activates the interaction.

Components:

  • root: scene
  • interaction: scene
json
{
  "class": "Interactable",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "prompt": "E: interact",
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": ""
  }
}

Door ​

Level class: Door. Category: Gameplay.

Interactable kinematic door.

PropTypeDefaultRangeMeaning
promptstring"E: open door"—HUD prompt for the nearest eligible interaction.
rangenumber2min 0; metresPlanar reach and maximum vertical separation in metres.
facingDegreesnumber75min 0; max 180; degreesMaximum angle from camera forward, degrees.
actionstring"E"—Input action/key; E also accepts Tap.
oncebooleanfalse—Allow interaction once per player; normally leave false so it can toggle.
enabledbooleantrue—Whether the actor can apply its behaviour.
assetstring""—Manifest mesh id; empty means no mesh.
openOffsetvec3[0,2,0]metresWorld-relative slide offset from the closed spawn position.
openYawnumber0degreesDegrees to rotate instead of sliding when nonzero.
secondsnumber1min 0; secondsDuration in seconds.
lockedBystring""—Inventory item required; empty means unlocked. Cleared on successful unlock.
consumeKeybooleanfalse—Remove one required item when unlocking.
autoCloseSecondsnumber0min 0; secondsWait after opening before closing; zero disables automatic close.
startOpenbooleanfalse—Start at the open pose.

Events:

  • onInteract: Called when an eligible player activates the interaction.

Components:

  • root: box
  • interaction: scene
json
{
  "class": "Door",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "prompt": "E: open door",
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "openOffset": [
      0,
      2,
      0
    ],
    "openYaw": 0,
    "seconds": 1,
    "lockedBy": "",
    "consumeKey": false,
    "autoCloseSeconds": 0,
    "startOpen": false
  }
}

Spawner ​

Level class: Spawner. Category: Gameplay.

Spawn registered actor classes in gameplay waves; destruction counts as a kill on the next fixed step.

PropTypeDefaultRangeMeaning
actorClassstring""—Registered class name to spawn; must be supplied.
pointsstring""—TargetPoint tag; empty or no matches uses this actor pose.
wavesarray[{"count":1,"every":1}]—Wave counts, spawn interval and optional pre-wave delay in seconds.
maxAlivenumber8min 0Maximum living wave children at once.
autoStartbooleantrue—Start waves at beginPlay.

Events:

None.

Components:

  • root: scene
json
{
  "class": "Spawner",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "actorClass": "",
    "points": "",
    "waves": [
      {
        "count": 1,
        "every": 1
      }
    ],
    "maxAlive": 8,
    "autoStart": true
  }
}

CheckpointVolume ​

Level class: CheckpointVolume. Category: Gameplay.

Ordered player respawn checkpoint, or a lap gate owned by a circuit race.

Lap gates use swept plane crossings, including fast movers. Overlap never awards progress. Place all gates before calling race.init(ctx); name them in dense order in createCircuitRace({id:'track',laps:2,maxRacers:4,gates:['start','turn']}). The race id must match every gate's raceId. Gate zero is the start; the first expected gate is one. Yaw is degrees in a level file; local +Z is forward. once is ignored in lap mode. respawnOffset is a local offset in metres, rotated by gate yaw: negative Z is behind, positive Y is above.

Lap-mode level entries (inside a format:1 level):

json
[
  {"class":"CheckpointVolume","name":"start","position":[0,0,0],"scale":[3,2,1],"props":{"mode":"lap","raceId":"track","order":0,"respawnOffset":[0,1,-2]}},
  {"class":"CheckpointVolume","name":"turn","position":[0,0,20],"yaw":180,"scale":[3,2,1],"props":{"mode":"lap","raceId":"track","order":1,"respawnOffset":[0,1,-2]}}
]

Register pawns with race.register(ctx,{racer:1,seat:0,entity:ctx.player}) and step race.system. race.respawn(ctx,1) preserves gate/lap progress and uses respawnPlayer to clear velocity and reset view. A bounded nine-slot grid checks racerRadius (default 0.5m), including racers in other circuits; if occupied, respawn returns false and the system holds progress and retries every 0.25 seconds. The onRespawn(ctx,progress) option is the adapter hook for a future vehicle simulation reset.

PropTypeDefaultRangeMeaning
modeenum"ordered"ordered, lapOrdered respawn checkpoint or swept circuit gate.
raceIdstring""—Lap mode: matching createCircuitRace id.
respawnOffsetvec3[0,0,0]metresLap mode: local safe-pose offset in metres, rotated by gate yaw.
forwardOnlybooleantrue—Lap mode: accept crossings toward local +Z only.
ordernumber0—Ordered mode: progression rank; a lower rank cannot replace a higher one. Lap mode: dense gate index 0..N-1; zero is start.
oncebooleanfalse—Allow use once per player in ordered mode; ignored in lap mode.

Events:

None.

Components:

  • root: box
json
{
  "class": "CheckpointVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "mode": "ordered",
    "raceId": "",
    "respawnOffset": [
      0,
      0,
      0
    ],
    "forwardOnly": true,
    "order": 0,
    "once": false
  }
}

JumpPad ​

Level class: JumpPad. Category: Gameplay.

Launch an entering character body or entity carrying Velocity.

PropTypeDefaultRangeMeaning
launchvec3[0,10,0]metres/secondEntering character/Velocity entity launch velocity [x,y,z], metres/second.
assetstring""—Manifest mesh id; empty means no mesh.
scalevec3[2,1,2]—Mesh scale only; collider remains in world metres.
tintcolor[1,1,1]min 0; max 1Mesh RGB material colour.

Events:

None.

Components:

  • root: box
  • mesh: mesh
json
{
  "class": "JumpPad",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "launch": [
      0,
      10,
      0
    ],
    "asset": "",
    "scale": [
      2,
      1,
      2
    ],
    "tint": [
      1,
      1,
      1
    ]
  }
}

MovingPlatform ​

Level class: MovingPlatform. Category: Gameplay.

Kinematic box moved by the reusable path component.

PropTypeDefaultRangeMeaning
pointsarray[[0,2,0]]—Path offsets [x,y,z] relative to spawn; legacy {x,y,z} objects are also accepted.
secondsnumber2min 0; secondsPositive whole-path traversal time in seconds; zero is invalid.
modeenum"pingPong"once, loop, pingPongPath traversal mode.
waitSecondsnumber0min 0; secondsPause at path endpoints, seconds.
assetstring""—Manifest mesh id; empty means no mesh.

Events:

None.

Components:

  • root: box
  • movement: scene
json
{
  "class": "MovingPlatform",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "points": [
      [
        0,
        2,
        0
      ]
    ],
    "seconds": 2,
    "mode": "pingPong",
    "waitSeconds": 0,
    "asset": ""
  }
}

Projectile ​

Level class: Projectile. Category: Gameplay.

Swept projectile that damages actors or players, attributes hits to its owner and stops after its bounce budget.

PropTypeDefaultRangeMeaning
speednumber20min 0; metres/secondLaunch speed along local +Z, metres/second.
homingTargetnumber0min 0Target ECS entity id; zero disables homing.
damagenumber10min 0Damage applied on a swept hit.
hitResponseenum"damage"damage, effect, bothHit handling: damage, effect hook only, or damage then effect hook.
gravityScalenumber0—Multiplier on world gravity for swept motion.
bouncesnumber0min 0Number of allowed bounces before stopping.
bouncinessnumber0.6min 0; max 1Reflected velocity multiplier.
lifeSpannumber5min 0; secondsSeconds before destruction; zero means forever.
assetstring""—Manifest mesh id; empty means no mesh.

Events:

  • onProjectileHit: Definition hook (self, hit, ctx, stopped); once per effect/both sweep hit before terminal destroy. Hit coordinates are borrowed; bounces report stopped=false.

Components:

  • root: sphere
  • movement: scene
json
{
  "class": "Projectile",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "speed": 20,
    "homingTarget": 0,
    "damage": 10,
    "hitResponse": "damage",
    "gravityScale": 0,
    "bounces": 0,
    "bounciness": 0.6,
    "lifeSpan": 5,
    "asset": ""
  }
}

Custom impacts ​

defineProjectile(name, spec) retains flight, bounces and lifespan. hitResponse defaults to damage; effect requires onProjectileHit at definition (instance overrides are checked at spawn). both applies damage then the hook once per accepted hit, before terminal destruction. Bounces report stopped=false. Hooks may destroy self or target safely; hit coordinates are borrowed. Entity 0 is terrain. The ray sweep excludes the owner entity and projectile body, but not attached owner children; it has no finite radius.

Push a dynamic body without Health; no vehicle-specific helpers are needed:

ts
import { defineProjectile } from 'gameable';

const PushShot = defineProjectile('PushShot', {
  props: { damage: 0, hitResponse: 'effect' },
  onProjectileHit(self, hit, ctx, stopped) {
    // No allocation or retained pooled coordinates; off-centre impulses also impart spin.
    ctx.physics.applyImpulse(hit.entity, 0, 12, 0, hit.point.x, hit.point.y, hit.point.z);
  },
});

HingedDoor ​

Level class: HingedDoor. Category: Gameplay.

A painted single leaf door with a fixed edge hinge.

PropTypeDefaultRangeMeaning
hingeenum"left"left, rightHinge edge viewed from local +Z.
swingDegreesnumber95degreesFull opening angle.
swingAwaybooleantrue—Choose a swing away from the interacting player.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.
  • onPassed: A player crosses the closed doorway plane while not closed.

Components:

  • root: scene
  • leaf: box
  • leafPaint: box
  • leafTop: box
  • leafBottom: box
  • leafSeam: box
  • interaction: scene
json
{
  "class": "HingedDoor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 1,
    "height": 2.1,
    "thickness": 0.1,
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 0.6,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.45,
      0.28,
      0.13
    ],
    "look": "wood",
    "opensWhen": [],
    "toggledBy": "interact",
    "hinge": "left",
    "swingDegrees": 95,
    "swingAway": true
  }
}

SlidingDoor ​

Level class: SlidingDoor. Category: Gameplay.

One or two kinematic panels sliding along the door face.

PropTypeDefaultRangeMeaning
colourcolor[0.35,0.4,0.45]min 0; max 1Linear RGB panel colour.
lookenum"metal"wood, metal, noneBuilt-in painted panel detail; asset overrides this.
panelsnumber1min 1; max 2One full-width panel or two opposing half panels.
slideenum"right"left, right, upSingle panel travel direction in local space.
travelnumber0min 0; metresDistance per panel; zero uses panel width.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.
  • onPassed: A player crosses the closed doorway plane while not closed.

Components:

  • root: scene
  • leaf: box
  • second: box
  • leafPaint: box
  • leafTop: box
  • leafBottom: box
  • leafSeam: box
  • secondPaint: box
  • secondTop: box
  • secondBottom: box
  • secondSeam: box
  • interaction: scene
json
{
  "class": "SlidingDoor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 1,
    "height": 2.1,
    "thickness": 0.1,
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 0.6,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.35,
      0.4,
      0.45
    ],
    "look": "metal",
    "opensWhen": [],
    "toggledBy": "interact",
    "panels": 1,
    "slide": "right",
    "travel": 0
  }
}

DoubleDoor ​

Level class: DoubleDoor. Category: Gameplay.

Two opposing hinged leaves meeting in the centre of a doorway.

PropTypeDefaultRangeMeaning
widthnumber2min 0; metresClosed doorway width.
swingDegreesnumber90min 0; degreesFull opening angle of each leaf.
swingAwaybooleantrue—Swing both leaves away from the interacting player.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.
  • onPassed: A player crosses the closed doorway plane while not closed.

Components:

  • root: scene
  • leaf: box
  • second: box
  • leafPaint: box
  • leafTop: box
  • leafBottom: box
  • leafSeam: box
  • secondPaint: box
  • secondTop: box
  • secondBottom: box
  • secondSeam: box
  • interaction: scene
json
{
  "class": "DoubleDoor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 2,
    "height": 2.1,
    "thickness": 0.1,
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 0.6,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.45,
      0.28,
      0.13
    ],
    "look": "wood",
    "opensWhen": [],
    "toggledBy": "interact",
    "swingDegrees": 90,
    "swingAway": true
  }
}

AutomaticDoor ​

Level class: AutomaticDoor. Category: Gameplay.

An automatic double sliding door with a departure hold and key checks.

PropTypeDefaultRangeMeaning
rangenumber2.5min 0; metresPlanar reach and maximum vertical separation in metres.
secondsnumber0.4min 0; secondsTime to move fully open or closed.
lockedMessagestring"Locked"—Notice on locked interaction; empty disables it.
colourcolor[0.35,0.4,0.45]min 0; max 1Linear RGB panel colour.
lookenum"metal"wood, metal, noneBuilt-in painted panel detail; asset overrides this.
toggledByenum"proximity"interact, signal, proximityInteraction, all named signals, or nearby players.
panelsnumber2min 1; max 2One full-width panel or two opposing half panels.
slideenum"right"left, right, upSingle panel travel direction in local space.
travelnumber0min 0; metresDistance per panel; zero uses panel width.
holdSecondsnumber0.5min 0; secondsHold open after the last player leaves.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.
  • onPassed: A player crosses the closed doorway plane while not closed.

Components:

  • root: scene
  • leaf: box
  • second: box
  • leafPaint: box
  • leafTop: box
  • leafBottom: box
  • leafSeam: box
  • secondPaint: box
  • secondTop: box
  • secondBottom: box
  • secondSeam: box
  • interaction: scene
json
{
  "class": "AutomaticDoor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 1,
    "height": 2.1,
    "thickness": 0.1,
    "range": 2.5,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 0.4,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "Locked",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.35,
      0.4,
      0.45
    ],
    "look": "metal",
    "opensWhen": [],
    "toggledBy": "proximity",
    "panels": 2,
    "slide": "right",
    "travel": 0,
    "holdSeconds": 0.5
  }
}

Gate ​

Level class: Gate. Category: Gameplay.

A metal barred gate rising by its height minus the remaining lip.

PropTypeDefaultRangeMeaning
widthnumber3min 0; metresClosed doorway width.
heightnumber3min 0; metresClosed doorway height.
secondsnumber2min 0; secondsTime to move fully open or closed.
colourcolor[0.35,0.4,0.45]min 0; max 1Linear RGB panel colour.
lookenum"metal"wood, metal, noneBuilt-in painted panel detail; asset overrides this.
toggledByenum"signal"interact, signal, proximityInteraction, all named signals, or nearby players.
lipnumber0.1min 0; metresAmount remaining below the ceiling when open.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.
  • onPassed: A player crosses the closed doorway plane while not closed.

Components:

  • root: scene
  • leaf: box
  • bar0: box
  • bar1: box
  • bar2: box
  • bar3: box
  • bar4: box
  • bar5: box
  • bar6: box
  • bar7: box
  • bar8: box
  • interaction: scene
json
{
  "class": "Gate",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 3,
    "height": 3,
    "thickness": 0.1,
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 2,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.35,
      0.4,
      0.45
    ],
    "look": "metal",
    "opensWhen": [],
    "toggledBy": "signal",
    "lip": 0.1
  }
}

TrapDoor ​

Level class: TrapDoor. Category: Gameplay.

A floor hatch swinging down so its supporting surface clears the opening.

PropTypeDefaultRangeMeaning
widthnumber1.5min 0; metresClosed doorway width.
heightnumber1.5min 0; metresHatch depth along local Z.
toggledByenum"signal"interact, signal, proximityInteraction, all named signals, or nearby players.
swingDegreesnumber90min 0; degreesDownward opening angle about local X.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.

Components:

  • root: scene
  • leaf: box
  • surface: scene
  • surfacePaint: box
  • surfaceTop: box
  • surfaceBottom: box
  • surfaceSeam: box
  • interaction: scene
json
{
  "class": "TrapDoor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 1.5,
    "height": 1.5,
    "thickness": 0.1,
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 0.6,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.45,
      0.28,
      0.13
    ],
    "look": "wood",
    "opensWhen": [],
    "toggledBy": "signal",
    "swingDegrees": 90
  }
}

Lever ​

Level class: Lever. Category: Gameplay.

A keyed or momentary lever supplying an on/off signal to named doors.

PropTypeDefaultRangeMeaning
promptstring"E: interact"—HUD prompt for the nearest eligible interaction.
rangenumber2min 0; metresPlanar reach and maximum vertical separation in metres.
facingDegreesnumber75min 0; max 180; degreesMaximum angle from camera forward, degrees.
actionstring"E"—Input action/key; E also accepts Tap.
oncebooleanfalse—Allow only one successful flip on, including startOn.
enabledbooleantrue—Whether the actor can apply its behaviour.
assetstring""—Manifest mesh id; empty means no mesh.
startOnbooleanfalse—Start with the signal on and the handle fully pulled.
resetSecondsnumber0min 0; secondsTime before springing back off; zero keeps the chosen state.
secondsnumber0.25min 0; secondsTime for a full handle flip.
onPromptstring"E: pull lever"—Prompt while the signal is off.
offPromptstring"E: reset lever"—Prompt while the signal is on.
switchSoundstring""—Manifest audio id on each signal change; empty is silent.
colourcolor[0.455,0.925,0.776]min 0; max 1Linear RGB switch colour.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses E or Tap.
  • onSwitched: The signal changes; who is the last activator, or zero for a startOn reset.

Components:

  • root: scene
  • base: box
  • handle: box
  • interaction: scene
json
{
  "class": "Lever",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "prompt": "E: interact",
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "startOn": false,
    "resetSeconds": 0,
    "seconds": 0.25,
    "onPrompt": "E: pull lever",
    "offPrompt": "E: reset lever",
    "lockedBy": "",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "consumeKey": false,
    "switchSound": "",
    "colour": [
      0.455,
      0.925,
      0.776
    ]
  }
}

PressurePlate ​

Level class: PressurePlate. Category: Gameplay.

A sinking floor plate that signals while enough players or named actors stand on it.

PropTypeDefaultRangeMeaning
widthnumber1min 0; metresTop footprint width.
depthnumber1min 0; metresTop footprint depth.
weightnumber1min 1; occupantsMinimum number of occupants required.
pressedByarray[]—Additional actor instance or class names that count as occupants.
holdSecondsnumber0min 0; secondsKeep the signal on after occupancy drops below the required weight.
oncebooleanfalse—Latch the signal on forever after the first press.
pressSoundstring""—Manifest audio id when pressed; empty is silent.
releaseSoundstring""—Manifest audio id when released; empty is silent.
colourcolor[0.455,0.925,0.776]min 0; max 1Linear RGB plate colour.

Events:

  • onPressed: The signal turns on after reaching the required weight.
  • onReleased: The signal turns off after the hold time expires.

Components:

  • root: scene
  • plate: box
json
{
  "class": "PressurePlate",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 1,
    "depth": 1,
    "weight": 1,
    "pressedBy": [],
    "holdSeconds": 0,
    "once": false,
    "pressSound": "",
    "releaseSound": "",
    "colour": [
      0.455,
      0.925,
      0.776
    ]
  }
}

LevelDoor ​

Level class: LevelDoor. Category: Gameplay.

A swinging or sliding door that takes players to another level.

PropTypeDefaultRangeMeaning
hingeenum"left"left, rightHinge edge viewed from local +Z.
swingDegreesnumber95degreesFull opening angle.
swingAwaybooleantrue—Choose a swing away from the interacting player.
opensenum"swing"swing, slideLeaf movement.
toLevelstring""—Declared destination level; empty fires only onTravel.
toPlayerStartstring""—Arrival PlayerStart or TargetPoint name; empty uses the first PlayerStart.
travelenum"party"party, playerMove the whole party or only the crossing player.
requireOpenbooleantrue—Require open or opening; false accepts any unlocked door phase.
travelPromptstring"Walk through to travel"—Prompt once fully open.

Plus the Door kit props.

Events:

  • onInteract: An eligible player presses the interaction action.
  • onOpened: The panel reaches fully open.
  • onClosed: The panel reaches fully closed.
  • onLocked: A player attempts to open without the key.
  • onUnlocked: A player successfully unlocks the door.
  • onPassed: A player crosses the closed doorway plane while not closed.
  • onTravel: Once per accepted crossing, before loading; may change toLevel.

Components:

  • root: scene
  • leaf: box
  • second: box
  • leafPaint: box
  • leafTop: box
  • leafBottom: box
  • leafSeam: box
  • secondPaint: box
  • secondTop: box
  • secondBottom: box
  • secondSeam: box
  • interaction: scene
json
{
  "class": "LevelDoor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "width": 1,
    "height": 2.1,
    "thickness": 0.1,
    "range": 2,
    "facingDegrees": 75,
    "action": "E",
    "once": false,
    "enabled": true,
    "asset": "",
    "prompt": "E: open",
    "seconds": 0.6,
    "startOpen": false,
    "autoCloseSeconds": 0,
    "lockedBy": "",
    "consumeKey": false,
    "stayOpen": false,
    "openPrompt": "E: open",
    "closePrompt": "E: close",
    "lockedPrompt": "Locked",
    "lockedMessage": "",
    "openSound": "",
    "closeSound": "",
    "lockedSound": "",
    "colour": [
      0.45,
      0.28,
      0.13
    ],
    "look": "wood",
    "opensWhen": [],
    "toggledBy": "interact",
    "hinge": "left",
    "swingDegrees": 95,
    "swingAway": true,
    "opens": "swing",
    "toLevel": "",
    "toPlayerStart": "",
    "travel": "party",
    "requireOpen": true,
    "travelPrompt": "Walk through to travel"
  }
}

VehicleGripVolume ​

Level class: VehicleGripVolume. Category: Volumes.

Timed spherical oil area; overlapping vehicle chassis refresh minimum-combined tyre grip, with recovery after exit. No damage.

PropTypeDefaultRangeMeaning
radiusnumber3min 0; metresSphere radius at unit scale.
durationnumber8min 0; secondsArea lifetime from spawn; zero expires immediately.
gripScalenumber0.15min 0; max 1Tyre grip while affected; overlapping sources combine by minimum.
recoverynumber1min 0; secondsGrip drop retained after last contact; zero means current step only.

Events:

None.

Components:

  • root: sphere
json
{
  "class": "VehicleGripVolume",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "radius": 3,
    "duration": 8,
    "gripScale": 0.15,
    "recovery": 1
  }
}

SoftPlatform ​

Level class: SoftPlatform. Category: Gameplay.

One-way top surface for characterMovement; supports per-character drop-through.

PropTypeDefaultRangeMeaning
assetstring""—Manifest mesh id; empty means no mesh.
scalevec3[4,0.3,2]—Mesh scale only; collider remains in world metres.
tintcolor[1,1,1]min 0; max 1Mesh RGB material colour.

Events:

None.

Components:

  • root: box
  • mesh: mesh
json
{
  "class": "SoftPlatform",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "asset": "",
    "scale": [
      4,
      0.3,
      2
    ],
    "tint": [
      1,
      1,
      1
    ]
  }
}

MeshActor ​

Level class: MeshActor. Category: Scene.

A prop mesh with optional fixed box collision.

PropTypeDefaultRangeMeaning
assetstring""—Manifest mesh id; empty means no mesh.
scalevec3[1,1,1]—Mesh scale only; collider remains in world metres.
tintcolor[1,1,1]min 0; max 1Mesh RGB material colour.
collisionenum"none"none, blockOptional fixed box collider; authored halfExtents, not manifest geometry.
halfExtentsvec3[0.5,0.5,0.5]metresPositive box half sizes [x,y,z], world metres, read at spawn.

Events:

None.

Components:

  • root: scene
  • mesh: mesh
  • collision: box
json
{
  "class": "MeshActor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "asset": "",
    "scale": [
      1,
      1,
      1
    ],
    "tint": [
      1,
      1,
      1
    ],
    "collision": "none",
    "halfExtents": [
      0.5,
      0.5,
      0.5
    ]
  }
}

CharacterActor ​

Level class: CharacterActor. Category: Scene.

An NPC character controller and splat bundle that stands and animates.

PropTypeDefaultRangeMeaning
characterstring""—Manifest character-bundle id; empty means no bundle.
animationstring""—Body-layer clip; empty keeps bundle idle.

Events:

None.

Components:

  • root: character
json
{
  "class": "CharacterActor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "character": "",
    "animation": ""
  }
}

PointLight ​

Level class: PointLight. Category: Scene.

Placeable light placeholder until the host accepts guest light commands.

PropTypeDefaultRangeMeaning
colorcolor[1,1,1]min 0; max 1RGB light colour, preserved only; no light command exists.
intensitynumber1min 0Light intensity, preserved only.
radiusnumber10min 0; metresLight range in metres, preserved only.

Events:

None.

Components:

  • root: scene
json
{
  "class": "PointLight",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "color": [
      1,
      1,
      1
    ],
    "intensity": 1,
    "radius": 10
  }
}

SpotLight ​

Level class: SpotLight. Category: Scene.

Entity-owned spotlight with optional active-camera attachment.

PropTypeDefaultRangeMeaning
colorcolor[1,1,1]min 0; max 1RGB light colour.
intensitynumber20min 0Light intensity.
radiusnumber12min 0; metresLight range.
anglenumber30min 0; max 90; degreesCone half angle.
penumbranumber0.4min 0; max 1Edge softness.
cameraAttachedbooleanfalse—Attach beam to the active camera view.
enabledbooleantrue—Whether the light illuminates.

Events:

None.

Components:

  • root: scene
json
{
  "class": "SpotLight",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "color": [
      1,
      1,
      1
    ],
    "intensity": 20,
    "radius": 12,
    "angle": 30,
    "penumbra": 0.4,
    "cameraAttached": false,
    "enabled": true
  }
}

DirectionalLight ​

Level class: DirectionalLight. Category: Scene.

Placeable light placeholder until the host accepts guest light commands.

PropTypeDefaultRangeMeaning
colorcolor[1,1,1]min 0; max 1RGB light colour, preserved only; no light command exists.
intensitynumber1min 0Light intensity, preserved only.

Events:

None.

Components:

  • root: scene
json
{
  "class": "DirectionalLight",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "color": [
      1,
      1,
      1
    ],
    "intensity": 1
  }
}

WorldText ​

Level class: WorldText. Category: Scene.

Placeable world text anchored to its component entity.

PropTypeDefaultRangeMeaning
textstring""—World text contents.
sizeenum"lg"sm, md, lg, xl, displayText size; defaults to lg.
toneenum"default"default, muted, accent, dangerSemantic text tone; defaults to default.

Events:

None.

Components:

  • root: scene
json
{
  "class": "WorldText",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "text": "",
    "size": "lg",
    "tone": "default"
  }
}

AmbientSound ​

Level class: AmbientSound. Category: Scene.

Entity-attached ambient sound, looping and autoplaying by default.

PropTypeDefaultRangeMeaning
soundstring""—Manifest audio id.
volumenumber1min 0; max 1Linear playback gain.
loopingbooleantrue—Loop until stopped or destroyed.
autoPlaybooleantrue—Play on the first actor step.
busenum"sfx"master, music, sfx, voice, uiMixer bus.

Events:

None.

Components:

  • root: scene
  • sound: scene
json
{
  "class": "AmbientSound",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "sound": "",
    "volume": 1,
    "looping": true,
    "autoPlay": true,
    "bus": "sfx"
  }
}

CameraActor ​

Level class: CameraActor. Category: Scene.

A placeable camera.

PropTypeDefaultRangeMeaning
fovnumber60min 0; degreesVertical camera field of view, degrees.
activateOnStartbooleanfalse—Select this view during construction; last activation wins.

Events:

None.

Components:

  • root: scene
json
{
  "class": "CameraActor",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "fov": 60,
    "activateOnStart": false
  }
}

ParticleEffect ​

Level class: ParticleEffect. Category: Scene.

Persistent entity-attached built-in particle effect; requires features: { vfx: true }.

PropTypeDefaultRangeMeaning
presetenum"fire"hit-sparks, explosion, smoke, fire, magic, dust, trailBuilt-in particle preset.
autoActivatebooleantrue—Activate on the first step.
scalenumber1min 0Particle size multiplier.
intensitynumber1min 0Particle count and brightness multiplier.
tintvec3[1,1,1]min 0Linear RGB; values above one glow.

Events:

None.

Components:

  • root: scene
json
{
  "class": "ParticleEffect",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "preset": "fire",
    "autoActivate": true,
    "scale": 1,
    "intensity": 1,
    "tint": [
      1,
      1,
      1
    ]
  }
}

Character ​

Level class: Character. Category: Framework.

Possessable character bundle with walking, jumping and independent facing.

PropTypeDefaultRangeMeaning
characterstring""—Manifest character-bundle id; empty means no bundle.
maxWalkSpeednumber6min 0; metres/secondMaximum walking speed.
jumpZVelocitynumber4.2min 0; metres/secondUpward speed on jump (world Y; the option name uses a Z-up convention).
orientRotationToMovementbooleantrue—Turn toward movement; disable to hold a controller yaw with setDesiredRotation.
rotationRatenumber540min 0; degrees/secondMaximum yaw speed.

Events:

None.

Components:

  • root: capsule
json
{
  "class": "Character",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "character": "",
    "maxWalkSpeed": 6,
    "jumpZVelocity": 4.2,
    "orientRotationToMovement": true,
    "rotationRate": 540
  }
}

FlyingPawn ​

Level class: FlyingPawn. Category: Framework.

Flying pawn with a kinematic sphere root. WASD or the left touch stick moves horizontally; Space flies up and Control flies down.

PropTypeDefaultRangeMeaning
maxSpeednumber12min 0; metres/secondMaximum flying speed.
collisionbooleantrue—Create a blocking sphere body.

Events:

None.

Components:

  • root: sphere
  • movement: scene
json
{
  "class": "FlyingPawn",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "maxSpeed": 12,
    "collision": true
  }
}

Spectator ​

Level class: Spectator. Category: Framework.

Flying spectator without collision or damageable health.

PropTypeDefaultRangeMeaning
maxSpeednumber12min 0; metres/secondMaximum flying speed.

Events:

None.

Components:

  • root: scene
  • movement: scene
json
{
  "class": "Spectator",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "maxSpeed": 12
  }
}

AIController ​

Level class: AIController. Category: Framework.

AI possession, walking navigation, vehicle driving, racing lines and pursuit.

After possess(ctx, ai, car), use driveTowards(ctx, ai, point, {speed:12}) or followRacingLine(ctx, ai, {actor:'track',component:'line'}, {speed:16,loop:true}). An explicitly ordered array of TargetPoint names can replace the spline reference. chaseVehicle(ctx, ai, suspect, {leadTime:0.6,maxLead:12,ramDistance:5,ramCooldown:4}) uses prediction, speed matching and physical contact. stopDriving(ctx, ai) parks once. Requests require vehicleMovement; intent and tuning are saved in aiMovement.drive. The tuning option accepts lookAheadMin (5m), lookAheadTime (0.45s), steerGain (9), speedGain (0.5), brakeGain (0.3), maxSpeed (30m/s), stuckSeconds (3s), reverseSeconds (1.5s). Recovery aborts after three retries. Destroyed targets/lines or unpossess abort once. Controls run before pawn steps; setFocus never rotates cars. Walking moveTo is unchanged. See the vehicles reference for arrival, preview braking and rival offsets.

PropTypeDefaultRangeMeaning
moveSpeednumber4min 0; metres/secondDesired movement speed.
acceptanceRadiusnumber0.5min 0; metresDistance at which a move succeeds.
turnRatenumber360min 0; degrees/secondMaximum pedestrian focus yaw rate; ignored for vehicle pawns.
possessOnSpawnstring""—Actor instance name to possess on the first step; empty disables.

Events:

  • onNavigationLinkReached: Called with pooled {from,to} after teleporting through a navigation link.
  • onMoveCompleted: Called once when walking or driving succeeds or is aborted, including lost targets and exhausted recovery.

Components:

  • root: scene
  • aiMovement: scene
json
{
  "class": "AIController",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "moveSpeed": 4,
    "acceptanceRadius": 0.5,
    "turnRate": 360,
    "possessOnSpawn": ""
  }
}

GameState ​

Level class: GameState. Category: Framework.

Read-only match lifecycle, clock and winners; rulesState normalizes legacy and phased modes to waiting, inProgress or ended.

PropTypeDefaultRangeMeaning
phasestring""—Active phase name; empty outside configured phases.
roundnumber0min 0One-based round; zero before start.
phaseTimeRemainingnumber0min 0; secondsFixed-step phase countdown; zero for indefinite phases or sudden death.
teamScoresarray[]—Accumulated points indexed by team id; teamScore reads this lane.
matchStateenum"waitingToStart"waitingToStart, inProgress, waitingPostMatchLegacy lifecycle names; rulesState exposes the normalized lifecycle.
rulesStateenum"waiting"waiting, inProgress, endedNormalized lifecycle for all modes: waitingToStart maps to waiting, inProgress stays inProgress, waitingPostMatch maps to ended.
elapsednumber0min 0; secondsSeconds played in this match.
remainingnumber0min 0; secondsTime remaining; zero with no time limit.
winnersarray[]—Winning seats, including ties.

Events:

None.

Components:

  • root: scene
json
{
  "class": "GameState",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "phase": "",
    "round": 0,
    "phaseTimeRemaining": 0,
    "teamScores": [],
    "matchState": "waitingToStart",
    "rulesState": "waiting",
    "elapsed": 0,
    "remaining": 0,
    "winners": []
  }
}

PlayerController ​

Level class: PlayerController. Category: Framework.

Player controller possessing the body provided by definition.player.

PropTypeDefaultRangeMeaning

Events:

None.

Components:

  • root: scene
  • frameworkPlayerTick: scene
json
{
  "class": "PlayerController",
  "position": [
    0,
    0,
    0
  ],
  "props": {}
}

PlayerState ​

Level class: PlayerState. Category: Framework.

Per-player match identity, team and statistics.

PropTypeDefaultRangeMeaning
playerNamestring""—Display name supplied at login.
scorenumber0pointsMatch score.
killsnumber0min 0Other players killed.
deathsnumber0min 0Deaths this match.
teamnumber0—Game-defined team identifier.
seatnumber-1min -1Player seat; -1 means unassigned.

Events:

None.

Components:

  • root: scene
json
{
  "class": "PlayerState",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "playerName": "",
    "score": 0,
    "kills": 0,
    "deaths": 0,
    "team": 0,
    "seat": -1
  }
}

GameMode ​

Level class: GameMode. Category: Framework.

Authority match rules, player login, death scoring and respawning.

PropTypeDefaultRangeMeaning
phasesarray[]—Ordered phases repeated each round; zero/null duration waits for endPhase. Optional respawn overrides the phase death policy.
roundsnumber1min 1Maximum rounds per match.
roundsToWinnumber0min 0Round victories needed to win early; zero disables.
teamsarray[]—Teams in id order, starting at one; zero means unassigned.
autoAssignenum"none"balanced, noneAssign joining players to the smallest available team, ties in definition order.
friendlyFirebooleanfalse—Whether damage code should allow damage between teammates.
allowLateJoinbooleantrue—Allow new seats after the match starts.
lastTeamStandingbooleanfalse—End a round when only one of at least two teams remains alive; use with respawn disabled.
tieBreakenum"draw"draw, suddenDeathFinish tied rounds as draws or wait for a unique score leader.
minPlayersnumber1min 0; playersLogged-in seats required to start.
startDelaynumber0min 0; secondsContinuous readiness time before starting.
matchTimenumber0min 0; secondsMatch duration; zero disables the time limit.
scoreToWinnumber0min 0; pointsWinning score; zero disables the score limit.
killScorenumber1pointsPoints awarded for killing another player.
respawnDelaynumber3secondsDeath-to-respawn delay; negative disables respawn.
restartAfternumber0min 0; secondsPost-match delay; zero leaves the match ended.
playerControllerClassstring"PlayerController"—Registered controller class spawned at login.
playerStateClassstring"PlayerState"—Registered player statistics class spawned at login.
gameStateClassstring"GameState"—Registered match state class spawned with the mode.

Events:

  • onPhaseStarted: Phase begins; borrowed payload contains phase, round and winner.
  • onPhaseEnded: Phase ends before the next begins.
  • onRoundStarted: Round begins before its first phase.
  • onRoundEnded: Round finishes with winner (team id or seat), null for draw.
  • onMatchEnded: Match finishes with winner (team id or seat), null for draw.

Components:

  • root: scene
  • frameworkMatch: scene
json
{
  "class": "GameMode",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "phases": [],
    "rounds": 1,
    "roundsToWin": 0,
    "teams": [],
    "autoAssign": "none",
    "friendlyFire": false,
    "allowLateJoin": true,
    "lastTeamStanding": false,
    "tieBreak": "draw",
    "minPlayers": 1,
    "startDelay": 0,
    "matchTime": 0,
    "scoreToWin": 0,
    "killScore": 1,
    "respawnDelay": 3,
    "restartAfter": 0,
    "playerControllerClass": "PlayerController",
    "playerStateClass": "PlayerState",
    "gameStateClass": "GameState"
  }
}

WheeledVehicle ​

Level class: WheeledVehicle. Category: Framework.

Possessable four-wheel car with heading-following chase camera. Arcade handling, authority-simulated; no client prediction yet. Four raycast wheels only; visuals use manifest ids.

PropTypeDefaultRangeMeaning
handlingenum"arcade"arcade, grippy, driftBase tuning; explicit fields override the preset.
collisionenum | nullnullVehicleChassis collision profile.
halfExtentsvec3 | nullnullmin 0; metresBox chassis half sizes.
massnumber | nullnullmin 0; kilogramsDynamic chassis mass.
wheelsarray | nullnull—Exactly four wheels: local mount, radius/restLength/travel in metres, springHz, dampingRatio, steer/driven/handbrake flags.
maxSpeednumber | nullnullmin 0; metres/secondForward speed cap.
reverseSpeednumber | nullnullmin 0; metres/secondReverse speed cap.
accelerationnumber | nullnullmin 0; metres/second²Drive acceleration.
brakeDecelerationnumber | nullnullmin 0; metres/second²Braking acceleration.
reverseAsBrakeboolean | nullnull—Opposite throttle brakes before reversing.
steerAnglenumber | nullnullmin 0; degreesMaximum steering angle.
steerRatenumber | nullnullmin 0; degrees/secondSteering slew rate.
steeringBySpeedarray | nullnull—Ascending [speed m/s, steering multiplier] points.
gripBySliparray | nullnull—Ascending [slip, grip multiplier] points.
rearHandbrakeGripnumber | nullnullmin 0; max 1Rear grip with handbrake.
driftRecoverynumber | nullnullmin 0; secondsGrip recovery time.
rollingDragnumber | nullnullmin 0; metres/second²Coasting deceleration.
downforcenumber | nullnullmin 0; N/(m/s)²Speed squared downforce coefficient.
antiRollnumber | nullnullmin 0; N/mAxle load transfer stiffness.
uprightAssistnumber | nullnullmin 0; N mBounded upright torque.
airControlnumber | nullnullmin 0; max 1Airborne assist fraction.
assetstring""—Chassis manifest mesh id; empty uses debug chassis.
wheelAssetstring""—Wheel manifest mesh id, model axle along local X; empty uses primitive wheels.

Events:

None.

Components:

  • root: box
  • visual: mesh
  • wheel0: sphere
  • wheel1: sphere
  • wheel2: sphere
  • wheel3: sphere
  • wheels: scene
  • arm: scene
  • camera: scene
json
{
  "class": "WheeledVehicle",
  "position": [
    0,
    0,
    0
  ],
  "props": {
    "handling": "arcade",
    "collision": null,
    "halfExtents": null,
    "mass": null,
    "wheels": null,
    "maxSpeed": null,
    "reverseSpeed": null,
    "acceleration": null,
    "brakeDeceleration": null,
    "reverseAsBrake": null,
    "steerAngle": null,
    "steerRate": null,
    "steeringBySpeed": null,
    "gripBySlip": null,
    "rearHandbrakeGrip": null,
    "driftRecovery": null,
    "rollingDrag": null,
    "downforce": null,
    "antiRoll": null,
    "uprightAssist": null,
    "airControl": null,
    "asset": "",
    "wheelAsset": ""
  }
}

Gameplay modules ​

Import factories from gameable. Helpers, not level classes. Initialize match modules with init after snapshot restoration; reset other helpers in game init. Start timer/wave clocks and use abilities explicitly; step every fixed tick (match modules use system). No default means required; ? means optional. Callbacks are synchronous.

createTriggers ​

Guest box/sphere trigger zones for watched entity points; no physics/networking. Entities without Transform are outside. Optional contains overrides geometry. Reset before adding zones.

OptionTypeDefaultMeaning
capacitynumber—Volume capacity (safe integer).
watchCapacitynumber—Watch capacity (safe integer).
contains?function—(volume: number, entity: number) => boolean. Override point geometry.
compactSnapshot?booleanfalseSparse persistence.
onEnter?function—(ctx: GameContext, volume: number, entity: number) => void. Enter callback.
onExit?function—(ctx: GameContext, volume: number, entity: number) => void. Exit callback.
ts
import { createTriggers, defineGame } from 'gameable';
const zones = createTriggers({ capacity: 1, watchCapacity: 1 });
export default defineGame({
  init(ctx) { zones.reset(); zones.addSphere(0, 0, 0, 3); zones.watch(ctx.player); },
  systems: [ctx => zones.step(ctx)],
});

createMatchModule ​

All-ready lobby/loading/countdown/racing/results match flow, fixed seats, late-join spectators and freeze messages. No movement or checkpoint/finish detection.

OptionTypeDefaultMeaning
maxPlayersnumber—Fixed seat capacity.
historynumber—Per-seat sound history capacity.
spawnsArray<Array<number>>—Seat-start XYZ; at least maxPlayers.
start"all-ready"—Only all-ready.
minPlayersnumber—Network player minimum.
soloMinPlayersnumber—Solo player minimum.
lateJoin"spectate-after-loading"—Late-join policy.
spectatorSpawnZnumber—Spectator Z; seat-spawn X/Y.
loadingSecondsnumber—Loading timeout (seconds).
cardSecondsnumber—Delay before tick cues (seconds).
countdownSecondsnumber—Countdown seconds.
limitSecondsnumber—Racing time limit (seconds).
afterFirstSecondsnumber—Time after first finish (seconds).
resultsSecondsnumber—Results seconds.
ts
import { createMatchModule, type MatchModuleOptions } from 'gameable';
const configure = (options: MatchModuleOptions) => createMatchModule(options);
console.log(configure);

createCheckpointModule ​

Checkpoints and fall recovery for straight decreasing-Z courses. Uses shared match state; no circuit or lap tracking. Run before the match system.

OptionTypeDefaultMeaning
axis"z"—Only Z.
direction"decreasing"—Only decreasing Z.
thresholdsArray<number>—Decreasing-Z thresholds.
pointsArray<Array<number>>—Respawn XYZ per threshold.
spawnsArray<Array<number>>—Lobby/start XYZ per seat.
maxAbsXnumber—Checkpoint X bound.
minYnumber—Checkpoint minimum Y.
fallYnumber—Fall/respawn Y threshold.
lobbyRespawn"seat-start"—Lobby respawn policy.
resetKnockboolean—Clear knock/hit deadlines.
ts
import { createCheckpointModule, type MatchModule, type CheckpointModuleOptions } from 'gameable';
const configure = (match: MatchModule, options: CheckpointModuleOptions) => createCheckpointModule(match, options);
console.log(configure);

createPlacingModule ​

Finish order at one bounded decreasing-Z plane; no laps or checkpoint enforcement. Tie policy. Uses shared match state; run before its system.

OptionTypeDefaultMeaning
axis"z"—Only Z.
direction"decreasing"—Only decreasing Z.
atnumber—Finish plane Z.
maxAbsXnumber—Maximum absolute X at finish.
minYnumber—Minimum Y at finish.
maxYnumber—Maximum Y at finish.
tieBreak"seat"—Tie policy.
requiresAllCheckpointsboolean—Only false is supported.
freezeFinishersboolean—Freeze placed seats.
ts
import { createPlacingModule, type MatchModule, type PlacingModuleOptions } from 'gameable';
const configure = (match: MatchModule, options: PlacingModuleOptions) => createPlacingModule(match, options);
console.log(configure);

createMatchHudModule ​

Publish roster, local seat state, quantized elapsed seconds and sound history to player HUD data; no UI rendering. Uses shared match state; run after its system.

OptionTypeDefaultMeaning
namespacestring—HUD namespace (nonempty).
secondsStepnumber—Time quantum (positive seconds).
ts
import { createMatchHudModule, type MatchModule } from 'gameable';
const configure = (match: MatchModule) => createMatchHudModule(match, { namespace: 'race', secondsStep: 0.1 });
console.log(configure);

createTimers ​

Fixed-step one-shot/repeating timer slots with persistence. Durations capture ctx.dt at start; zero/negative durations take one step.

OptionTypeDefaultMeaning
capacitynumber—Slot capacity (safe integer).
onFire?function—(ctx: GameContext, timer: number) => void. Slot-order callback.
ts
import { createTimers, defineGame } from 'gameable';
const timers = createTimers({ capacity: 1 });
export default defineGame({ init(ctx) { timers.reset(); timers.start(ctx, 0, 1); }, systems: [ctx => timers.step(ctx)] });

createAbilities ​

Per-owner ability charges and fixed-step cooldowns with persistence; no ability effects. Owners are indices, not entity ids. Running recharges retain their duration/timestep.

OptionTypeDefaultMeaning
ownersnumber—Owner capacity (safe integer).
abilitiesArray<{ id: string; cooldown: number; charges?: number = 1 }>—Unique ability definitions.
onReady?function—(ctx: GameContext, owner: number, ability: number) => void. Restored-charge callback.
ts
import { createAbilities, defineGame } from 'gameable';
const skills = createAbilities({ owners: 1, abilities: [{ id: 'dash', cooldown: 0.5 }] });
export default defineGame({ init: () => skills.reset(), systems: [ctx => skills.step(ctx)] });

createWaves ​

Timed spawn attempts with survivor tracking and persistence. onSpawn returns a unique entity id or zero; report death/despawn with killed. Capacity pauses clocks; stop forgets tracking without despawning.

OptionTypeDefaultMeaning
wavesArray<{ count: number; every: number; delay?: number = 0 }>—Wave definitions.
loop?booleanfalseLoop after last clear.
maxAlive?number—Survivor limit; omitted = unlimited.
onSpawnfunction—(ctx: GameContext, wave: number, index: number) => number. Return entity id or zero.
onWaveStart?function—(ctx: GameContext, wave: number) => void. Wave starts.
onWaveClear?function—(ctx: GameContext, wave: number) => void. Wave clears.
onAllClear?function—(ctx: GameContext) => void. Final nonlooping clear.
ts
import { createWaves, defineGame } from 'gameable';
const waves = createWaves({ waves: [{ count: 2, every: 0.5 }], onSpawn: () => 0 });
export default defineGame({ init: ctx => { waves.reset(); waves.start(ctx); }, systems: [ctx => waves.step(ctx)] });

createCircuitRace ​

Circuit laps and live places; publishes full circuits[id] HUD standings with revision-on-change for clients and late joiners. Read with circuitStandings(adapter.hudModel, id). Shares the match HUD transport; compose custom HUD data in a single publisher. Needs gates as positions/yaw/half-extents or named box actors; optional section line. Teleport adapters must reset crossing history.

OptionTypeDefaultMeaning
idstring—Unique race id.
lapsnumber—Lap count.
maxRacersnumber—Racer capacity.
gatesArray<string>—Ordered gate geometry or actor names; start is zero.
line?object—Section polylines or named spline.
racerRadiusnumber0.5Respawn occupancy radius in metres.
onRespawn?function—After pawn respawn; adapter hook for vehicle reset.
resetOnDisconnectbooleanfalseRemove disconnected identity.
ts
import { createCircuitRace } from 'gameable';
const race = createCircuitRace({id:'race',laps:2,maxRacers:4,gates:['start','turn']});
console.log(race.standings);