Hungrit Docs

Talking between scripts#

Three ways for scripts to reach each other, and when each is right.

WayReachesGood for
events:emit / listenyour own scriptsa switch and its door
events:send / openanyone who opted inyour HUD and somebody else's shop
objectsone object you can addresspainting every lamp

Your own build talking to itself#

The sender:

Luau
--!strictlocal self = require("self")local events = require("events") self:on_touch(function(player)    events:emit("alarm", { by = player.id })end)

Every listener:

Luau
--!strictlocal self = require("self")local events = require("events") events:listen("alarm", function(data)    self:set({ color = "#e35d6a", emissive = 3 })    self:after(5, function()        self:set({ color = "#3a3a3a", emissive = 0 })    end)end)

One button, twenty lamps, no list of ids anywhere. Adding a lamp is copying the listener onto it.

emit is private to you. Another creator's scripts never hear it, even if they guess the channel name.

Two scripts on the same object#

They do not share variables, but they hear the same events:

Luau
-- main.luauevents:emit("state", { open = true }) -- lock.luauevents:listen("state", function(data)    -- ...end)

emit reaches every script of the same owner including the one that sent it, so a script can listen to its own channel. That is occasionally what you want and occasionally a loop. See below.

Crossing owners#

Your personal HUD is yours; the shop is somebody else's. emit cannot reach across, and that is deliberate.

The receiver opens a door:

Luau
events:open("acme.shop", function(data, from)    if from.kind ~= "hud" then return end    serve(from.owner, data)end)

The sender knocks:

Luau
events:send("acme.shop", { want = "rope" })

open is the receiver's consent. Nothing can push a message into a script that never asked for one.

The from table is stamped by the region and is the only part you can trust:

Field
kind"object", "hud" or "attachment"
ownerthe account that owns the sending script
objectthe sending object's id, or nil from a HUD

Careful

Channel names are global to the region. Two creators who both pick "shop" are on the same channel. Prefix yours: "acme.shop", "mira.lift".

Reaching a specific object#

When you know which object, objects is more direct than a broadcast:

Luau
local objects = require("objects") local lamps = objects:tagged("streetlight")if lamps then    for _, lamp in ipairs(lamps) do        lamp:set({ light = true })    endend

Tags beat names: a name is what a person reads and may rename; a tag is what a script means.

Tip

You cannot read another object's state, only act on it. Tags are the way round it: an object's own script controls its tags, so a tag like "door.open" is the public half of an object that anyone may check with has_tag.

Choosing: event or tag?#

Eventsomething happened. A moment
Tagsomething is true. A state

A door that just opened emits; a door that is open carries a tag. Somebody arriving later missed the event but can still read the tag.

What can travel#

Nothing, a boolean, a number, a string, or or a table with string keys, 3 levels deep, 32 entries, 512-byte strings. Anything else is refused with a reason rather than trimmed.

Values arrive as what they were; unlike self.store, you do not convert.

Always check the shape you were given:

Luau
events:listen("alarm", function(data)    if type(data) ~= "table" then return end    local who = tostring(data.by or "")    -- ...end)

Loops#

If A emits to B, B emits to C, and C emits back to A, you have built a loop. The region cuts it at 64 deliveries rather than letting it run.

If a message mysteriously stops arriving, a loop is the first thing to check. The usual fix is a guard:

Luau
local settling = false events:listen("state", function(data)    if settling then return end    settling = true    -- ... change things, which may emit ...    settling = falseend)

Ceilings#

Sends per event (emit + send)16
Cascade cut at64 deliveries
Channel name1 to 64 characters

Registering the same channel twice replaces the handler. A script has one handler per channel, not a list.

Built-in channels#

The world reports on its own channels; listen with events:listen:

Channel
world.destroyedsomething with health was destroyed
world.collapsea building piece lost its support and came down
world.blocka block was placed or broken
world.builda building piece was raised

See also#

Updated 04 September 2026