Phaser AE

Horror director

Pro packv3.0.0-0ArcadeNew

The rules of a first-person horror game where you walk slowly, peer round with a torch, and the scares land when the tension has built. It runs beside your own rules and tells your presenter what to draw and your audio what to play.

This is a Pro pack. Upgrade to Phaser Pro to use it in your games.See Phaser Pro →

Released October 25, 2026

Horror director: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

The pack

horrorDirector

function horrorDirector(): Pack<{ horrorDirector: typeof kit; }>

Compose the horror director, its world adapter for sector maps, the scare library, two presets and their maps under game.horrorDirector.

Helpers

createHorrorDirector

function createHorrorDirector(config: HorrorConfig, world: HorrorWorld): HorrorDirector

Start a night: the config (a preset such as nightShift(), or your own) and the world it plays on (sectorHorrorWorld(map), or any HorrorWorld). Throws, naming the field, on a config it cannot use.

cryptMap

function cryptMap(): SectorMapData

The Crypt Vigil crypt, about 30 by 54 metres: a long nave with four alcoves a side, a passage down to the crypt with its altar and coffin, a chapel with a bell behind an open gate, an ossuary behind another gate with a grate looking into an alcove, and the porch where the vigil starts. Candles (lights of kind 'torch') are tagged one by one. Spots: start, tomb, coffin (a fixture), bell, niche, grate, oil.

cryptVigil

function cryptVigil(overrides: HorrorConfig = {}): HorrorConfig

Crypt Vigil: a night kept in a crypt by lantern light. No stalker and no running: an oil lantern that lights all round but not far, and gutters as the oil runs low; candles that are snuffed and flare again; shades at the edge of the light, a face behind a grate, a procession crossing the nave, gates slamming, bare feet behind, prayers whispered, bones falling from niches, a bell tolling, a coffin lid sliding. Fear is the danger: left in the dark with no light it climbs, and ten seconds at its height loses the night. Survive seven minutes to dawn. Plays on cryptMap().

nightShift

function nightShift(overrides: HorrorConfig = {}): HorrorConfig

Night Shift: an abandoned hospital at night. A slow walk with a short sprint, a torch on batteries that die (spares to find), hiding in lockers, under desks and beds, leaning round corners, no weapons, the stalker (it hunts by sound and sight, flees the torch's beam and will not follow into bright lamplight), the whole scare library, and three fuses to find before the stairs light up and the night can be escaped. Plays on nightShiftMap(). overrides lay over it field by field (nightShift({ seed: 7, stalker: { light: 'freeze' } })); lists and null replace.

nightShiftMap

function nightShiftMap(): SectorMapData

The Night Shift hospital floor, about 46 by 24 metres: a long corridor with a wing at each end, two wards with beds to hide under, an office with desks, a radio and a window onto the corridor, the stairs out (dark until the fuses are found), a washroom with three stalls and a mirror, the nurses' station with its phone, a storeroom with lockers and shelves, and the morgue, where the stalker sleeps. Doors stay where they are put (wait: 0); two start open. Spots: start, bed, desk, locker (hiding), stall, cabinet (fixtures), mirror, window, phone, radio, shelf, battery, fuse, exit, lair and patrol. Lamps are tagged by room, the corridor's one by one.

prepareHorrorMap

function prepareHorrorMap(data: SectorMapData): SectorMapData

A copy of a sector map's data with the triggers the director works it by: for every lamp tag, one switching it on and one off, and for every door, one opening and one closing it. They are switched off (disabled), so nothing in the map sets them off; sectorHorrorWorld fires them by id. Preparing a map twice changes nothing more.

scareLibrary

function scareLibrary(): ScareDef[]

The full scare library, one of each kind and two apparitions (at corridor ends, and behind window spots): lights failing, an apparition, a figure at a window, a runner, a door slam, footsteps, a whisper, a falling object, breathing, a phone, a distortion pulse, a stall opening by itself and a mirror figure. Each takes its kind's defaults; tune or replace any of them.

sectorHorrorWorld

function sectorHorrorWorld(map: SectorMap, options: SectorWorldOptions = {}): SectorHorrorWorld

The HorrorWorld of a sector map: its enemyWorld() for sight, moves, routes and hearing, its lights as lamps, its door sectors as doors, and its things as spots (each thing's type its kind). The map must be built from prepareHorrorMap data for lamps to switch and doors to slam; otherwise those throw, naming the missing trigger. Light at a point is the sector's light (times ambient) plus each lit lamp that sees the point, falling off to its radius.

Classes

HorrorDirector

class HorrorDirector

The director of a horror night, run beside the game's own rules. Each step it reads where the player is and what they pressed, and the world through its HorrorWorld; it runs the torch, the player's stamina, fear, hiding and leaning, the stalker, the scares going on and the pacing (tension, phases and a scare budget that rations the next scare), and answers with events for the presenter and the sound. Seeded and deterministic: the same seed and the same player path give the same night. Time moves only through step. Get one from createHorrorDirector.

  • constructor(config: HorrorConfig, world: HorrorWorld)
  • get config(): HorrorConfig — The config it was made with (a copy).
  • get time(): number — Seconds the night has run.
  • get status(): HorrorStatus — 'playing', or how the night ended: 'escaped', 'dawn' or 'dead'.
  • get phase(): HorrorPhase — The pacing's phase.
  • get tension(): number — Tension, 0 to 1.
  • get target(): number — The tension it heads for now, 0 to 1.
  • get budget(): number — Scare budget points left.
  • get landed(): number — Scares landed so far (forced ones included).
  • get collected(): number — Things on the night's list collected.
  • get distortion(): number — The screen distortion now, 0 to 1: drive a warp, a chromatic split or static by it.
  • get light(): number — The light (lamps and room, without the torch) where the player stands, 0 to 1.
  • spots(): HorrorSpot[] — The spots the director read from the world (copies).
  • get torch(): TorchView — The torch, for the presenter's light and the HUD.
  • get player(): PlayerView — The player, for the camera, the HUD and the sound.
  • get stalker(): StalkerView | null — The stalker, or null when the night has none.
  • figures(): FigureView[] — The figures to draw now: apparitions, runners, mirror figures.
  • fixtures(): FixtureView[] — The fixtures and how far open each is.
  • pickups(): PickupView[] — The pickups still to be taken: refills for the light and things on the night's list.
  • active(): ScareView[] — The scares going on.
  • beam(x: number, z: number, y: number): number — How brightly the torch lights a point at height y, 0 to 1 (0 outside its beam or behind a wall).
  • step(dt: number, input: HorrorInput): HorrorEvent[] — Run the night on by dt seconds (0 to 1) with the player's doings, and return what happened. Throws on a dt out of range or an input without a finite x, z and yaw. Once the night has ended it returns nothing.
  • scare(id: string): HorrorEvent[] — Land a scare now by its def's id, as a script or a map trigger would: no budget is spent and the phase and conditions are not asked, but it still needs somewhere to go. Returns the events it made (its scare event carries the new scare's id), or none when it found nowhere, the night is over or no step has placed the player. Throws on an unknown id.
  • noise(x: number, z: number, radius: number): void — Tell the stalker of a noise the game made between steps, heard radius units away (0 to 200).
  • get state(): HorrorState — A copy of the state: everything a save needs, with the world's own (a sector map's state).
  • restore(state: HorrorState): void — Put back a saved state of this night. Throws on one that does not fit.

