Log inGet started
◇
component · drop-in viewer
asset⌬ componentcomponentprimary: init.luau·originates fromworld e339ab22-c…

Creature

One creature, two kinds — the engine's half of a monster. The brain decides; this does everything that needs a world: builds the body, sights the player, asks physics for line of sight, walks the route the nav graph gives it, and says what happened on the bus.

by◐aiden·posted 1d ago
What it does

game.monsters.Creature

One creature, two kinds — the engine's half of a monster. The brain decides; this does everything that needs a world: builds the body, sights the player, asks physics for line of sight, walks the route the nav graph gives it, and says what happened on the bus.

kind picks which: resident — two and a half metres, thin, long-armed, walks the main hallway and the ground floor; broodmother — the spider, wider sight arc, hears further, and brings the baby spiders.

Fields

FieldWhat it does
kind"resident" or "broodmother".
activeWhether it is hunting.
difficultyWhich row of GameRules.DIFFICULTY it runs on.
stateWhat it is doing right now — read this to see the AI working.
seedIts own randomness, so two creatures do not move as one.

How it moves

Along a route of waypoints — room, doorway, room — turning to face where it is going and stepping toward the next point. It carries no collider and physics does not push it, so it cannot be shoved into a wall or wedged on a chair; the route goes through doorways by construction. If a route cannot be found it walks straight at its goal rather than freezing.

The baby spiders

The broodmother's strike begins a swarm: tiny spiders on the player's own view, which ride the camera so they are on the player's hands wherever they look. Each counted press of E visibly removes one. The first swarm of a session runs in slow motion with the prompts; later ones do not. It emits spidersStarted, spidersProgress, spidersCleared and damage — the interface draws the prompt, and the systems slice applies the damage.

Every state change is announced on Bus.E.monsterState, so the audio director can hear a creature the player cannot see.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

game/monsters/Creature.component — one creature, two kinds. THE ENGINE'S HALF OF A MONSTER. The brain (MonsterBrain) decides; this does everything that needs a world: builds the body, sights the player, asks the physics world for line of sight, walks the route the nav graph gives it, and says what happened on the bus. `kind` picks which creature: "resident" — tall, thin, walks the upstairs corridor and the ground floor; "broodmother" — the spider, wider sight arc, hears further, and brings the baby spiders. IT NEVER KNOWS WHERE THE PLAYER IS. Everything it acts on is something it saw or heard, and MonsterBrain keeps that distinction. HOW IT MOVES. Along a route of waypoints from the nav graph — room, doorway, room — turning to face where it is going and stepping toward the next point. It carries no collider and is not pushed by physics, so it cannot be shoved into a wall or stuck on a chair; the route is through doorways by construction. What it is NOT yet: the Broodmother does not climb walls or ceilings, and there is no animation beyond the body turning and stepping.

Model

rand( ) → number

Deterministic per creature, so a seeded session plays the same way twice.

difficultyRow( ) → void

part(name: ?, position: ?, size: ?, material: ?) → void

The body. Primitives, at the sizes the two creatures are: these are SLOTS for generated models, blocked out so the creature is real — it stands, it turns, it moves, it has a silhouette you can see coming.

argtypedescription
name?
position?
size?
material?

buildResident( ) → void

buildBroodmother( ) → void

findPlayer( ) → void

Where the player is, if there is one.

setRoute(goal: ?) → void

Walking the route.

argtypedescription
goal?

followRoute(speed: ?, dt: ?) → void

argtypedescription
speed?
dt?

clearSwarmVisuals( ) → void

The baby spiders. The Broodmother's signature: a swarm on the player's own view that has to be brushed off by hand.

drawSwarm( ) → void

brushOne( ) → void

Brushing one off: the spider that is on the hand goes.

beginSwarm( ) → void

endSwarm(succeeded: ?) → void

argtypedescription
succeeded?

awake( ) → void

update(dt: ?) → void

argtypedescription
dt?

onDestroy( ) → void

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

