BLOXAR Lua API

Block scripts in BLOXAR are written in Lua and run in an isolated virtual machine (fengari) — each script has its own separate state, and scripts cannot see each other's variables directly. Blocks can communicate with each other only through the explicit engine functions described in this document, or through events (emit/on).

🔑 Core principle

A script has no direct access to the engine's 3D objects. Instead of parent.position.x = 5 use functions like setBlockPosition(id, x, y, z), where id is the unique UUID of a block.

🚀 First script

  1. Open the project in Studio Mode.
  2. In the Explorer panel, select a block, click ➕ and add 📜 Script.
  3. Click the script — the code editor will open.
  4. Write Lua code and click Save & Close.
  5. Click Publish to publish the world to the server.

Important: scripts are saved only via Publish (an actual publication of the world), not via local saving of the .blxr file. After publishing, re-enter the place so that the script takes effect.

Minimal example

function onTick(dt)
    if isKeyDown('e') then
        say('Hello from the script!')
    end
end

onTick(dt) is the only function the engine calls automatically, every frame, with dt being the time in seconds since the previous frame. All other code inside the script is written around it.

🧬 Block variables

These functions are available only inside a script attached to a block — they return data of precisely this block, without requiring a UUID.

getBlockX() / getBlockY() / getBlockZ()→ number

Current coordinates of the block the script is attached to.

getBlockName()→ string

The block's name, set in the editor.

getBlockUUID()→ string

The unique ID of this block — use it in functions like setBlockPosition(id, ...) to move itself.

⚡ Events

onPlayerEnter(function(who) ... end)

Called once when a player enters a radius of ~1.5 from the block. who is the player's nickname.

onTouch(function(who) ... end)

Called once when a player touches the block up close (radius ~1.0).

emit(eventName, key1, val1, key2, val2, ...)

Sends an event to all blocks subscribed to eventName via on().

on(eventName) / off(eventName)

Subscribe/unsubscribe. When triggered, the script's global function onEvent_<eventName>(data).

-- Button block
on('door_toggle')
function onEvent_door_toggle(data)
    say('The door received a signal from ' .. data.from)
end

function onTick(dt)
    if isKeyDown('e') then
        emit('door_toggle', 'state', 'open')
    end
end

❤️ Player health and position

getPlayerHealth() / getPlayerMaxHealth()→ number

Current and maximum player health.

isPlayerAlive() / isPlayerDead()→ boolean

Whether the player is alive right now.

damagePlayer(amount) / healPlayer(amount)

Deals damage / restores health. Does not go beyond 0..max.

killPlayer() / respawnPlayer()

Instantly kills or respawns the player at the spawn point.

isPlayerSpawnProtected()→ boolean / protectPlayer()

Check/enable temporary invulnerability after spawning.

getPlayerPosition()→ x, y, z

Player position. Returns three numbers: local x, y, z = getPlayerPosition().

setPlayerPosition(x, y, z) / movePlayerBy(dx, dy, dz)

Teleports the player or shifts them by an offset.

teleportPlayerToBlock(uuid)

Teleports the player to the specified block (slightly above its position).

getPlayerRotationY()→ number / setPlayerRotationY(rad)

Player rotation around the vertical axis, in radians.

getPlayerNickname() / getPlayerSkin()

Nickname and skin of the local player.

isNoclipEnabled()→ boolean / setNoclip(enabled)

Walk-through-walls mode.

distanceToPlayer(x, y, z)→ number

Distance from the player to a point — the basis for traps and triggers.

⌨️ Input

isKeyDown(key)→ boolean

Whether a key is held down right now. A lowercase string: 'w', 'e', ' ' (space), 'shift'.

isAnyKeyDown(...keys) / areAllKeysDown(...keys)→ boolean

At least one / all of the listed keys are held down simultaneously.

getPressedKeys()→ string

A comma-separated list of all held keys — for debugging.

🎥 Camera

getCameraPosition()→ x, y, z

Current camera position.