Types

ActiveScare

interface ActiveScare

A scare in play, as saved.

  • id: string — Its id, <def>-<n>.
  • scare: string — The def's id.
  • kind: ScareKind — Its kind.
  • x: number — Where it is, world units.
  • y: number — Height.
  • z: number — Where it is, world units.
  • yaw: number — The engine's yaw it faces.
  • vx: number — Velocity (a runner), units a second.
  • vz: number — Velocity (a runner), units a second.
  • age: number — Seconds since it began.
  • life: number — Seconds it lasts at most; 0 until it is done.
  • target: string — What it works on: a lamp tag, a door or fixture id, a spot id; '' for none.
  • count: number — Steps or flickers left.
  • next: number — Seconds to the next step or flicker.
  • stage: string — Where it is in its course: 'live', 'out', 'flicker', 'falling'.
  • look: number — Seconds the player has looked straight at it.
  • yaw0: number — The player's yaw when it began.
  • from: number — A fall's top height; footsteps' distance behind.
  • to: number — A fall's floor height.
  • on: boolean — A flickering lamp is lit now.

BudgetDef

interface BudgetDef

The scare budget: points that refill over time and that each scare spends, so scares are rationed.

  • start?: number — Points at the start, 0 to 100; default 1.
  • max?: number — Most points held, 0 to 100; default 4.
  • rate?: number — Points regained a second, 0 to 10; default 0.04 (one every 25 seconds).

CatchDef

interface CatchDef

What a catch does.

  • damage?: number — Health a catch takes; default 1 (with the player's default health, the night is lost).
  • retreat?: [number, number] — Seconds it keeps away after a catch the player survives, [min, max] from 0 to 600; default [10, 16].

FigureView

interface FigureView

A figure to draw: an apparition, a runner, a mirror figure.

  • id: string — The scare's id; the scare-end event with it removes the figure.
  • scare: string — The scare def's id.
  • kind: ScareKind — Its kind.
  • show: string — What to draw.
  • x: number — Position, world units.
  • y: number — Feet height.
  • z: number — Position, world units.
  • yaw: number — The engine's yaw it faces (the player).
  • height: number — Height in units.
  • mirror: string | null — A mirror figure: the mirror spot to draw it in (only its reflection shows), else null.

FixtureSounds

interface FixtureSounds

Sounds fixtures make, by name; '' for none.

  • open?: string — Opening; default 'creak'.
  • shut?: string — Shutting; default 'latch'.
  • slam?: string — Slammed; default 'slam'.

FixtureState

interface FixtureState

A fixture, as saved.

  • id: string — Its spot's id.
  • open: number — How far open, 0 to 1.
  • target: number — Where it swings to, 0 or 1.

FixtureView

interface FixtureView

A fixture: a stall door, a cabinet, a locker, anything that opens.

  • id: string — Its spot's id.
  • kind: string — Its spot's kind.
  • x: number — Position, world units.
  • z: number — Position, world units.
  • yaw: number — The engine's yaw it faces.
  • open: number — How far open, 0 (shut) to 1 (open): swing its door by it.
  • opening: boolean — Opening (true) or shutting (false).
  • occupied: boolean — The player hides in it now.

HideDef

interface HideDef

Hiding spots: any spot kinds the player can get into, where the stalker cannot see them.

  • kinds?: string[] — Spot kinds that hide the player ('locker', 'desk', 'bed'); default those three. Empty for none.
  • time?: number — Seconds getting in or out takes, 0 to 10; default 0.6.
  • exit?: number — Units in front of the spot the player comes out, 0 to 5; default 0.9.
  • peek?: number — Units within which the stalker sees a player peeking out, 0 to 50; default 3. 0: peeking is safe.
  • noise?: number — How far getting in or out is heard, units, 0 to 100; default 2.

HorrorBody

interface HorrorBody

The body the world moves: its size and how it climbs.

  • radius: number — Radius in world units.
  • height: number — Height in world units.
  • step: number — Highest step up, and deepest step down, it takes.
  • fly: boolean — Whether it flies over steps and drops.

HorrorConfig

interface HorrorConfig

Everything a night is. Every field has a default; nightShift() and cryptVigil() fill them in two ways.

  • seed?: number — Seed, 0 to 4294967295; default 1. A seed and the player's path give the same night.
  • view?: ViewDef — The camera, for in and out of view.
  • pacing?: PacingDef — Phases, tension and the scare budget.
  • light?: LightDef — The player's light.
  • player?: PlayerDef — The player.
  • scares?: ScareDef[] — The scare library the director draws on; default scareLibrary(). Empty for none.
  • stalker?: StalkerDef | null — The stalker; null (the default) for none.
  • night?: NightDef — What the player must do.
  • fixtures?: string[] — Spot kinds that open and shut, by the player's hand or a scare's; default ['stall', 'cabinet', 'locker'].
  • fixtureSpeed?: number — Units a second a fixture swings, as a share of fully open, 0.1 to 50; default 1.5.
  • fixtureSounds?: FixtureSounds — Fixture sounds.
  • dim?: number — Light (lamps and sectors) at or above which a figure is not placed, and goes, 0 to 1; default 0.35.
  • dark?: number — Ambient light below which the player counts as in the dark, 0 to 1; default 0.25.

HorrorDoor

interface HorrorDoor

A door the director may slam, and whether it is shut.

  • id: string — The world's id for it (a sector map's door sector id).
  • tag: string | null — Its group name, or null.
  • x: number — Its middle, in world units.
  • z: number — Its middle, in world units.
  • shut: boolean — Shut, or not open enough to see through.

