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

CameraPanic

How the view moves when you are frightened. It rides the player's **CameraRig**, the same entity the engine's first-person controller drives, and runs after it (`executionOrder = 60`) so what it adds sits on top of the eye rather than being overwritten by it.

by◐aiden·posted 1d ago
What it does

game.camera.CameraPanic

How the view moves when you are frightened. It rides the player's CameraRig, the same entity the engine's first-person controller drives, and runs after it (executionOrder = 60) so what it adds sits on top of the eye rather than being overwritten by it.

game.camera.sceneContent attaches it.

Sway

A small natural walk, more when running, more again when a creature is hunting within 24 m (it reads the creatures' live state), unsteady when stamina is low, settling when the player stops. The reduceShake setting scales all of it to a third without turning it off.

The capture

When the creature reaches the player the view drops to the floor and rolls onto its side, then Bus.E.captured raises the blackout, and at 3.9 seconds Bus.E.runEnded hands the run to the interface's GAME OVER card. It fires once per capture and cannot fire again until a new run starts.

Its timing uses its own clock: it originally read the sway clock, which only advances in the branch the capture skips, so the sequence sat on its first frame for ever.

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/camera/CameraPanic.component — how the view moves when you are scared. IT ADDS ON TOP OF THE EYE, it does not replace it. The engine's first-person controller sets the camera's position and rotation early in the frame; this runs after it and offsets what it wrote, so the look controls stay exactly as they are and the sway rides along. Two jobs, and they are the same job at different intensities: SWAY — a small, natural walk; more when running; more again when something is hunting you; unsteady when you are out of breath. It settles when you stand still. `reduceShake` scales all of it down for anyone who needs a steadier picture, without turning it off. THE CAPTURE — when the creature reaches you, the view goes down to the floor as though the thing in your hand was dropped, lies there at an angle, and then the world goes black. Nothing is shown; the sounds are the scene. It fires once per capture and cannot fire again until a new run starts.

quatParts(q: any) → void

`localRotation` answers a table; the Transform helpers hand back four separate numbers. This reads either shape, so a quaternion can be taken apart and put back together without guessing which one arrived.

argtypedescription
qany

playerBody( ) → void

chaseState( ) → void

Is anything hunting, and how close?

settingReduceShake( ) → boolean

currentSpeed(body: any) → number

argtypedescription
bodyany

playerTired(body: any) → boolean

argtypedescription
bodyany

interactTicks( ) → number

How many times E has been pressed, and a way to tell the player they are held — so E fights the grip instead of opening a door or reading a note.

setPlayerGrabbed(held: boolean) → void

argtypedescription
heldboolean

awake( ) → void

onDestroy( ) → void

runGrab(dt: number) → void

THE HOLD. A creature that reaches the player holds them before anything else happens, and the player has a window to fight free. This runs BEFORE the capture sequence, and hands over to it if the window runs out — so there is one capture in this game, with a chance to avoid it, rather than a second sequence bolted alongside.

argtypedescription
dtnumber

runCapture(dt: number, rig: any, base: any, baseQuat: any) → void

argtypedescription
dtnumber
rigany
baseany
baseQuatany

update(dt: ?) → void

argtypedescription
dt?

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.

19+items
◇
component · born here
❒asset
# game.ui.UiDirector The interface, and what its buttons mean. Screens are registered here, so every callback the user triggers lands in this component's `onCallback` — which is why the trees live in `game.ui.Screens` as pure functions and the meaning of a press lives here, next to the state it changes. Attaches to one entity (`ui_director`, placed by `game.ui.sceneContent`). Nothing it does is decorative: Play starts a run, Resume unpauses the engine, Restart resets the player, Endless flips the generator on and moves the player into the arena, and the sliders write the engine's own volume channels and the camera's look sensitivity. ## Screens `menu`, `hud`, `journal`, `pause`, `ending`, `endless`, `blackout`, `gameover` — shown one at a time except for the journal, which overlays the HUD by design. ## Two things learned the hard way **`ui.updateScreen` SHOWS the screen it updates**, so hiding a screen before updating it re-shows it. Visibility is applied last. **The interface's key memory lives in component FIELDS, not module locals.** A module local read as nil inside `update`, the throw disabled the component, and the journal and pause keys were silently dead — while the screens kept rendering from an older compile and looked fine.
▲ 0↑ born
◇
component · born here
❒asset
# 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 | Field | What it does | |---|---| | `kind` | `"resident"` or `"broodmother"`. | | `active` | Whether it is hunting. | | `difficulty` | Which row of `GameRules.DIFFICULTY` it runs on. | | `state` | What it is doing right now — read this to see the AI working. | | `seed` | Its 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.
▲ 0↑ born
◇
component · born here
❒asset
# game.systems.Player Everything the player is and does. Attached to the player's own avatar (the `body` entity inside the player prototype, so every peer gets one). It owns the torch and its battery, sprint and crouch with stamina, health, what is carried, which clues have been read, how far along the objective chain the player is, and what happens when they press E at something. It publishes all of it as fields so the interface can draw it and the creatures can hear it. ## What it does not own The house owns the doors and the hiding places; this reads an `Interactable` marker on them and decides whether the player may pass. The run — objectives, clues, the ending — lives in `game.systems.PlayerState` and in the shared store, so a reload cannot lose it. ## How it touches the engine Two patterns worth keeping, both learned the hard way here: - **Finding what the player can use** goes through the `scene.find` *tool*, never `queryEntitiesFlex`: that function ignores a component filter and answers with every entity in the scene, so "nearest thing in front" becomes a wall. - **Changing a field** is a write onto the component object (`comp.brightness = v`). There is no `component.set`. - **Reach is three-dimensional.** The house is stacked — the living room sits under the attic — so a distance test on x/z alone lets a player take the attic key from the room below. ## Fields `active`, `difficulty`, `health`, `stamina`, `battery`, `torchOn`, `hiding`, `objective`, `prompt`, `carrying`, `clues`, `ending` — all read-only mirrors of the state, for the interface.
▲ 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

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.