Lua API reference

The runtime exposes a sandboxed Lua 5.3 environment via fengari. Entity scripts define lifecycle hooks (onStart, onUpdate(dt), onCollision(otherId)) and can call the globals below. self is the entity handle, set before each hook.

Sandbox
  • Removed globals: os, io, debug, loadfile, dofile.
  • print is overridden to call game.log.
  • require resolves only against the manifests module registry.
  • Rotations in Lua are in degrees.

Input

Function form of `input.getAxis`. Convenient for legacy shims and event callbacks.

NameTypeDescription
axisstringAxis identifier.
Returnsnumber

Returns the current value of a float input axis.

NameTypeDescription
axisstringAxis identifier (e.g. `"pointer.dragX"`, `"pointer.scrollY"`, `"gesture.palmX"`, `"gesture.palmY"`).
ReturnsnumberTypically in `[-1, 1]` for normalized axes. 0 when not driven.
local yaw = input.getAxis("pointer.dragX")
self:setRotation(0, yaw * 180, 0)

Returns true while an input button is held.

NameTypeDescription
buttonstringButton identifier. Platform-registered examples: keyboard (`"key.space"`, `"key.1"`..`"key.5"`, `"key.q"`, `"key.e"`, `"key.f"`, `"key.r"`), gestures (`"gesture.open_palm"`, `"gesture.point"`, `"gesture.thumbs_up"`, `"gesture.thumbs_down"`), or multiplayer event names routed from phone controllers.
Returnsboolean
if input.isPressed("gesture.open_palm") then
  game.playAnimation(self.id, "flap")
end

Entity

Removes an entity from the scene and destroys its physics body.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
game.destroy("enemy_42")

Looks up an entity declared in the manifest by its ID.

NameTypeDescription
idstringEntity ID from `manifest.entities[].id`.
ReturnsEntityHandle|nilHandle with an `id` field and `self:*` methods, or `nil` if not found.
local bird = game.findEntity("phoenix")
if bird then bird:setPosition(0, 1, 0) end

Spawns a new entity at runtime. Overloaded: - First arg is a string → spawn a registered prefab/asset by name (2nd arg optional position). - First arg is a table → spawn a primitive with `{ mesh, id?, position? }`.

NameTypeDescription
prefabOrOptsstring|objectPrefab name, or `{ mesh: "box"|"sphere"|"plane"|"cylinder"|"cone"|"torus", id?: string, position?: {x,y,z} }`.
position?object`{x, y, z}` spawn position when first arg is a prefab name.
ReturnsEntityHandle|nil
local enemy = game.spawn("goblin", { x = 0, y = 0, z = -2 })
local cube = game.spawn({ mesh = "box", position = { x = 1, y = 0, z = 0 } })

Transform

Returns an entity's world-space axis-aligned bounding box.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
Returnsobject|nil`{min_x, min_y, min_z, max_x, max_y, max_z, size_x, size_y, size_z}` or `nil`.
local b = game.getBounds(self.id)
if b then game.log("height:", b.size_y) end

Returns an entity's current world position.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
Returnsobject|nil`{x, y, z}` or `nil` if the entity doesn't exist.
local p = game.getPosition(self.id)
if p then game.log(p.x, p.y, p.z) end

game.move

Transform

Sets an entity's world position.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
posobject`{x, y, z}` in world units.
game.move(self.id, { x = 0, y = 1, z = 0 })

game.rotate

Transform

Sets an entity's Euler rotation in **degrees**. Susceptible to gimbal lock — prefer `game.rotateQ` for accumulated rotations.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
rotobject`{x, y, z}` Euler angles in **degrees**.
game.rotate(self.id, { x = 0, y = 90, z = 0 })

game.rotateQ

Transform

Sets an entity's rotation from a quaternion. No gimbal lock — preferred for frame-to-frame accumulated rotations.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
wnumberQuaternion w component.
xnumberQuaternion x component.
ynumberQuaternion y component.
znumberQuaternion z component.
game.rotateQ(self.id, 1, 0, 0, 0)  -- identity

game.scale

Transform

Sets an entity's scale. Pass a single number for uniform scale, or `{x, y, z}` for per-axis scale.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
scalenumber|objectUniform multiplier, or `{x, y, z}`.
game.scale(self.id, 1.5)
game.scale(self.id, { x = 1, y = 2, z = 1 })

Physics

Adds a dynamic cannon-es rigid body to the entity at runtime. If the entity already has a body this is a no-op.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
opts?object
opts.mass?number = 1Rigid body mass (kg).
opts.gravity?boolean = trueWhether gravity affects this body.
game.addPhysics(self.id, { mass = 2, gravity = true })

