Hungrit Docs

Triggers and zones#

Reacting to where people are, rather than to what they click.

Which one to use#

EventFires whenGood for
on_regionsomebody enters or leaves a sphere around the objectgreeters, checkpoints, ambience, traps
on_contactsomebody's body touches the objectpressure plates, lava, hazards
on_touchsomebody clicks itdoors, buttons, pickups

on_region does not need the object to be solid, or even visible. on_contact does. It is real physical contact.

A greeter#

Luau
--!strictlocal self = require("self") self:on_region({    radius = 6,    near = function(p)        p:show_hud({            id = "welcome",            anchor = "top",            pages = { main = {                { "text", "Welcome, " .. p.name, size = 18, align = "center" },            } },        })    end,    far = function(p)        p:hide_hud("welcome")    end,})

Both are edges: each fires once per crossing, never repeatedly while somebody stands there.

Counting who is inside#

Luau
--!strictlocal self = require("self") local inside = 0 self:on_region({    radius = 8,     near = function()        inside += 1        if inside == 1 then            self:sound("hum", { volume = 0.3, fade = 1.0 })        end    end,     far = function()        inside -= 1        if inside <= 0 then            inside = 0            self:stop_sound()        end    end,})

Clamp at zero. A player who disconnects inside still gets their far, so every near gets its pair, and you would rather be safe than negative.

The sphere follows the object#

A moving platform brings its trigger with it, at no extra cost:

Luau
self:on_region({ radius = 3, near = function(p) ... end })self:tween({ to = far_side, seconds = 10 })

A pressure plate#

Luau
--!strictlocal self = require("self")local events = require("events") local on = 0 self:on_contact(function()    on += 1    if on == 1 then        self:set({ color = "#55e38b", emissive = 1 })        events:emit("plate", { down = true })    endend) self:on_contact_end(function()    on -= 1    if on <= 0 then        on = 0        self:set({ color = "#3a3a3a", emissive = 0 })        events:emit("plate", { down = false })    endend)

on_contact_end also fires when somebody leaves the world while standing on it, so the plate cannot get stuck down.

A hazard#

Luau
--!strictlocal self = require("self")local events = require("events") local burning = {} self:on_contact(function(p)    if burning[p.id] then return end    burning[p.id] = true     local function tick()        if not burning[p.id] then return end        events:emit("combat:hit", { target = p.id, amount = 8 })        self:after(0.5, tick)    end     tick()end) self:on_contact_end(function(p)    burning[p.id] = nilend)

The damage repeats on a chain of one-shot timers rather than a loop, so each slice stays short.

A checkpoint#

Luau
--!strictlocal self = require("self") self:on_region({    radius = 4,    near = function(p)        local here = self:position()        self.store:set("spawn." .. p.id,            here.x .. "," .. here.y .. "," .. here.z)         p:show_hud({            id = "checkpoint",            anchor = "top",            pages = { main = { { "text", "Checkpoint reached", align = "center" } } },        })         self:after(2, function()            p:hide_hud("checkpoint")        end)    end,})

Key by player id, never by name.

Store the three numbers with a separator you can split on later. tostring on a point gives you something readable but not parseable back.

Asking who is nearby, instead of waiting#

Sometimes you want the list, not an event:

Luau
local players = require("players")local events = require("events") self:on_timer(2, function()    local crowd = players:nearby(20)    if #crowd >= 5 then        events:emit("crowd", { n = #crowd })    endend)

nearby measures from the object this script is in, and reading it is free.

Ranges and behaviour#

radius0.5 to 96 m
leavingtakes half a metre more than entering, so nobody on the line flickers
calling on_region againreplaces the volume and re-announces whoever is inside
radius = 0 or omittedremoves the volume

See also#

Updated 04 September 2026