BrickBit Hosted Scripting

Hosted game logic on BrickBit is now Luau-only. The game server still uses node-hill for networking and world state, but hosted user scripts are no longer executed as JavaScript or through the old Node sandbox.

Every newly created game now publishes a default starter bundle containing a baseplate and spawnpoint, so new games start from a valid playable map instead of an empty unpublished state.

Starter Game

New games created from the site or Workshop immediately receive a repo-owned starter bundle. That bundle contains:

  • A default baseplate map
  • A spawnpoint brick
  • An empty scripts.manifest.json so hosted scripting metadata is present from day one

You can replace the starter map later by uploading a new BRK, but every game now starts from a real playable base state.

Script Types

BrickBit stores script metadata in the bundle manifest and extracts it into runtime buckets. The script editor exposes the same script types.

Type Runtime behavior
server Executed by the hosted Luau runtime when the server boots.
server_storage Available to require() as Luau modules. Not auto-started.
replicated Included in the delivery manifest for future client fetch/order work. Not executed server-side.
client Included in the delivery manifest for client-only execution later. Not executed server-side.
legacy javascript Readable for migration, but never executed by hosted servers.

New hosted authoring accepts .lua and .luau only. Existing .js rows stay visible so you can migrate them.

Bridge API

Hosted Luau scripts interact with the running server through a narrow bridge instead of a full Node runtime. The bridge is versioned under Bridge.meta.version.

Inbound events

Bridge.on("playerJoin", function(player)
    print("joined", player.username)
end)

Bridge.on("playerLeave", function(player)
    print("left", player.username)
end)

Bridge.on("initialSpawn", function(player)
    print("spawned", player.username)
end)

Bridge.on("chat", function(player, message)
    print(player.username, message)
end)

Bridge.on("brickClick", function(player, brick, secure)
    print("clicked", brick.name, secure)
end)

Bridge.on("heartbeat", function(dt, timestamp)
    -- runs on the hosted heartbeat loop
end)

Outbound methods

Method Description
Bridge.messageAll(message)Broadcast a message to every connected player.
Bridge.messagePlayer(userId, message)Send a message to one player.
Bridge.setPlayerProperty(userId, property, value)Change supported player state like health, speed, position, scale, score, team, and speech.
Bridge.createBrick(descriptor)Create a runtime brick.
Bridge.updateBrick(brickId, changes)Update a runtime brick.
Bridge.removeBrick(brickId)Delete a runtime brick.
Bridge.createTeam(descriptor)Create a team at runtime.
Scheduler

The hosted Luau runtime exposes a first-pass scheduler. In the current host, wait-style operations return awaitable promises.

task.spawn(function()
    print("spawned now")
end)

task.delay(3, function()
    print("three seconds later")
end)

task.wait(1):await()
print("after wait")

wait(2):await()
print("after alias wait")
DataStore & Badges

The bridge reuses BrickBit’s existing manager-side DataStore and badge clients. Async bridge calls return awaitable values from the Luau side.

Bridge.on("playerJoin", function(player)
    local visits = Bridge.datastore.getPlayer(player.userId, "visits"):await() or 0
    visits = visits + 1
    Bridge.datastore.setPlayer(player.userId, "visits", visits):await()

    local awarded = Bridge.badges.award(player.userId, 42):await()
    print("badge award result", awarded)
end)
Example Server Script
Bridge.on("playerJoin", function(player)
    local visits = Bridge.datastore.getPlayer(player.userId, "visits"):await() or 0
    visits = visits + 1
    Bridge.datastore.setPlayer(player.userId, "visits", visits):await()
    Bridge.messagePlayer(player.userId, "Welcome back! Visits: " .. tostring(visits)):await()
end)

Bridge.on("initialSpawn", function(player)
    Bridge.createBrick({
        name = "SpawnMarker",
        position = { x = 0, y = 4, z = 0 },
        scale = { x = 4, y = 1, z = 4 },
        color = "#4a9eff",
        clickable = true,
    }):await()
end)
Migrating Legacy JavaScript

Legacy JavaScript scripts are no longer hosted. They remain visible in the editor so you can migrate them, but the server only logs them as unsupported migration content.

  1. Open the legacy .js script in the script editor.
  2. Use Migrate to Luau to rename it to .luau.
  3. Rewrite Node/JavaScript APIs against Bridge, task, and Luau syntax.
  4. Save and republish your game bundle.

Until a script is migrated, it is not part of the hosted runtime.

Replicated / Client Delivery

The server now writes non-server Luau assets into a stable delivery artifact: runtime/delivery.manifest.json. The manifest groups replicated and client scripts, keeps their order, and records relative paths inside the extracted runtime.

This is intentionally a server-side metadata step only. The native client fetch, ordering, and Luau execution path is still follow-up work and is not implemented in this repo yet.