Appearance
The scene and visibility sets
You'll learn: how anything gets drawn, and how to hide information from some players. You'll need this when: you create anything visible, or your game has secrets.
Status: Built (headless, and in the plots dev stack, whose page draws plot entities, cuboid and glTF models and mesh terrain): the scene, components, visibility sets, interest management and the binary snapshots. Not in the live world yet.
If others should see it, it's in the scene
The scene is a set of entities with components, replicated to every viewer who's allowed to see them. Nothing replicates unless you write it here.
ts
import { scene } from "@inventery/host";
const torch = scene.create({
Transform: { pos: [10, 65, 4] },
Model: { asset: "models/torch.glb" },
Light: { color: "#ffaa44", intensity: 2, range: 8 },
Emitter: { particles: "inventery:flame", rate: 4 },
});
scene.setComponent(torch, "Light", { color: "#ff4400", intensity: 4, range: 10 }); // replace one component
scene.setComponent(torch, "Emitter", null); // remove one
scene.remove(torch);Components are plain data: Transform, Model, Pose, Material, Light, Emitter, AudioSource, Nametag, Collider, Controller, Velocity, Billboard, Lifetime, Custom. See Components.
One lighting. Everything the world draws is lit by the same world lighting as the blocks around it: your entities, cuboid models, glTF meshes and props, mesh terrain and dropped items get the sky light and block light at their position, the time of day, face shading and fog. A mesh in a dark cave is dark, and a torch lights it. Light components are dynamic lights on top.
Visibility sets
Every entity (and sound) has a set saying who receives it:
| Set | Who sees it |
|---|---|
"public" (default) | everyone: this lobby, and onlookers whose lobby it is (and everyone, if it's the featured lobby) |
"lobby" | the players in this lobby |
{ players: [id, ...] } | just those players |
"serverOnly" | nobody: the server keeps it (a hidden marker your code uses) |
ts
// Among Us: only the impostor sees the vent markers
scene.create({ Transform: { pos: ventPos }, Model: { asset: "models/vent_glow.glb" } },
{ visibility: { players: [impostor] } });
// Horror: the scare is only for its target
audio.play("sfx/whisper.ogg", { at: hallway, to: { players: [target] } });
scene.setVisibility(ghost, { players: [target] });The room filters by set before encoding anything for a viewer. A hacked client can't reveal what it was never sent: this is also your wallhack protection.
One limit: sets hide information, not the place. What someone saw from outside must be what they walk into. Hide the impostor's role, not the building.
Children inherit
ts
const ship = scene.create({ Transform: { pos: [0, 80, 0] }, Model: { asset: "models/ship.glb" } });
const flag = scene.create({ Transform: { pos: [0, 4, 0] }, Model: { asset: "models/flag.glb" } }, { parent: ship });A child's Transform is relative to its parent, and it inherits the parent's visibility.
Shared entities
At plot level, { shared: true } puts an entity in the shared base, seen by every lobby:
ts
// plot level: a leaderboard every lobby and every passer-by sees
scene.create({ Transform: { pos: [16, 70, 0] }, Billboard: { text: "Top: Ana (12 wins)", size: 2 } }, { shared: true });What isn't the scene
| Reaches onlookers? | Use for | |
|---|---|---|
scene | yes (public parts) | anything visible or audible in the world |
ui.* | no: per player | HUDs, scoreboards, menus |
network.send (channels) | no: the lobby's players only | game logic messages |
Custom component | replicated, drawn by no one | data your client code reads (client code is In progress) |
The lint warns when a channel or client code looks like it's carrying visuals.
Rates and detail outside

Players inside get the scene at your tick rate. Onlookers near the plot (about 2 chunks) get it at 10 Hz with simpler poses; far ones at 2 Hz, transforms only. Low-end devices fall back to LODs, impostors, then average colours. Your plot always shows; it just shows simpler.