game.push

Physics

Applies an instantaneous impulse to the entity's rigid body. Wakes sleeping bodies. No-op if the entity has no physics body.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
impulseobject`{x, y, z}` impulse vector.
game.push(self.id, { x = 0, y = 5, z = 0 })  -- jump

Tween

Cancels any in-flight tween on the entity.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.

Tweens any combination of entity properties to target values over a duration. Targets are a flat table keyed by property name — accepted keys include `position_x/y/z`, `rotation_x/y/z` (degrees), `scale_x/y/z`, and any entity property your `GameAPI` registers.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
targetsobjectFlat table of `{ property_name = target_value, ... }`.
durationnumberSeconds.
easing?stringEasing name (`"linear"`, `"easeInOutQuad"`, etc.).
game.tween(self.id, { position_y = 2, rotation_y = 90 }, 0.5, "easeInOutQuad")

Animation

Returns the list of animation clip names available on an entity's model. Returns an empty array for entities without a model or with no clips.

NameTypeDescription
entityIdstringEntity ID.
Returnsstring[]Array of clip names (1-indexed Lua table).
for i, name in ipairs(game.listAnimations(self.id)) do game.log(name) end

Plays an animation clip on an entity. Returns `true` if the clip exists.

NameTypeDescription
entityIdstringEntity ID.
namestringClip name (see `game.listAnimations`).
opts?object
opts.loop?boolean = trueLoop the clip.
opts.timeScale?number = 1Playback rate multiplier.
opts.crossFadeDuration?number = 0Seconds to crossfade from the current clip.
Returnsboolean
game.playAnimation(self.id, "flap", { loop = true, crossFadeDuration = 0.2 })

Plays an animation clip exactly once (loop=false, no crossfade). Returns `true` if the clip exists.

NameTypeDescription
entityIdstringEntity ID.
namestringClip name.
Returnsboolean

Stops the entity's current animation (if any) and returns the model to its bind pose.

NameTypeDescription
entityIdstringEntity ID.

Audio

Fades out **all** music channels simultaneously. Useful for scene transitions.

NameTypeDescription
durationnumberFade-out length in seconds.

Fades a music channel's volume to zero over `duration` seconds, then stops it.

NameTypeDescription
durationnumberFade-out length in seconds.
channel?string = "default"Channel name.

Plays a looping/long-running music track on a named channel. Music channels are independent: call `playMusic` with different `channel` strings to layer tracks. Use `game.setMusic` to adjust volume/pitch mid-playback.

NameTypeDescription
namestringSound name from the manifest.
opts?object
opts.volume?number = 10..1
opts.loop?boolean = true
opts.pitch?number = 1Playback rate / pitch multiplier.
opts.channel?string = "default"Channel name for later `stopMusic`/`setMusic`/`fadeOutMusic`.
game.playMusic("theme", { channel = "bg", volume = 0.4 })

Plays a one-shot sound effect. Sound names map to assets via the manifest's `sounds` table.

NameTypeDescription
namestringSound name from `manifest.sounds[].name`.
opts?object
opts.volume?number = 10..1
opts.loop?boolean = false
game.playSound("pop", { volume = 0.6 })

Adjusts volume and/or pitch on a playing music channel without restarting it.

NameTypeDescription
channelstringChannel name.
opts?object
opts.volume?number
opts.pitch?number
game.setMusic("bg", { volume = 0.2, pitch = 1.2 })

Immediately stops music on the named channel.

NameTypeDescription
channelstringChannel name (use `"default"` if you omitted `channel` in `playMusic`).

Stops any currently-playing instances of the named sound.

NameTypeDescription
namestringSound name.

Timers

Runs a callback once after `seconds`. Returns a timer ID you can cancel.

NameTypeDescription
secondsnumberDelay in seconds.
callbackfunctionLua function to call (no arguments).
ReturnsnumberTimer ID for `game.cancelTimer`.
game.after(1.5, function() game.playSound("pop") end)

Cancels a timer returned by `game.after` or `game.every`. Unknown IDs are ignored.

NameTypeDescription
timerIdnumberID returned by `game.after` or `game.every`.

Runs a callback repeatedly at `seconds` interval. Returns a timer ID.

NameTypeDescription
secondsnumberInterval in seconds.
callbackfunctionLua function to call (no arguments).
ReturnsnumberTimer ID for `game.cancelTimer`.
local t = game.every(1, function() game.log("tick") end)
game.after(10, function() game.cancelTimer(t) end)

Events

Fires a named event. All subscribers registered via `game.on(event, ...)` are called synchronously in registration order.

NameTypeDescription
eventstringEvent name.
game.fireEvent("score", 10)

game.on

Events