getCameraDistance()→ number / setCameraDistance(dist)

Camera distance from the player in third-person mode (1..40).

isStudioMode()→ boolean

Whether the script is running in Studio mode (touch events do not fire there).

🌍 Time of day and gravity

getDayTime()→ number / setDayTime(radians)

Current time of day in radians (0..2π — a full cycle).

setTimeOfDay('day'|'night'|'dawn'|'dusk')

Quickly set the time of day by name.

getGravity()→ number / setGravity(value) / resetGravity()

Reads/changes the strength of gravity in the world; resetGravity() restores the default value.

getEnvironmentData() / getWorldData()

Service data about the environment and the world.

toggleClouds(enabled) / generateTerrain()

Turns clouds on/off, or starts terrain generation.

scanArea()→ string

Scans placed blocks (water/lava nearby, average height) — useful for AI scripts. Format: "hasWater:0,hasLava:0,blockCount:12,avgY:3.5,dominantColor:...".

🧱 Blocks

Each function takes or returns a uuid — the unique ID of a block (you can get it via getBlockUUID() for your own block, findBlockByName() for someone else's, or as the result of spawnBlock()).

Search

findBlockByName(name)→ string | nil

UUID of the first block with the specified name.

findAllBlocksByName(name)→ string

All matching UUIDs, comma-separated. See also the data tables below.

getUniqueBlockNames()→ string / blockExists(uuid)→ boolean / getBlockCount()→ number

General information about all blocks in the world.

Reading properties

getBlockPosition(uuid)→ x, y, z / getBlockScale(uuid)→ x, y, z

Block position and scale.

getBlockName(uuid) / getBlockColor(uuid) / isBlockPhysical(uuid)

Block name, color (hex) and physical collision.

Modification

setBlockPosition(uuid, x, y, z) / moveBlockBy(uuid, dx, dy, dz)

Moves a block in the world.

setBlockColor(uuid, hex) / setBlockScale(uuid, sx, sy, sz) / setBlockRotation(uuid, rx, ry, rz)

Recolors, scales, rotates a block (radians).

setBlockVisible(uuid, visible)

Shows/hides a block.

Creation / removal

spawnBlock(shape, color, x, y, z, sx, sy, sz)→ string (uuid)

Creates a new block. shape: 'box', 'sphere', 'cone', 'cylinder'.

removeBlock(uuid) / removeAllBlocksByName(name)

Removes a block (or all blocks with the specified name).

📡 Raycast

raycastForward(maxDistance)→ string (uuid) | nil

A ray from the camera forward. Returns the UUID of the first block hit.

raycastFrom(ox, oy, oz, dx, dy, dz, maxDistance)→ string (uuid) | nil

A ray from an arbitrary point in an arbitrary direction.

🎒 Inventory and score

getActiveSlot()→ number / selectSlot(slotNum)

The currently selected slot and switching to another.

getInventoryItem(slotNum) / hasItemInSlot(slotNum)

What is in the slot.

giveItem(slot, itemId) / clearInventorySlot(slot)

Puts an item into a slot or clears it.

setGlobalVar(key, value) / getGlobalVar(key)

Variables shared by all scripts for the duration of the session — handy for keeping score or a simple currency.

setGlobalVar('score', (getGlobalVar('score') or 0) + 10)
say('Score: ' .. getGlobalVar('score'))

👥 Multiplayer

Read-only — other players are controlled by the server directly.

getOtherPlayers()→ string

Format: "id:nick:x:y:z;id:nick:x:y:z". For a proper table, see getOtherPlayersTable() below.

getOtherPlayerCount()→ number / getOtherPlayerPosition(id)→ x, y, z

Number of players nearby and the position of a specific one by its id.

🔊 Sound and chat

playSound(type, intensity)

Plays an engine sound effect.

playMusic(url, name) / stopMusic()

Background music from a link.

say(text)

A message on behalf of the script in chat + a speech bubble above the player.

announce(text)

A system message in a different color — for warnings.

⏱ Timers

wait(seconds, callback)

Runs a Lua function after the specified number of seconds.

wait(2, function()
    say('2 seconds have passed')
end)

🖥️ UI and dialogs

showNotification(text, duration)

A pop-up notification at the top of the screen (toast).

showDialog(title, text)

A modal window with an OK button in the center of the screen.

📊 Data tables

Most API functions return a string (easier to marshal into Lua), but for lists of objects there are versions that return a real Lua table.

getOtherPlayersTable()→ table

An array of tables {id, nickname, x, y, z}.

findAllBlocksByNameTable(name)→ table

An array of UUID strings instead of a comma-separated string.

for i, p in ipairs(getOtherPlayersTable()) do
    print(p.nickname, p.x, p.y, p.z)
end

🎬 Animations

registerAnimation(uuid, speedY) / unregisterAnimation(uuid)

Enables/disables a block's built-in animation (for example, constant rotation).

🧮 Math and utilities

distance3D(x1,y1,z1, x2,y2,z2)→ number

Distance between two points in 3D.

clamp(v, min, max) / lerp(a, b, t) / randomRange(min, max) / vectorLength(x, y, z)

Standard helpers that plain Lua lacks.

getTime()→ number

Time in seconds since the page was loaded.

print(...) / warn(...)

Output to the browser console — the main tool for debugging scripts.

💡 Ready-made examples (Copy & Paste)

Light car (get in with E)

local carId = nil
local seated = false
local eWasDown = false
local speed = 6.0
local turnSpeed = 2.2
local enterRadius = 2.5
local rotY = 0

function onTick(dt)
    if carId == nil then carId = getBlockUUID() end
    local cx, cy, cz = getBlockX(), getBlockY(), getBlockZ()
    local eDown = isKeyDown('e')
    local ePressed = eDown and not eWasDown
    eWasDown = eDown

    if not seated then
        if ePressed and distanceToPlayer(cx, cy, cz) < enterRadius then
            seated = true
            say('Got behind the wheel')
        end
        return
    end

    if ePressed then
        seated = false
        say('Got out of the car')
        setPlayerPosition(cx + 2, cy + 1, cz)
        return
    end

    if isKeyDown('a') then rotY = rotY + turnSpeed * dt end
    if isKeyDown('d') then rotY = rotY - turnSpeed * dt end

    local moveDir = 0
    if isKeyDown('w') then moveDir = 1 end
    if isKeyDown('s') then moveDir = -1 end

    local nx, nz = cx, cz
    if moveDir ~= 0 then
        nx = cx + math.sin(rotY) * speed * dt * moveDir
        nz = cz + math.cos(rotY) * speed * dt * moveDir
    end

    setBlockPosition(carId, nx, cy, nz)
    setBlockRotation(carId, 0, rotY, 0)
    setPlayerPosition(nx, cy + 1.0, nz)
    setPlayerRotationY(rotY)
end

Spike trap (damage on touch)

local cooldown = 0

function onTick(dt)
    cooldown = math.max(0, cooldown - dt)
    local x, y, z = getBlockX(), getBlockY(), getBlockZ()
    if distanceToPlayer(x, y, z) < 1.2 and cooldown <= 0 then
        cooldown = 1.5
        damagePlayer(20)
        playSound('land', 1)
    end
end

Interactive button

local activated = false

function onTick(dt)
    local x, y, z = getBlockX(), getBlockY(), getBlockZ()
    if distanceToPlayer(x, y, z) < 3 and not activated then
        if isKeyDown('e') then
            activated = true
            playSound('jump', 1)
            setBlockColor(getBlockUUID(), 0x2EE6A6)
            announce('Button activated!')
        end
    end
end

Portal with a delay

local used = false

function onPlayerEnter(who)
    if used then return end
    used = true
    say(who .. ' activated the portal')
    wait(1, function()
        setPlayerPosition(0, 5, 0)
        used = false
    end)
end