HorrorEvent

type HorrorEvent = | { type: 'phase'; phase: HorrorPhase; from: HorrorPhase } | { type: 'scare'; id: string; scare: string; kind: ScareKind; show: string; sound: string; x: number; y: number; z: number; duration: number; target: string } | { type: 'scare-end'; id: string; scare: string; kind: ScareKind; why: ScareEnd } | { type: 'sound'; sound: string; x: number; y: number; z: number; volume: number; source: HorrorSoundSource; id: string; loop: number } | { type: 'lamp'; tag: string; on: boolean; spark: boolean } | { type: 'sparks'; x: number; y: number; z: number; count: number } | { type: 'door'; door: string; open: boolean; by: 'scare' | 'stalker' | 'night' } | { type: 'fixture'; id: string; kind: string; open: boolean; by: 'player' | 'scare' | 'stalker' } | { type: 'fall'; id: string; show: string; x: number; z: number; from: number; to: number; time: number } | { type: 'distort'; strength: number; duration: number } | { type: 'torch'; change: TorchChange; charge: number } | { type: 'pickup'; id: string; kind: string; x: number; z: number } | { type: 'collect'; id: string; kind: string; have: number; need: number } | { type: 'objective'; done: boolean } | { type: 'hide'; spot: string; state: 'entering' | 'in' | 'leaving' | 'out'; x: number; z: number; yaw: number } | { type: 'stalker'; mode: StalkerMode; why: string; x: number; z: number } | { type: 'caught'; hidden: boolean; health: number } | { type: 'beat'; bpm: number; strength: number } | { type: 'end'; status: Exclude<HorrorStatus, 'playing'> }

What a step did, for the presenter and the sound. Every sound to play is a sound event; the others say what to show and why. See the pack's page for what to draw and play for each.

HorrorInput

interface HorrorInput

The player's doings this step. The game moves the player (at most director.player.speed); the director reads where they are.

  • x: number — Where the player's feet are now, world units. Ignored while hidden, when the player is held at the spot.
  • z: number — Where the player's feet are now, world units.
  • y?: number — Feet height; default the floor there.
  • yaw: number — The engine's yaw the player faces.
  • pitch?: number — Pitch in radians, positive looking down (as sector-map's rays); default 0.
  • sprint?: boolean — The sprint key is held.
  • crouch?: boolean — The crouch key is held.
  • switchTorch?: boolean — The torch's switch was pressed this step.
  • use?: boolean — Use was pressed this step: get into or out of a hiding spot, open or shut a fixture, take a pickup, answer a phone.
  • lean?: number — Lean, −1 (left) to 1 (right), held; default 0.
  • peek?: boolean — Peeking out of a hiding spot, held.
  • shake?: boolean — The torch was shaken this step (with light.shake).
  • reload?: boolean — Put a spare in this step.
  • noises?: HorrorNoise[] — Other noises the game made this step: a shot, a thing knocked over, a door forced.

HorrorLamp

interface HorrorLamp

A lamp, as the director sees it.

  • index: number — Its index among the map's lights.
  • tag: string | null — Its group name, which lamps are switched by; null for none (such a lamp cannot be switched).
  • x: number — Position in world units.
  • y: number — Height in world units.
  • z: number — Position in world units.
  • radius: number — Units it reaches.
  • intensity: number — Brightness (inverse-square units; 6 is a room lamp).
  • on: boolean — Lit now.

HorrorNoise

interface HorrorNoise

A noise the game made, for the stalker's ears.

  • x: number — Where, in world units.
  • z: number — Where, in world units.
  • radius: number — Units it carries through open space and open doors, 0 to 200.

HorrorPhase

type HorrorPhase = 'calm' | 'build' | 'peak' | 'relief'

The four moods of a night, in the order they turn: calm, build, peak, relief, then calm again.

HorrorSoundSource

type HorrorSoundSource = 'scare' | 'stalker' | 'player' | 'torch' | 'fixture' | 'night'

Who a sound comes from.

HorrorSpot

interface HorrorSpot

A place the map marks: a hiding spot, a window, a mirror, a phone, a shelf, a stall, a patrol point, a pickup. What a kind means is the config's (player.hide.kinds, a scare's spots, fixtures, light.refill, night).

  • id: string — Unique id: its kind and its number among that kind, 'locker-2'.
  • kind: string — What it is, by name. A sector map's spots are its things, and a thing's type is its kind.
  • x: number — Position in world units.
  • z: number — Position in world units.
  • y: number — Height above the floor, units (a shelf's top, a mirror's middle); 0 when the map gives none.
  • yaw: number — The engine's yaw it faces: out of a hiding spot, out of a mirror's glass, into a window.
  • tag: string | null — Its group name, or null.

HorrorState

interface HorrorState