Subscribes a callback to a named event. Events can come from the runtime (collisions, gestures) or be fired from any script via `game.fireEvent`. For multiplayer-scoped events see `game.onPlayer`.

NameTypeDescription
eventstringEvent name.
callbackfunction`function(...args)` called when the event fires.
game.on("score", function(points) total = total + points end)

Multiplayer

Returns the currently active player ID, set via `game.setActivePlayer`.

Returnsnumber1-based player index (0 if no player active).

game.onPlayer

Multiplayer

Subscribes to an event scoped to a specific player. Sugar for `game.on("p{playerId}_{event}", callback)`. Use with the multiplayer relay which dispatches phone-controller inputs as player-scoped events.

NameTypeDescription
playerIdnumberPlayer index (1-based).
eventstringEvent name (without the `p{n}_` prefix).
callbackfunction`function(...args)` called when the scoped event fires.
game.onPlayer(1, "swing", function(power) hit(1, power) end)

Sets the active player ID used by gameplay systems that route input/state by current player (e.g. turn-based games).

NameTypeDescription
playerIdnumberPlayer index (1-based).

UI (3D)

Removes a 3D UI text label.

NameTypeDescription
idstringHandle from `game.ui.text`.

Creates a 3D world-space text label. The label renders in the scene at the given coordinates and follows the camera orientation (billboarded).

NameTypeDescription
textstringText to display (auto-coerced via `tostring`).
opts?object
opts.x?number = 0
opts.y?number = 0
opts.z?number = 0
opts.size?number = 1World-space text size.
Returnsstring|nilHandle ID for `game.ui.update` / `game.ui.remove`, or `nil` on failure.
local h = game.ui.text("HP: 10", { y = 2, size = 0.5 })

Replaces the content of an existing 3D UI text label.

NameTypeDescription
idstringHandle from `game.ui.text`.
textstringNew text (auto-coerced via `tostring`).

Side UI

Returns the currently active side set via `game.side.set`.

Returnsstring`"front"`, `"back"`, `"left"`, or `"right"`.

Instantiates a registered side-UI prefab (HUD/status/score widget) on a side of the Pepper's Ghost diamond.

NameTypeDescription
sidestring`"front"`, `"back"`, `"left"`, or `"right"`.
namestringPrefab name registered by the runtime or manifest.
opts?object
opts.anchor_x?number = 0.5
opts.anchor_y?number = 0.5
ReturnsstringHandle ID for `game.side.remove`, `setFill`, `setColor`.

Removes a side overlay by its handle.

NameTypeDescription
handlestringID returned by `game.side.text` or `game.side.prefab`.

Sets the active side for the Pepper's Ghost diamond viewport. Subsequent calls that omit a `side` argument use this value.

NameTypeDescription
sidestring`"front"`, `"back"`, `"left"`, or `"right"`.

Sets the color of a named sub-element of a side prefab.

NameTypeDescription
handlestringPrefab handle from `game.side.prefab`.
pathstringSub-element path within the prefab.
colorstringCSS color string.

Updates a fill ratio (0..1) on a named sub-element of a side prefab — e.g. a progress bar's "bar" path.

NameTypeDescription
handlestringPrefab handle from `game.side.prefab`.
pathstringSub-element path within the prefab (e.g. `"bar"`).
rationumber0..1

Places a 2D text overlay on one face of the Pepper's Ghost diamond. Overlays are screen-space per side — they stay put as the user looks around.

NameTypeDescription
sidestring`"front"`, `"back"`, `"left"`, or `"right"`.
textstringText to display (auto-coerced via `tostring`).
opts?object
opts.size?numberFont size.
opts.color?stringCSS color string.
opts.anchor_x?number = 0.50 = left, 0.5 = center, 1 = right.
opts.anchor_y?number = 0.50 = top, 0.5 = center, 1 = bottom.
ReturnsstringHandle ID for `game.side.remove`.
local h = game.side.text("front", "Hello", { size = 48, anchor_y = 0.1 })

Scene

Destroys all runtime-spawned entities. Entities declared in the manifest are preserved.

Requests a scene transition. The client handles the actual navigation — typically maps `name` to a manifest and loads it.

NameTypeDescription
namestringScene identifier.
game.loadScene("main_menu")

Viewport

Adjusts bloom post-processing at runtime. Pass any subset of `{ intensity, threshold, radius }`; omitted keys keep their current value.

NameTypeDescription
opts?object
opts.intensity?numberOverall bloom strength.
opts.threshold?numberLuminance threshold above which pixels bloom.
opts.radius?numberBloom spread radius.
game.setBloom({ intensity = 1.5, threshold = 0.7 })

