Hungrit Docs

world.build#

Building pieces: walls, floors, beams and roofs that players raise themselves. They snap to each other, they hold each other up, and they come down when what was under them is taken away.

Use it to

  • turn objects you built into pieces players can raise: walls, floors, roofs
  • decide who may build, and how many pieces each
  • know what holds a piece up, and hear when one collapses
Luau
local world = require("world") world.build:define("wall",  { from = "WoodWall",  kind = "wall",  material = "wood" })world.build:define("floor", { from = "WoodFloor", kind = "floor", material = "wood" })world.build:allow(player_id, { wall = -1, floor = -1 })

Those three lines are a working building set. The rest of this page is what each word does.


A piece is an object you already built#

There is no piece file and no importer. You build the wall with the ordinary editor and then name it:

Luau
world.build:define("wall", { from = "WoodWall", kind = "wall" })

from is the object's display name. The region takes a snapshot of that object's whole subtree, meaning its parts, its properties, its contents and its scripts, and the definition owns a copy from then on, so editing the original later does not silently rewrite every wall anybody built.

What you see is what gets raised. The piece is remembered in the pose you left the prototype in. If you made your wall by standing a slab on its edge, every wall raised from it stands the same way. Where the prototype is parked makes no difference.

Keep prototypes out of the way, or delete them once the definition exists. The catalogue is saved with the world and outlives them.

Tip

The behaviour travels. A door that opens, a chest that holds, a workbench that crafts: whatever scripts are on the prototype are re-attached to every copy that gets built, with the builder as their creator. It is their wall and their code.


Where a piece snaps#

Every piece offers sockets, points on its own body where a neighbour can arrive. You do not author them; they are read off the shape.

The piece isIt gets
flat (a wall, a floor, a roof panel)eight around the rim of its flat face, being four edge midpoints and four corners, plus five on each large face: the centre and the four rim midpoints
long (a beam, a pillar, a post)one on each end, plus four around its waist so a floor can land halfway up
anything else (a crate, a workbench)one per face

Two pieces join when a socket of one lands on a socket of the other. No grid and no cell size is involved, so pieces of different sizes work together.

The rim sockets on a flat face are what let a wall stand on the edge of a floor and not only in the middle of it.


What holds a piece up#

Every standing piece carries a support from 1 (on the ground) down to 0 (nothing holding it). It is computed from the joints: a piece on the ground has full support, and every joint crossed from there loses some.

Sideways costs more than upward. That one asymmetry is the whole mechanic: a stone tower goes up comfortably, a wooden walkway sags after a few spans and needs a pillar.

materialupout
"straw"4 pieces2
"wood" (default)85
"stone"168
"iron"3212

When support reaches zero the piece comes down, and so does whatever it was holding. Nobody can raise a piece that would fall immediately. The placement is refused with nothing would hold that up.


define#

world.build:define(name, opts) → true, or nil, reason

Defines or replaces one piece.

OptionMeaning
fromdisplay name of the object to snapshot. Required the first time; leave it out afterwards to change numbers without re-snapshotting the geometry
kind"wall", "floor", "roof", "beam" and so on. What shape rules it follows
material"straw", "wood" (default), "stone", "iron". How far it carries
labelwhat the player sees in their build bar
healthhow much damage it takes to destroy
vertical_losssupport lost crossing one joint straight up. Overrides what the material says
horizontal_losssupport lost crossing one joint sideways. Overrides what the material says
min_supportthe piece comes down below this instead of at zero

The last three are the dials behind material. Name a material and leave them alone unless a piece has to carry further, or less far, than its material does.

forget#

world.build:forget(name) → true, or nil, reason

Removes a piece from the catalogue.

What people already built keeps standing, because those are ordinary objects, but it stops taking part in the structure, so anything that was only being held up by it comes down.

list#

world.build:list() → list

Every piece this world defines, sorted by name. Each entry has name, label, kind and health.

Always a list. A world with no pieces answers an empty one. Never fails: the catalogue is public, the same way the block palette is.

allow#

world.build:allow(player, counts) → true, or nil, reason

Opens somebody's build bar and says how many of each piece they may raise. This is the verb that turns building on for a player.

Luau
world.build:allow(id, { wall = 10, floor = 4, roof = 0 })world.build:allow(id, { wall = -1 })   -- as many as they likeworld.build:allow(id, {})              -- closes the bar
CountThe player sees
-1the piece, with no number
nthe piece, with n left
0the piece, greyed out. How somebody learns a piece exists before they can afford it
absentnothing at all; the piece is not in their bar

Careful

An allowance is a count, never a recipe. The engine does not know what wood is, what a wall costs, or whether the player is holding a hammer. Those are your game's questions, and every game answers them differently.

What the engine does is show the number and refuse the eleventh wall without a round trip. You decide when to hand out more:

Luau
events:listen("world.build", function(e)    local left = spend(e.player_uuid, e.piece)    world.build:allow(e.player_uuid, left)end)

place#

world.build:place(name, opts) → true, or nil, reason

Raises a piece from a script: a starter shelter at spawn, a quest structure, a ruin the world begins with.

Luau
world.build:place("wall", { pos = { x = 4, y = 0, z = -2 }, rot = { x = 0, y = 90, z = 0 } })

The structural rules still apply. A script cannot hang a wall in mid-air either: the support solve would knock it down on the same tick, so refusing it now is the honest version of what was going to happen anyway.

If you want to put something anywhere at all, you want world:spawn.

remove#

world.build:remove(id) → true, or nil, reason

Takes a standing piece down, with whatever it was holding up.

support#

world.build:support(id) → support, band

What is holding that piece up (0 to 1), and the band the game paints it with.

BandSupportReads as
0≥ 0.75solid
1≥ 0.5fine
2≥ 0.25strained
3< 0.25about to go

Never fails: an object that is not a standing piece answers 0, 3, which is true of a rock.

The band travels so that your own HUD and the built-in support view can never disagree about what a colour means, because they read the same function.


Events#

Two channels report what the structure is doing. Listen with events:listen.

world.build#

Somebody raised a piece.

Luau
events:listen("world.build", function(e)    print(e.player_uuid .. " raised a " .. e.piece)end)

world.collapse#

A piece came down because it lost its support. Different from world.destroyed, which is about damage.

See also#

Updated 17 October 2026