Everything that changes in a night; a save holds exactly this (with the map's own state).

  • time: number — Seconds the night has run.
  • status: HorrorStatus — How it stands.
  • phase: HorrorPhase — The phase.
  • phaseTime: number — Seconds in the phase.
  • phaseLength: number — Seconds the phase lasts this time.
  • tension: number — Tension, 0 to 1.
  • target: number — The tension it heads for.
  • budget: number — Scare budget points.
  • gap: number — Seconds before the director may land another scare.
  • since: number — Seconds since the last scare.
  • noise: number — Noise heard near the player lately, 0 to 1.
  • landed: number — Scares landed.
  • cooldowns: Record<string, number> — Seconds before each scare may land again, by def id.
  • uses: Record<string, number> — Times each scare has landed, by def id.
  • scares: ActiveScare[] — Scares going on.
  • serial: number — Scares started, for ids.
  • distort: { strength: number; time: number; length: number } — The screen distortion now, 0 to 1, and seconds it lasts.
  • torch: TorchState — The torch.
  • player: PlayerState — The player.
  • stalker: StalkerState | null — The stalker, or null.
  • fixtures: FixtureState[] — The fixtures.
  • taken: string[] — Pickups taken, by spot id.
  • collected: number — Things collected.
  • doors: Record<string, boolean> — Doors' shut states last step, by id.
  • worked: string[] — Doors a scare or the stalker opened or shut, so the player is not blamed for them.
  • noises: { x: number; z: number; radius: number }[] — Noises the stalker has yet to hear.
  • rng: number[] — The random stream.

HorrorStatus

type HorrorStatus = 'playing' | 'escaped' | 'dawn' | 'dead'

How a night ended, or that it goes on.

HorrorWaypoint

interface HorrorWaypoint

A point on a route, and the door to open before going on, if any.

  • x: number — Where, in world units.
  • z: number — Where, in world units.
  • door?: string — A door to open first, by the world's id for it.

HorrorWorld

interface HorrorWorld

What the director needs of the map. sectorHorrorWorld(map) gives one from a sector map; any map that answers these can host a night. All positions are world units with the engine's yaw (forward is (−sin yaw, cos yaw)).

  • sees(ax: number, az: number, bx: number, bz: number, ay?: number, by?: number): boolean — An unbroken line from a to b; with heights, through openings in 2.5D maps.
  • move(x: number, z: number, dx: number, dz: number, body: HorrorBody, y?: number): { x: number; z: number; y: number } — Move a body by dx, dz, sliding along walls; where it ends up and the floor under it. y is its feet now.
  • route(fx: number, fz: number, tx: number, tz: number, body: HorrorBody): HorrorWaypoint[] | null — The way from one point to another for this body, next point first, through unlocked doors; null when there is none.
  • hearing(x: number, z: number, radius: number): (x: number, z: number) => boolean — Who hears a noise at x, z that carries radius units through open space and open doors.
  • wallDistance(x: number, z: number, yaw: number, max: number, y?: number): number | null — How far a flat ray goes before a wall or shut door, or null within max. y is its height, for 2.5D maps.
  • doorShut(door: string): boolean — Whether a door on a route is still shut.
  • openDoor(door: string): boolean — Start a door opening; true when it was shut and now opens.
  • floorAt(x: number, z: number): number — The floor height at a point.
  • open(x: number, z: number): boolean — Whether a body could stand at a point: inside the map, not in rock, a pillar or a shut door.
  • ceilingAt(x: number, z: number): number — The ceiling height over a point.
  • light(x: number, z: number, y?: number): number — How lit a point is by the lamps and the room, 0 (black) to 1, without the player's torch. y defaults to a metre above the floor.
  • lamps(): HorrorLamp[] — The lamps, as they are now.
  • setLamps(tag: string, on: boolean): boolean — Switch every lamp with a tag on or off; false when no lamp has it.
  • doors(): HorrorDoor[] — The doors.
  • closeDoor(door: string): boolean — Slam a door shut; false when it is shut already or unknown.
  • spots(): HorrorSpot[] — The marked spots. They do not move; the director reads them once.

LeanDef

interface LeanDef

Leaning round a corner.

  • distance?: number — Units the eye moves sideways at a full lean, 0 to 2; default 0.4.
  • roll?: number — Roll of the camera at a full lean, radians, 0 to 1; default 0.15.
  • speed?: number — Lean gained a second, 0.1 to 50; default 5.
  • cover?: number — Multiplies the stalker's sight of a player leaning still, 0 to 1; default 0.7.

LightDef

interface LightDef

The player's light: a torch with a beam, or a lantern all round.

  • kind?: string — What it is, for the presenter ('torch', 'lantern', 'candle', 'phone'); default 'torch'.
  • cone?: number — Half-angle of the beam in radians, 0.05 to π; π lights all round (a lantern). Default 0.42.
  • range?: number — Units it reaches at full charge, 0.5 to 200; default 12.
  • lowRange?: number — Share of the range it still reaches at the bottom of its low mark, 0 to 1; default 0.5.
  • color?: string — Colour, CSS; default '#fff2d6'.
  • capacity?: number — Seconds of light a full charge gives, 0 to 100000; 0 never runs out. Default 240.
  • start?: number — Charge at the start, 0 to 1; default 1.
  • startOn?: boolean — On at the start; default true.
  • toggle?: boolean — It can be switched off; default true.
  • low?: number — Charge below which it flickers, 0 to 1; default 0.25.
  • dying?: number — Charge below which it sputters and cuts out, 0 to 1; default 0.08.
  • flicker?: number — Flickers a second at an empty-ish charge (fewer as the charge rises to the low mark), 0 to 20; default 1.5.
  • flame?: number — A flame's steady waver, 0 to 0.5 of its strength; default 0 (a lantern or candle wants about 0.1).
  • refill?: string — The spot kind that refills it (batteries, oil); default 'battery'.
  • refillAmount?: number — Charge one refill gives, 0 to 1; default 0.6.
  • spares?: number — Most refills carried for later, 0 to 20; 0 uses each at once. Default 2.
  • autoSwap?: boolean — A spare goes in by itself when the charge runs out; default true.
  • shake?: ShakeDef | null — Shaking it to recharge; default none.
  • sounds?: LightSounds — Its sounds.

LightSounds

interface LightSounds

Sounds the torch asks for, by name; '' for none.

  • on?: string — Switched on; default 'torch-on'.
  • off?: string — Switched off; default 'torch-off'.
  • flicker?: string — A flicker as it runs low; default 'torch-flicker'.
  • sputter?: string — A sputter as it dies; default 'torch-sputter'.
  • dead?: string — The charge ran out; default 'torch-dead'.
  • swap?: string — A spare put in; default 'torch-swap'.
  • shake?: string — Shaken to recharge; default 'torch-shake'.

MercyDef

interface MercyDef

How the stalker fails to find the player on purpose, so it stays frightening rather than unfair.

  • miss?: number — Chance that going after a noise it goes astray, 0 to 1; default 0.3.
  • offset?: [number, number] — Units it goes astray by, [min, max] from 0 to 50; default [2.5, 5].
  • hidden?: number — Chance it leaves a hiding spot it saw the player take without pulling them out, 0 to 1; default 0.4.
  • giveUp?: [number, number] — Seconds of hunting after which it loses the player on purpose, [min, max] from 1 to 600; default [12, 22].
  • grace?: [number, number] — Seconds after losing the player before its sight can start a hunt again, [min, max] from 0 to 600; default [10, 18].
  • edge?: number — Noticings a second of a player at the far edge of its sight (past 70% of it), 0 to 20; default 0.6.

NightDef

interface NightDef

What the player must do: survive until dawn, collect things, reach an exit, or a mix.

  • length?: number | null — Seconds until dawn, which ends the night survived, 1 to 360000; default none.
  • collect?: { kind: string; count: number } | null — The spot kind to collect and how many; default none.
  • exit?: string | null — A spot kind to reach once everything is collected (or at once, with nothing to collect); default none.
  • reach?: number — Units within which pickups are taken and the exit is reached, 0.2 to 10; default 1.
  • pickup?: 'touch' | 'use' — Pickups are taken by walking onto them ('touch', default) or by pressing use ('use').
  • lamps?: string[] — Lamp tags switched on when everything is collected (the way out lights up); default none.
  • doors?: string[] — Doors (ids) opened when everything is collected; default none.
  • sounds?: NightSounds — Its sounds.

NightSounds

interface NightSounds

Sounds the night asks for, by name; '' for none.

  • collect?: string — Something on the list collected; default 'collect'.
  • done?: string — Everything collected; default 'objective'.
  • dawn?: string — Dawn; default 'dawn'.

NoiseDef

interface NoiseDef

How far the player's doings are heard, in units: the stalker hears them through open space and open doors.

  • walk?: number — A walking step; default 2.5.
  • run?: number — A running step; default 9.
  • sneak?: number — A crouching step; default 0.8.
  • fixture?: number — Opening or shutting a fixture; default 3.
  • door?: number — A map door opening near the player; default 6.

PacingDef

interface PacingDef

The pacing: phases, tension and the scare budget, in the manner of a game director.

  • phases?: Partial<Record<HorrorPhase, PhaseDef>> — The phases, by name; each field left out keeps its default.
  • weights?: PacingWeights — What raises tension.
  • rise?: number — Tension gained a second toward a higher target, 0 to 10; default 0.12.
  • fall?: number — Tension lost a second toward a lower target, 0 to 10; default 0.05.
  • peakAt?: number — Tension at which build turns to peak, 0 to 1; default 0.7. Build also turns to peak when its time is up.
  • wait?: number — Seconds since the last scare at which the wait factor is full, 1 to 3600; default 60.
  • near?: number — Units within which the stalker counts as near, 0.5 to 200; default 12.
  • budget?: BudgetDef — The scare budget.
  • gap?: [number, number] — Seconds between any two scares the director lands, [min, max] from 0 to 600; default [8, 20].
  • start?: HorrorPhase — The phase a night starts in; default 'calm'.

PacingWeights

interface PacingWeights

How much each thing the player is going through raises the tension it heads for. Each factor is 0 to 1; the target is their weighted sum, at most 1. Every weight is 0 to 2.

  • dark?: number — Darkness where the player stands (1 minus the light there, the torch left out); default 0.2.
  • torch?: number — The torch: 1 when off or dead, rising as the charge runs below its low mark; default 0.15.
  • seen?: number — The stalker sees the player; default 0.55.
  • unseen?: number — The stalker is near (within near) and does not see the player: hidden, or simply unseen; default 0.35.
  • noise?: number — Noises heard near the player recently (each one fades over a few seconds); default 0.25.
  • wait?: number — Time since the last scare, full at wait seconds; default 0.3.
  • speed?: number — The player's speed as a share of their sprint; default 0.1.

PatrolDef

interface PatrolDef

Patrolling between rooms.

  • spots?: string[] — Spot kinds it walks between; default ['patrol']. With none on the map it walks between the hiding spots.
  • wait?: [number, number] — Seconds it stands at each, [min, max] from 0 to 600; default [2, 6].

PhaseDef

interface PhaseDef

One phase of the pacing.

  • time?: [number, number] — Seconds it lasts, [min, max] from 1 to 3600, rolled each time it begins. Defaults: calm [25, 45], build [30, 60], peak [12, 24], relief [15, 30].
  • rate?: number — Scares a second it tries to land at full tension, 0 to 5 (0: none in this phase). Defaults: calm 0.02, build 0.12, peak 0.25, relief 0.
  • fall?: number — Multiplies how fast tension falls in it, 0 to 20. Defaults: relief 3, the others 1.

PickupView

interface PickupView

A pickup still to be taken: a refill for the light, or something on the night's list.

  • id: string — Its spot's id.
  • kind: string — Its spot's kind.
  • x: number — Position, world units.
  • y: number — Height above the floor.
  • z: number — Position, world units.

PlayerDef

interface PlayerDef

The player: movement, stamina, fear, hiding and leaning. The game moves the player; the director says how fast.

  • walk?: number — Walking speed, units per second, 0.1 to 20; default 1.5.
  • sprint?: number — Sprinting speed, units per second, 0 to 40; 0 (or no more than walk) means no sprint. Default 3.4.
  • crouch?: number — Crouching speed, units per second, 0 to 20; default 0.7.
  • stamina?: number — Seconds of sprint from full stamina, 0.5 to 600; default 6.
  • recover?: number — Stamina regained a second (a share of full), 0 to 10; default 0.15.
  • delay?: number — Seconds after sprinting before stamina comes back, 0 to 30; default 1.
  • again?: number — Stamina needed to sprint again after running out, 0 to 1; default 0.35.
  • tired?: number — Multiplies walking speed while out of breath, 0.1 to 1; default 0.75.
  • eye?: number — Eye height above the feet, 0.1 to 10; default 1.6.
  • health?: number — Health at the start; a catch takes the stalker's catch.damage, 0.01 to 1000. Default 1.
  • dread?: number | null — Seconds at full fear before the night is lost to fright, 0.5 to 600; default none.
  • fearFall?: number — Fear lost a second when calm (twice as fast in lamplight), 0 to 10; default 0.05.
  • darkFear?: number — The fear darkness brings with no light of your own (torch off or dead, in the dark), 0 to 1; default 0.45.
  • heartbeat?: [number, number] — Resting and racing heart rates, beats a minute, [rest, max] from 20 to 260; default [68, 165].
  • beats?: number | null — Fear from which each heartbeat is an event (for a thump), 0 to 1; default 0.3. null for none.
  • reach?: number — Units within which the player uses a fixture, a hiding spot or a pickup, 0.2 to 10; default 1.3.
  • stride?: number — Units walked per footstep, 0.1 to 10; default 0.75.
  • hide?: HideDef | null — Hiding; null for none.
  • lean?: LeanDef | null — Leaning; null for none.
  • noise?: NoiseDef — How far the player is heard.
  • sounds?: PlayerSounds — The player's sounds.

PlayerSounds

interface PlayerSounds

Sounds the player asks for, by name; '' for none.

  • step?: string — A walking step; default ''.
  • run?: string — A running step; default ''.
  • pant?: string — Out of breath; default 'pant'.
  • hide?: string — Getting into a hiding spot; default 'hide'.
  • unhide?: string — Getting out; default 'unhide'.
  • gasp?: string — A gasp when a scare lands close; default 'gasp'.
  • pickup?: string — A pickup taken; default 'pickup'.

PlayerState

interface PlayerState

The player, as saved.

  • placed: boolean — Whether the first step has placed them.
  • x: number — Position.
  • y: number — Feet height.
  • z: number — Position.
  • yaw: number — Yaw.
  • pitch: number — Pitch.
  • moving: number — Speed measured last step.
  • speed: number — Speed allowed now.
  • stamina: number — Stamina, 0 to 1.
  • rest: number — Seconds since they last sprinted.
  • sprinting: boolean — Sprinting.
  • exhausted: boolean — Out of breath.
  • crouch: boolean — Crouching.
  • exertion: number — Exertion, 0 to 1.
  • fear: number — Fear, 0 to 1.
  • dread: number — Seconds at full fear.
  • bpm: number — Heart rate.
  • beat: number — Where in its beat the heart is, 0 to 1.
  • health: number — Health.
  • hidden: string | null — The spot they hide in, or null.
  • hiding: 'entering' | 'in' | 'leaving' | null — Getting in, in, getting out, or null.
  • hideT: number — Seconds left getting in or out.
  • peeking: boolean — Peeking.
  • lean: number — Lean, −1 to 1.
  • still: number — Seconds standing still.
  • stride: number — Units walked since the last footstep.
  • seen: boolean — The stalker saw them last step.

PlayerView

interface PlayerView

The player, for the camera, the HUD and the sound.

  • x: number — Position the camera should be at (a hiding spot's, while hidden), world units.
  • y: number — Feet height.
  • z: number — Position, world units.
  • yaw: number — The engine's yaw.
  • speed: number — The fastest the game should move the player now, units a second (0 while hiding).
  • moving: number — How fast they moved last step, units a second.
  • stamina: number — Stamina, 0 to 1.
  • sprinting: boolean — Sprinting now.
  • exhausted: boolean — Out of breath: no sprint until stamina comes back to player.again.
  • fear: number — Fear, 0 to 1: drive a vignette, a desaturation or a ringing.
  • heartbeat: number — Heart rate, beats a minute.
  • breath: number — How hard they breathe, 0 to 1, for a breathing loop.
  • vignette: number — How dark to make the screen's edges, 0 to 1 (fear and hurt).
  • health: number — Health left.
  • hidden: string | null — The hiding spot they are in, getting into or out of, or null.
  • hiding: 'entering' | 'in' | 'leaving' | null — 'entering', 'in', 'leaving', or null.
  • peeking: boolean — Peeking out of a hiding spot.
  • lean: number — Lean, −1 to 1.
  • leanX: number — Where the lean moves the eye, world units: add to the camera's position.
  • leanZ: number — Where the lean moves the eye, world units.
  • roll: number — The camera's roll for the lean, radians.
  • seen: boolean — The stalker sees them now.
  • still: number — Seconds they have stood still.

ScareDef

interface ScareDef

A scare, as data. Its kind says what it does and how it is placed; everything else tunes it. Fields left out take the kind's defaults (listed on the pack's page). show and sound name what the presenter draws and plays.

  • id: string — Unique id.
  • kind: ScareKind — - 'lights': lamps with one tag near the player go out with sparks, and maybe flicker back. - 'apparition': a figure stands just beyond the torch beam, at a corridor end or behind a window spot; it goes when lit, looked at straight on or come near. - 'runner': a figure crosses a corridor end ahead, from out of sight to out of sight. - 'slam': an open door or fixture near the player slams shut, by preference out of sight. - 'footsteps': steps behind the player that follow, and stop when the player looks back. - 'whisper': a whisper just behind the player. - 'fall': a thing drops from a shelf spot nearby, or from the ceiling at the edge of view. - 'breath': breathing close by, out of sight (outside the spot when the player is hidden). - 'phone': a phone or radio spot rings or crackles until the player reaches it. - 'distort': a screen distortion pulse. - 'fixture': a shut fixture (a stall, a cabinet) opens by itself. - 'mirror': a figure stands behind the player, seen in a mirror spot they face; it goes when they turn.
  • show?: string — What the presenter shows (a figure's look, an effect); default by kind.
  • sound?: string — The sound it plays at its place; default by kind. '' for none.
  • sound2?: string — A second sound: a lamp's buzz as it flickers back, a phone answered, a thing landing; default by kind.
  • cost?: number — Budget points it spends, 0 to 100; default by kind (1 or 2).
  • cooldown?: number — Seconds before it may land again, 0 to 3600; default 40.
  • max?: number — Most times it lands in a night, 0 to 10000; default unlimited.
  • weight?: number — How often it is chosen against the others, 0 to 100; default 1.
  • phases?: HorrorPhase[] — The phases it lands in; default by kind (build and peak; lights and distortion in calm too).
  • tension?: [number, number] — The tension it lands within, [min, max] from 0 to 1; default [0, 1].
  • jolt?: number — Tension it adds when it lands, 0 to 1; default by kind.
  • fear?: number — Fear it adds, 0 to 1; default by kind.
  • pulse?: number — A screen distortion pulse with it, 0 to 1; default 0 (a 'distort' scare 0.8).
  • noise?: number — How far the stalker hears it, units, 0 to 200; default 0 (a falling thing 6).
  • range?: [number, number] — Units from the player it is placed within, [min, max] from 0 to 200; default by kind.
  • spots?: string[] — The spot kinds it uses (windows, phones, mirrors, shelves, stalls); default by kind.
  • tags?: string[] — Lamp tags (lights) or door ids and tags (slam) it may use; default any.
  • duration?: [number, number] — Seconds it lasts at most, [min, max] from 0 to 600; default by kind.
  • when?: ScareWhen — When it may land.
  • back?: [number, number] | null — Lights: seconds out before they flicker back, [min, max] from 0 to 3600; null: they stay out. Default [6, 18].
  • stayOut?: number — Lights: the chance they stay out anyway, 0 to 1; default 0.25.
  • count?: number — Lights: sparks in each burst, 0 to 500; default 14. Footsteps: steps, count from 1 to 100 (default 6).
  • speed?: number — Runner: units a second (default 5). Footsteps: steps a second (default 1.8). 0.1 to 50.
  • span?: number — Runner: half the width of the crossing, units, 0.5 to 20 (default 2.5); its two ends must be out of sight.
  • ends?: boolean — Apparition: also stand at corridor ends along the view (default true).
  • height?: number — Figures: height in units, 0.2 to 20; default 1.8.
  • vanish?: VanishDef — What makes a figure go.

ScareEnd

type ScareEnd = 'time' | 'lit' | 'look' | 'near' | 'turn' | 'answered' | 'done'

Why a scare ended.

ScareKind

type ScareKind = | 'lights' | 'apparition' | 'runner' | 'slam' | 'footsteps' | 'whisper' | 'fall' | 'breath' | 'phone' | 'distort' | 'fixture' | 'mirror'

What a scare does. Each kind has its own placement and its own way of ending; see ScareDef.

ScareView

interface ScareView

A scare going on.

  • id: string — Its id, <def>-<n>.
  • scare: string — The def's id.
  • kind: ScareKind — Its kind.
  • show: string — What it shows.
  • x: number — Where it is now, world units (a falling thing's y falls).
  • y: number — Height.
  • z: number — Where, world units.
  • age: number — Seconds since it began.
  • life: number — Seconds it lasts at most (0: until it is done).

ScareWhen

interface ScareWhen

When a scare may land, beyond its phase, tension and budget. Every condition left out holds.

  • dark?: number — The light where the player stands (lamps and sectors, without the torch) is at most this, 0 to 1.
  • torch?: 'on' | 'off' | 'low' — 'on' (lit), 'off' (off or dead) or 'low' (below its low mark).
  • moving?: boolean — The player is moving (true) or not (false).
  • still?: number — The player has stood still at least this many seconds, 0 to 600.
  • hidden?: boolean — The player is hidden (true) or not (false).
  • chased?: boolean — The stalker is hunting the player (true) or not (false).

SearchDef

interface SearchDef

Searching.

  • time?: [number, number] — Seconds it searches round where it lost the player or heard them, [min, max] from 0 to 600; default [8, 14].
  • radius?: number — Units round that place it searches, 0.5 to 50; default 5.
  • wait?: [number, number] — Seconds it stands at each place it checks, [min, max] from 0 to 60; default [0.8, 2].

SectorHorrorWorld

interface SectorHorrorWorld extends HorrorWorld

The world a sector map gives, with the map's own events from the doors and lamps the director worked.

  • readonly map: SectorMap — The map.
  • drain(): MapEvent[] — The map's events (movers starting, their sounds) caused by slams and lamps since the last call; for the game to play.

SectorWorldOptions

interface SectorWorldOptions

How sectorHorrorWorld reads a sector map.

  • ambient?: number — Multiplies a sector's own light as the room's share of the light at a point, 0 to 10; default 1.
  • lampScale?: number — Multiplies each lamp's share, 0 to 10; default 1.
  • ignore?: string[] — Thing types that are not spots; default ['start'].
  • rename?: Record<string, string> — Thing types read as another spot kind ({ wardrobe: 'locker' }); default none.

ShakeDef

interface ShakeDef

Shaking the torch to win back a little charge.

  • gain: number — Charge one shake gives, 0 to 1.
  • up: number — The most charge shaking brings it to, 0 to 1.
  • noise?: number — How far the shaking is heard, units, 0 to 100; default 0.

StalkerDef

interface StalkerDef

The stalker: one monster that hunts by sound and sight and hates the light.

  • show?: string — What the presenter shows; default 'stalker'.
  • speed?: StalkerSpeeds — Speeds by mode.
  • radius?: number — Body radius, units, 0.1 to 4; default 0.35.
  • height?: number — Height, units, 0.2 to 20; default 2. Its eye is at 90% of it.
  • step?: number — Highest step it walks up, units, 0 to 20; default 0.5.
  • sight?: number — Units it sees a player in light without a torch, 0 to 500; default 12.
  • sightLit?: number — Units it sees a player whose torch is on, 0 to 500; default 22.
  • sightDark?: number — Units it sees a player in the dark (light below 0.25) with no torch, 0 to 500; default 4.
  • fov?: number — Half-angle it sees across, radians, 0 to π; default 1.1.
  • hearing?: number — Multiplies how far it hears every noise, 0 to 10; default 1.
  • light?: StalkerLight — What light does to it: 'flee' runs, 'avoid' steps out of the beam, 'freeze' cannot move while lit or watched, 'ignore'. Default 'flee'.
  • tolerance?: number — Seconds in the light before it reacts, 0 to 30; default 0.4.
  • lamps?: boolean — Bright lamplight keeps it off: it will not follow a player standing in light of at least bright into it, but waits at its edge; it never catches a player standing in it; and it keeps its beat to the darker rooms (it still passes through lit places on its way). Default true.
  • bright?: number — Light from which lamps keep it off, 0 to 1; default 0.55.
  • flee?: [number, number] — Seconds it runs from the light, [min, max] from 0 to 600; default [3, 6].
  • reach?: number — Units within which it catches the player, 0.1 to 10; default 0.9.
  • catch?: CatchDef — What a catch does.
  • search?: SearchDef — Searching.
  • patrol?: PatrolDef — Patrolling.
  • wake?: number — Seconds before it first appears, 0 to 36000; default 30.
  • wakeOnPeak?: boolean — It appears at the first peak even before wake; default true.
  • lair?: string — The spot kind where it appears; default 'lair'. With none, the patrol spot furthest from the player.
  • mercy?: MercyDef — How it fails on purpose.
  • director?: boolean — The pacing steers it: away in calm, toward the player at a peak, back to its far rooms in relief; default true.
  • stride?: number — Units walked per footstep sound, 0.1 to 10; default 0.9.
  • ambient?: [number, number] — Seconds between its idle sounds, [min, max] from 0.5 to 600; default [7, 14].
  • sounds?: StalkerSounds — Its sounds.

StalkerLight

type StalkerLight = 'flee' | 'avoid' | 'freeze' | 'ignore'

How the stalker reacts to light.

StalkerMode

type StalkerMode = 'dormant' | 'patrol' | 'investigate' | 'hunt' | 'search' | 'flee' | 'retreat'

What the stalker is doing.

StalkerSounds

interface StalkerSounds

Sounds the stalker makes, by name; '' for none.

  • step?: string — A footstep, every stride units; default 'stalker-step'.
  • growl?: string — It heard something; default 'growl'.
  • scream?: string — It saw the player and the hunt begins; default 'scream'.
  • sniff?: string — It checks a place or a hiding spot; default 'sniff'.
  • hiss?: string — The light hurts it; default 'hiss'.
  • idle?: string — Now and then, unaware; default 'moan'.
  • door?: string — It forces a door; default 'door-bash'.
  • catch?: string — It catches the player; default 'catch'.

StalkerSpeeds

interface StalkerSpeeds

Units a second the stalker moves in each mode, 0 to 30.

  • patrol?: number — Walking its beat; default 1.1.
  • search?: number — Going to a noise and searching; default 1.7.
  • hunt?: number — Chasing the player; default 3.1.
  • flee?: number — Running from the light; default 3.8.

StalkerState

interface StalkerState

The stalker, as saved.

  • x: number — Position.
  • y: number — Feet height.
  • z: number — Position.
  • yaw: number — Yaw.
  • mode: StalkerMode — Mode.
  • timer: number — Seconds left in a timed mode (dormant, search, flee, retreat).
  • wait: number — Seconds left standing where it is.
  • gx: number — Where it is going.
  • gz: number — Where it is going.
  • route: { x: number; z: number; door?: string }[] — Its route, next first.
  • replan: number — Seconds until it plans its route again.
  • lx: number — Where it last saw or heard the player.
  • lz: number — Where it last saw or heard the player.
  • cx: number — Where it searches round.
  • cz: number — Where it searches round.
  • sees: boolean — It saw the player last step.
  • sawHide: string | null — The hiding spot it saw the player take, or null.
  • hunt: number — Seconds this hunt has run.
  • giveUp: number — Seconds of hunting before it gives up on purpose.
  • grace: number — Seconds before its sight may start a hunt.
  • lit: number — Seconds it has been in the light.
  • litNow: boolean — In the light now.
  • frozen: boolean — Held by the light.
  • avoiding: boolean — Stepping out of the beam.
  • lurk: boolean — Waiting at the edge of bright lamplight it will not enter.
  • walked: number — Units walked.
  • stride: number — Units since its last footstep.
  • noise: number — Seconds to its next idle sound.
  • stuck: number — Seconds without getting nearer its goal.
  • checking: string | null — The spot it is checking, or null.
  • checked: string[] — Spots it has checked in this search.
  • post: string | null — The patrol spot it walks to, or null.

StalkerView

interface StalkerView

The stalker, for the presenter.

  • x: number — Position, world units.
  • y: number — Feet height.
  • z: number — Position, world units.
  • yaw: number — The engine's yaw it faces.
  • mode: StalkerMode — What it is doing.
  • show: string — What the presenter shows (stalker.show). Draw nothing while mode is 'dormant'.
  • lit: boolean — In the light (the torch's or a bright lamp's).
  • frozen: boolean — Held still by the light or a look (with light: 'freeze').
  • avoiding: boolean — Stepping back out of the torch beam (with light: 'avoid').
  • lurking: boolean — Waiting at the edge of bright lamplight it will not follow the player into.
  • walked: number — Units walked, for a walk cycle.

TorchChange

type TorchChange = 'on' | 'off' | 'low' | 'flicker' | 'sputter' | 'dead' | 'swap' | 'charge' | 'refill'

What the torch did.

TorchState

interface TorchState

The torch, as saved.

  • on: boolean — Switched on.
  • charge: number — Charge, 0 to 1.
  • spares: number — Spares carried.
  • dip: number — How deep the current dip is, 0 to 1.
  • dipT: number — Seconds left in the current dip.
  • strength: number — Strength now, 0 to 1.
  • warned: boolean — It said it was low.

TorchView

interface TorchView

The torch, for the presenter's light and the HUD.

  • kind: string — What it is (light.kind).
  • on: boolean — Switched on (it may still be dark when dead).
  • charge: number — Charge left, 0 to 1.
  • strength: number — How bright it shines now, 0 to 1, with flicker and sputter: set the light's intensity by it (0 is dark).
  • flicker: number — How much it is dipping now, 0 to 1 (a flicker or a sputter).
  • cone: number — The beam's half-angle, radians (π all round).
  • range: number — Units it reaches now.
  • color: string — Colour, CSS.
  • spares: number — Spare refills carried.
  • dead: boolean — Out of charge.
  • sputter: boolean — Sputtering (it cuts out now and then).

VanishDef

interface VanishDef

What makes a figure go.

  • lit?: boolean — It goes when the torch beam or a lamp lights it; default true for apparitions.
  • look?: number — It goes after being looked at straight on this many seconds, 0 to 60; default 0.35 for apparitions. 0: never.
  • near?: number — It goes when the player comes within this many units, 0 to 100; default 2.5. 0: never.
  • turn?: number — A mirror figure goes when the player turns more than this many radians from where they looked, 0 to π; default 1.

ViewDef

interface ViewDef

How the presenter's camera sees, for placing things in or out of view.

  • fov?: number — Half the camera's horizontal field of view, radians, 0.1 to 1.5; default 0.75.
  • look?: number — Half-angle within which the player counts as looking straight at something, radians, 0.01 to 0.6; default 0.12.