Sets the camera distance for the Pepper's Ghost viewport. No effect in standard viewport mode.

NameTypeDescription
distancenumberWorld-space distance from target.

VFX

Spawns a one-shot visual effect at a world position. VFX names are registered by the runtime (e.g. sparkles, explosions).

NameTypeDescription
namestringVFX name.
posobject`{x, y, z, scale?}`. `scale` multiplies the default VFX size.
game.vfx("sparkle", { x = 0, y = 1, z = 0, scale = 2 })

Mesh

Slices an entity's mesh along a plane, producing two new entities. The plane is defined by a normal `{nx, ny, nz}` and an optional point `{px, py, pz}` (defaults to entity center). The original entity is destroyed.

NameTypeDescription
idstring|EntityHandleEntity ID or handle.
planeobject`{ nx, ny, nz, px?, py?, pz? }`. Normal defaults to `{1,0,0}`; point defaults to entity center.
Returnsobject|nil`{ pos = EntityHandle, neg = EntityHandle }` for the two halves, or `nil` on failure.
local pieces = game.cut(self.id, { nx = 0, ny = 1, nz = 0 })
if pieces then pieces.pos:applyImpulse(0, 2, 0) end

Settings

Reads a key previously stored via `game.setSetting`.

NameTypeDescription
keystringSetting name.
Returnsboolean|number|string|nil

Stores a key/value in the runtime settings bag. Used for cross-script communication and manifest-level tuning knobs.

NameTypeDescription
keystringSetting name.
valueboolean|number|stringValue (non-primitives are ignored).

Logging

game.clock

Logging

Seconds since the Unix epoch — useful as a seed for `math.randomseed`.

Returnsnumber
math.randomseed(game.clock())

game.log

Logging

Writes any number of arguments to the in-UI debug console. The global `print(...)` is rewired to call this.

NameTypeDescription
args...anyValues to log. Numbers, strings, booleans stringified.
game.log("hp:", hp, "pos:", self:getPosition())

print

Logging

Standard Lua `print` is overridden to route through `game.log`, so all output appears in the runtime's in-UI debug console.

NameTypeDescription
args...any

Entity handle (self)

self:applyForce

Entity handle (self)

Applies a continuous force to the entity's rigid body (ignored if no physics body). Must be called every frame for sustained motion. Wakes sleeping bodies.

NameTypeDescription
xnumber
ynumber
znumber

self:applyImpulse

Entity handle (self)

Applies an instantaneous impulse to the entity's rigid body. Wakes sleeping bodies. Use for jumps, knockbacks, projectile launches.

NameTypeDescription
xnumber
ynumber
znumber

self:destroy

Entity handle (self)

Destroys this entity.

self:destroy()

self:getPosition

Entity handle (self)

Returns the entity's world position as three separate numbers (not a table).

Returnsnumber,number,number`x, y, z`
local x, y, z = self:getPosition()

self:getRotation

Entity handle (self)

Returns the entity's Euler rotation in **degrees** as three separate numbers.

Returnsnumber,number,number`x, y, z` in degrees.

self:getScale

Entity handle (self)

Returns the entity's scale as three separate numbers.

Returnsnumber,number,number

self:getVelocity

Entity handle (self)

Returns the entity's current rigid-body velocity as three numbers. Returns `(0, 0, 0)` if the entity has no physics body.

Returnsnumber,number,number

self:setPosition

Entity handle (self)

Sets the entity's world position.

NameTypeDescription
xnumber
ynumber
znumber
self:setPosition(0, 1, 0)

self:setRotation

Entity handle (self)

Sets the entity's Euler rotation in **degrees**. Prefer `game.rotateQ` for accumulated frame-to-frame rotations (avoids gimbal lock).

NameTypeDescription
xnumberDegrees.
ynumberDegrees.
znumberDegrees.

self:setScale

Entity handle (self)

Sets the entity's per-axis scale.

NameTypeDescription
xnumber
ynumber
znumber

self:setVelocity

Entity handle (self)

Directly sets the entity's rigid-body velocity. Ignored if no physics body.

NameTypeDescription
xnumber
ynumber
znumber

self:tween

Entity handle (self)

Tweens a single named property on this entity. For multi-property tweens prefer `game.tween(self.id, {...}, duration, easing)`.

NameTypeDescription
propertystringProperty name (e.g. `"position"`, `"rotation"`, `"scale"`).
targetobject`{x=, y=, z=}` target values.
durationnumberSeconds.
easing?string
self:tween("position", { x = 0, y = 2, z = 0 }, 0.5, "easeInOutQuad")
Generated from JSDoc in packages/runtime/src/engines/fengari.ts. Regenerate with pnpm docs:lua.