Showing up to 3 levels deep. Open a part to see what it holds further down.

33+items
▣
module · born here
❒asset
# game.monsters.Swarm The baby spiders, as rules. No entities and no input — the event's arithmetic, on its own. **The first one teaches.** Every later swarm is a scramble; the first runs the world at a fifth speed, gives twice the time and hurts a quarter as much, because a player who has never been told which key to press must not die learning it. ```lua local state = Swarm.new(now, tutorial) Swarm.press(state) -- one press of E; true when it counted Swarm.tick(state, dt) -- real seconds -> "ongoing" | "cleared" | "failed" Swarm.damagePerSecond(state) Swarm.prompt(state), Swarm.counter(state), Swarm.spidersLeft(state) ``` The clock runs on **real** seconds, so a slow-motion swarm is never given more wall-clock time than a normal one — the slowdown exists to give the player time to read, not to give the swarm time to bite. Numbers come from `GameRules.SPIDERS`: five presses, six seconds, the prompts, the cooldown, the damage.
▲ 0↑ born
◐
material · born here
❒asset
▲ 0↑ born
◐
material · born here
❒asset
▲ 0↑ born
▣
module · born here
❒asset
# game.Bus The one table the game's parts talk over. **Every slice announces what happened and listens for what it cares about; no slice requires another**, and this is the table in the middle they share. ```lua local Bus = require("game.Bus") Bus.emit(Bus.E.noise, { id = "sprint", position = p, source = "player" }) local handle = Bus.on(Bus.E.playerCaught, function(payload) print(payload.monster) -- "resident" end) Bus.off(Bus.E.playerCaught, handle) ``` `Bus.E` is the event-name list, spelled once so no slice can invent a string nobody else listens for. It is the same set as `GameRules.EVENTS`, which also documents the payload each event carries; the scene entrypoint checks the two agree on every load and warns if they have drifted. `on`, `once`, `off`, `emit`, `count`, `clear`, plus `error()` and `clearError()` for the last handler failure. ## Two rules, because getting them wrong desynchronises a co-op run 1. **The bus is local.** It is a module, and a module is one instance *per peer*. An emit reaches the parts of the game running on this machine and nowhere else. Anything another player must agree about — a door, a key, the objective list, the monster — is written to the **shared store** (`runtime_data.world`, under the keys in `GameRules.DATA`) and read back by every peer. Emit the local *response* to a thing; store the *fact* of it. A part that emits `doorOpened` and never writes the store has a door that opens for one player and stays shut for everyone else. 2. **An emit is synchronous.** Handlers run before `emit` returns, in subscription order, on the frame the thing happened. The payload table is handed out, not copied — read it, do not keep it, do not mutate it. A handler that throws is caught and reported, so one broken listener cannot silence every other listener on the same event; `Bus.error()` reads the last one back. Who calls it: every slice. The house emits doors and pickups, the monsters emit their state and a sighting, the survival systems emit noise, damage and clues, the interface listens to most of it, and the audio director listens to nearly all of it.
▲ 0↑ born
▣
module · born here
❒asset
# game.monsters.MonsterBrain What a creature decides, frame by frame. **Policy only** — it reads what the world told it and writes a destination. It never touches an entity, a path or a raycast; the `Creature` component does the engine's half and hands the answers in. The states are the game: `patrol`, `investigate`, `chase`, `search`, `attack`, `recover`. On every difficulty a creature runs exactly this logic — difficulty moves only how far it sees, how far it hears and how long it looks before giving up. **It never knows where the player is.** It knows where the player *was* — a sighting, or a sound it heard. That is the difference between a hunter and a cheat. ```lua local agent = Brain.new("resident", position) Brain.hear(agent, senses, "sprint", noisePosition) -- true when it heard it local state = Brain.tick(agent, senses, dt, ctx) -- ctx carries what the component saw Brain.speedFor(agent, senses) ``` `ctx` is the component's half: `playerPosition`, `canSee` (physics line of sight), `playerHidden`, `angleToPlayer`, `arrived`, `difficulty`, `rand`. `agent.pending` comes back with what happened this frame (`spotted`, `attack`, `lostSight`, `gaveUp`).
▲ 0↑ born
▣
module · born here
❒asset
# game.monsters.NavGraph How a creature finds its way through the house. **The graph is the house.** Nodes are the twelve areas and the doorways between them; edges are the doorways and the stairways. So a creature routes the way a person does — room, doorway, room — and it uses the same doors the player uses. A doorway is a **node**, not just an edge, so a creature walks *to* the door and then *through* it rather than straight at a wall corner. Why not a voxel grid: a grid over a two-storey house is thousands of nodes built from raycasts, and it would have to be rebuilt whenever a door moved. The room graph is about thirty nodes, comes free from the plan the house is already built from, and **cannot disagree with the geometry, because it is that plan**. ```lua local NavGraph = require("game.monsters.NavGraph") local points, status = NavGraph.route(from, to) -- plain world points, first to last local spot = NavGraph.randomRoom(rand) -- somewhere to wander to local rooms = NavGraph.roomsNear(point, 4) -- the rooms a searcher checks first ```
▲ 0↑ born
◐
material · born here
❒asset
▲ 0↑ born
▣
module · born here
❒asset
# game.GameRules The constants and rules of **The House That Knows You** — the one module every part of the game reads, so two systems written in different sessions agree on what a room is called, how loud a sprint is, how long a torch battery lasts and which ending the player earned. It holds **no behaviour and no entities**: pure data plus a handful of pure functions. Require it and read it; never write to it. ```lua local RULES = require("game.GameRules") ``` ## What is in it - **`ART_DIRECTION`** — the one sentence every generation prompt reuses word for word, and **`REFERENCES`** — the pictures the game is judged against. - **`PALETTE`** — that sentence as numbers, for the interface and for materials. - **`HOUSE`** — the wall height, the wall thickness, the doorway size, the room module, the storey height and the player's own dimensions. Every prop in the game is sized against these. - **`AREAS`** / **`AREA_BY_ID`** — the twelve areas, each with its floor, its nominal centre on the ground plan and the item that unlocks it. - **`OBJECTIVES`** — the twelve-step chain, in order, each naming the area it happens in and the item it needs. - **`ITEMS`**, **`REQUIRED_CLUES`**, **`CLUE_COUNT_FOR_TRUTH`** — what can be picked up, and what the ending is decided on. - **`ENDINGS`** and **`selectEnding(cluesFound, secretRoomOpened)`** — the three endings and the rule that picks one, stated once so the interface and the systems cannot disagree. - **`SURVIVAL`** — speeds, stamina, health, torch battery, interaction ranges. - **`DIFFICULTY`** — easy, normal, nightmare. These change the monster's persistence, reach and the supply density **only**; all three run the same monster logic. - **`MONSTERS`** and **`MONSTER_STATES`** — THE RESIDENT and THE BROODMOTHER, and the states both run: patrol, investigate, chase, search, attack, recover. - **`NOISE`** — the interface between what a player *does* and what a monster *hears*. A system emits a noise id; the monster AI turns it into a reach. Nothing else may write a raw radius. - **`SPIDERS`** — the baby-spider event: five presses, six seconds, the slow-motion tutorial, the prompts, the damage. - **`ENDLESS`** / **`endlessDifficultyFor(floor)`** — Endless Nightmare, and a floor number that never stops climbing. - **`MODES`**, **`MAX_PLAYERS`**, **`DATA`** — the game modes and the keys shared state lives under. ## Who calls it Every slice: the house builder, both monsters, the survival systems, the interface and the audio director. Every component that runs in play reads its numbers from here rather than carrying its own copy.
▲ 0↑ born
backing path · game/monsters/Creature.component

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported on this asset or on the parts this page shows. Parts it leaves out are not counted here.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.