NET FORGE DOCS

@netforge/engine API reference

Last updated Checked against @netforge/engine 0.2.0View as Markdown

Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under @netforge with source at github.com/netnetdev/net-forge.

The API a game is written against: game, prefab, weapon, upgrade, director, system, earn, store and the headless test harness engine.test.run. Declarative and Zod-validated, with no DOM, renderer or netcode. This is the only module src/game.ts may import.

import { game, prefab, engine } from "@netforge/engine";

Generated from packages/engine/src/index.ts by apps/forge-docs/scripts/api.mjs. Signatures are what the TypeScript compiler reports for the current source; long types are cut and say so.

KindCount
Functions23
Classes1
Constants38
Types83

Functions

achievement

Declare an achievement (counted per player per run; it unlocks keepers, never coins).

function achievement(id: string, def: AchievementInput): AchievementDef;

Source: packages/engine/src/api/registry.ts

card

A card (at most 40).

function card(id: string, def: CardInput): CardDef;

Source: packages/engine/src/api/cards.ts

cardTable

The table: hero health, hand and board sizes, the gauntlet, the starter deck and the AI tiers (one per game).

function cardTable(def: CardTableInput): CardTableDef;

Source: packages/engine/src/api/cards.ts

creature

A creature players meet, fight and catch (at most 24).

function creature(id: string, def: CreatureInput): CreatureDef;

Source: packages/engine/src/api/collector.ts

director

Declare the spawn director (at most one per game): who spawns, how many, how fast and how tough, over the run's clock. See directorSchema.

function director(def: DirectorInput): DirectorDef;

Source: packages/engine/src/api/registry.ts

dungeon

Build a dungeon floor from a spec. Throws GameDefinitionError with readable lines on a bad spec.

function dungeon(spec: DungeonSpec): DungeonLayout;

Source: packages/engine/src/api/dungeon.ts

economy

Declare the game's coin model (at most once). Without it a game uses the recommended default: coins buy cosmetics, unlocks and in-run consumables, never permanent stat power. economy({ store: "cosmetics" }) sells looks only; economy({ metaUpgrades: true }) opts in to metaUpgrade(...).

function economy(def?: EconomyInput): EconomyDef;

Source: packages/engine/src/api/registry.ts

game

Declare the game. Exactly one per game module; it is the module's default export.

function game(def: GameInput): GameDef;

Source: packages/engine/src/api/registry.ts

keeper

Declare a keeper (a playable character): a start weapon and a signature passive. Players pick one before their first level; at most 15.

function keeper(id: string, def: KeeperInput): KeeperDef;

Source: packages/engine/src/api/registry.ts

marsh

The marsh: its size, camp, starters, grass, blocked tiles and warden (one per game).

function marsh(def: MarshInput): MarshDef;

Source: packages/engine/src/api/collector.ts

metaUpgrade

Declare a meta upgrade: a permanent stat bonus a player buys with coins, level by level (opt-in: economy({ metaUpgrades: true })). The engine caps meta power at +15% per stat and +30% in total, and costs grow geometrically. The store shows every level's bonus and price.

function metaUpgrade(id: string, def: MetaUpgradeInput): MetaUpgradeDef;

Source: packages/engine/src/api/registry.ts

mission

Declare a daily goal (the HUD shows three a day; it pays nothing).

function mission(id: string, def: MissionInput): MissionDef;

Source: packages/engine/src/api/registry.ts

move

A move creatures use in battle (at most 48).

function move(id: string, def: MoveInput): MoveDef;

Source: packages/engine/src/api/collector.ts

plant

A plant players buy and level (at most 8).

function plant(id: string, def: PlantInput): PlantDef;

Source: packages/engine/src/api/idle.ts

prefab

Declare a prefab: a spawnable entity template.

function prefab(id: string, def: PrefabInput): PrefabDef;

Source: packages/engine/src/api/registry.ts

saltFlat

The flat: shift length, tending, raking, the chain's ratios and the shared contract (one per game).

function saltFlat(def: SaltFlatInput): SaltFlatDef;

Source: packages/engine/src/api/idle.ts

system

Declare a system. setup runs once when a run starts and schedules work with every, after, onTick.

function system(name: string, setup: SystemSetup): void;

Source: packages/engine/src/api/registry.ts

title

Declare an end-screen title ("The Butcher": the most kills).

function title(id: string, def: TitleInput): TitleDef;

Source: packages/engine/src/api/registry.ts

tower

A tower players build (at most 8).

function tower(id: string, def: TowerInput): TowerDef;

Source: packages/engine/src/api/tower.ts

towerBoard

The board: its size, the creeps' road, lives and starting gold (one per game).

function towerBoard(def: TowerBoardInput): TowerBoardDef;

Source: packages/engine/src/api/tower.ts

upgrade

Declare a passive upgrade offered at level-up (survivor template).

function upgrade(id: string, def: UpgradeInput): UpgradeDef;

Source: packages/engine/src/api/registry.ts

waves

The waves (one per game).

function waves(def: WavesInput): WavesDef;

Source: packages/engine/src/api/tower.ts

weapon

Declare a weapon (survivor template): it fires by itself; players gain and level weapons at level-up.

function weapon(id: string, def: WeaponInput): WeaponDef;

Source: packages/engine/src/api/registry.ts

Classes

GameDefinitionError

Thrown for any invalid declaration; issues are agent-readable lines.

class GameDefinitionError {
  constructor(where: string, issues: readonly string[]);
  readonly issues: readonly string[];
}

Source: packages/engine/src/api/schemas.ts

Constants

AI_BEHAVIOURS

Enemy behaviours the sim runs (roles). Every big hit is telegraphed with a ground marker that fills before it lands.

  • chase (default): runs at the nearest player. tank: chase, for slow heavy prefabs (give it mass).
  • idle / none: stands still.
  • runner: aims where the player will be in 0.5 s. Fast and fragile.
  • charger: inside attack.range (6 m) stops, shows a lane for 0.55 s, dashes 3.4x along it for 0.6 s, recovers 1 s.
  • ranged: keeps ~80% of attack.range (10 m), backs off, shows an aim line 0.3 s, fires a slow shot (attack.speed 7 m/s).
  • bomber: next to a player stops, arms a 1 s fuse circle (attack.radius 2.5 m), explodes for 1.4x damage; the blast hurts enemies too.
  • shielder: every 6 s shields the 6 nearest allies for 35% of their health, 8 s.
  • healer: every 3.5 s heals the 6 nearest allies 7%.
  • summoner: keeps its distance and calls attack.count (2) attack.summon adds every 7 s, at most 4 alive.
  • flee: runs from the nearest player. wander: drifts. Anything else is rejected at build time, never silently ignored.
const AI_BEHAVIOURS: readonly ["none", "chase", "idle", "tank", "runner", "charger", "ranged", "bomber", "shielder", "healer", "summoner", "flee", "wander"];

Source: packages/engine/src/api/schemas.ts

APPEARANCE_PARTS

Attachments an appearance can add. Each sits on an anchor the body plan has (head, face, back, tail, body, wheels).

const APPEARANCE_PARTS: readonly ["horns", "ears_long", "ears_round", "antenna", "crown", "hat_cap", "hat_top", "mustache", "tail", "tail_bolt", "wings", "armor", "backpack", "big_wheels"];

Source: packages/engine/src/api/appearance.ts

appearanceSchema

const appearanceSchema: z.ZodObject<{ tint: z.ZodOptional<z.ZodString>; accent: z.ZodOptional<z.ZodString>; scale: z.ZodOptional<z.ZodNumber>; parts: z.ZodDefault<z.ZodArray<z.ZodEnum<{ horns: "horns"; ears_long: "ears_long"; ears_round: "ears_round"; antenna: "antenna"; crown: "crown"; hat_cap: "hat_cap"; hat_top: "hat_top"; mustache: "mustache"; tail: "tail"; tail_bolt: "tail_bolt"; wings: "wings"; armor: "armor"; backpack: "backpack"; big_wheels: "big_wheels"; }>>>; }, z.core.$strict>;

Source: packages/engine/src/api/appearance.ts

CARD_STATS

Store upgrade stats a card battler reads: hero health, unit attack, starting mana, starting hand.

const CARD_STATS: readonly ["maxHealth", "might", "haste", "amount"];

Source: packages/engine/src/api/cards.ts

COLLECTOR_STATS

Store upgrade stats a collector game reads: team attack, team health, team defence, extra snares, healing between battles.

const COLLECTOR_STATS: readonly ["might", "maxHealth", "armor", "amount", "regen"];

Source: packages/engine/src/api/collector.ts

DECAL_PRESETS

Ground decals left behind (scorch marks, splats, shock rings).

const DECAL_PRESETS: readonly ["none", "scorch", "splat", "ring"];

Source: packages/engine/src/api/schemas.ts

dungeonSchema

const dungeonSchema: z.ZodObject<{ seed: z.ZodNumber; rooms: z.ZodNumber; cell: z.ZodDefault<z.ZodNumber>; size: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>; corridor: z.ZodDefault<z.ZodNumber>; loops: z.ZodDefault<z.ZodNumber>; }, z.core.$strict>;

Source: packages/engine/src/api/dungeon.ts

earn

Earn rules (every game must have at least one).

const earn: { rule(id: string, def: EarnRuleInput): EarnRuleDef; stake(def: EarnStakeInput): EarnStakeDef; pot(def: EarnPotInput): EarnPotDef; };

Source: packages/engine/src/api/registry.ts

EFFECT_KINDS

const EFFECT_KINDS: readonly ["damage", "heal", "draw", "buff"];

Source: packages/engine/src/api/cards.ts

EFFECT_TARGETS

Who an effect hits. "enemy": the player picks an enemy unit or the enemy hero; "enemy_hero"; "all_enemies": every enemy unit; "own_hero"; "own_unit": the player picks one of their units; "all_own": every unit they have. draw ignores the target.

const EFFECT_TARGETS: readonly ["enemy", "enemy_hero", "all_enemies", "own_hero", "own_unit", "all_own"];

Source: packages/engine/src/api/cards.ts

ELEMENTS

The four elements, a cycle: each one is strong against the next and weak against the one before (root soaks tide, tide shorts spark, spark cracks stone, stone crushes root). Strong hits deal 1.5x, weak ones 0.67x.

const ELEMENTS: readonly ["root", "tide", "spark", "stone"];

Source: packages/engine/src/api/collector.ts

engine

engine.test.run({ ticks, bots, assert }): the headless playtest.

const engine: { readonly test: { readonly run: (opts: HarnessOptions) => Promise<HarnessReport>; }; };

Source: packages/engine/src/index.ts

IDLE_MAX_TEND

The longest tending window (seconds): a works nobody touches for this long stops.

const IDLE_MAX_TEND: 300;

Source: packages/engine/src/api/idle.ts

IDLE_MIN_SHIFT

The shortest shift (seconds): earn rules pay once a shift, so this bounds what one seat can earn an hour.

const IDLE_MIN_SHIFT: 600;

Source: packages/engine/src/api/idle.ts

IDLE_STATS

Store upgrade stats an idle game reads: plant output (might), raking speed (haste), salt a rake (amount).

const IDLE_STATS: readonly ["might", "haste", "amount"];

Source: packages/engine/src/api/idle.ts

LOOK_PRESETS

Lighting presets of the engine's render stack (sun, sky, fog and grading together).

const LOOK_PRESETS: readonly ["night", "dusk", "day", "studio"];

Source: packages/engine/src/api/schemas.ts

META_MAX_LEVELS

Most levels of one meta upgrade, most meta upgrades per game, and the slowest cost growth (geometric).

const META_MAX_LEVELS: 5;

Source: packages/engine/src/api/schemas.ts

META_MAX_PER_STAT

Hard caps (engine-enforced, not a game setting): +15% to any one stat from meta upgrades, +30% across all of them.

const META_MAX_PER_STAT: 0.15;

Source: packages/engine/src/api/schemas.ts

META_MAX_TOTAL

const META_MAX_TOTAL: 0.3;

Source: packages/engine/src/api/schemas.ts

META_MAX_UPGRADES

const META_MAX_UPGRADES: 8;

Source: packages/engine/src/api/schemas.ts

META_MIN_GROWTH

const META_MIN_GROWTH: 1.5;

Source: packages/engine/src/api/schemas.ts

META_STATS

Stats a meta upgrade may raise (each a percentage of the base).

const META_STATS: readonly ["speed", "maxHealth", "magnet", "might", "haste", "area"];

Source: packages/engine/src/api/schemas.ts

MOVE_EFFECTS

const MOVE_EFFECTS: readonly ["none", "drain", "heal", "guard"];

Source: packages/engine/src/api/collector.ts

PARTICLE_PRESETS

GPU particle presets the engine draws (one draw call for all of them).

const PARTICLE_PRESETS: readonly ["sparks", "burst", "embers", "smoke", "hitSpark", "dust", "magic"];

Source: packages/engine/src/api/schemas.ts

PLANT_KINDS

const PLANT_KINDS: readonly ["pump", "pan", "kiln"];

Source: packages/engine/src/api/idle.ts

POT_REASON

The coin spend reason a PvP pot entry is spent under.

const POT_REASON: "pot";

Source: packages/engine/src/api/registry.ts

SOUND_CUES

Procedural sound cues of the feel kit (no audio files needed).

const SOUND_CUES: readonly ["none", "hit", "crunch", "boom", "zap", "chime", "thud"];

Source: packages/engine/src/api/schemas.ts

STAKE_MAX_COINS

Highest stake one run may take, in coins (the source reader's bound too).

const STAKE_MAX_COINS: 1000000;

Source: packages/engine/src/api/schemas.ts

STAKE_MAX_MULTIPLE

PLACEHOLDER: the most a stake's payout ceiling may be, as a multiple of the stake.

const STAKE_MAX_MULTIPLE: 2;

Source: packages/engine/src/api/schemas.ts

STAKE_REASON

The coin spend reason a buy-in run's stake is spent under (the referee reads it at run start).

const STAKE_REASON: "stake";

Source: packages/engine/src/api/registry.ts

STAT_KINDS

const STAT_KINDS: readonly ["speed", "maxHealth", "magnet", "might", "haste", "regen", "armor", "area", "amount"];

Source: packages/engine/src/api/schemas.ts

store

Store SKUs: upgrades and cosmetics priced in the game's coins (and/or USDG).

const store: { sku(id: string, def: SkuInput): SkuDef; };

Source: packages/engine/src/api/registry.ts

STYLES

Art styles of the asset library.

const STYLES: readonly ["pixel", "lowpoly", "toon", "voxel", "ps1", "handdrawn"];

Source: packages/engine/src/api/schemas.ts

TEMPLATES

Templates carry the genre machinery; the model adds content and rules.

const TEMPLATES: readonly ["survivor", "arena", "dungeon", "racer", "platformer", "tower-defense", "party", "idle", "cards", "collector"];

Source: packages/engine/src/api/schemas.ts

TITLE_STATS

What end-screen titles rank players by.

const TITLE_STATS: readonly ["kills", "damage", "revives", "downs", "level", "pickups"];

Source: packages/engine/src/api/schemas.ts

TOWER_KINDS

const TOWER_KINDS: readonly ["bolt", "splash", "frost", "chain"];

Source: packages/engine/src/api/tower.ts

TOWER_STATS

Store upgrade stats a tower defense game reads: tower damage, fire rate, range, and team lives.

const TOWER_STATS: readonly ["might", "haste", "area", "maxHealth"];

Source: packages/engine/src/api/tower.ts

WEAPON_KINDS

const WEAPON_KINDS: readonly ["nova", "bolt", "orbit", "blaster", "beam", "cone", "chain", "aura", "meteor", "boomerang"];

Source: packages/engine/src/api/schemas.ts

Types

AchievementDef

type AchievementDef = z.output<typeof achievementSchema>;

Source: packages/engine/src/api/schemas.ts

AchievementInput

type AchievementInput = z.input<typeof achievementSchema>;

Source: packages/engine/src/api/schemas.ts

AppearanceDef

type AppearanceDef = z.output<typeof appearanceSchema>;

Source: packages/engine/src/api/appearance.ts

AppearanceInput

type AppearanceInput = z.input<typeof appearanceSchema>;

Source: packages/engine/src/api/appearance.ts

AppearancePart

type AppearancePart = (typeof APPEARANCE_PARTS)[number];

Source: packages/engine/src/api/appearance.ts

AssetId

type AssetId = string;

Source: packages/engine/src/api/schemas.ts

CardDef

type CardDef = z.output<typeof cardSchema>;

Source: packages/engine/src/api/cards.ts

CardInput

type CardInput = z.input<typeof cardSchema>;

Source: packages/engine/src/api/cards.ts

CardTableDef

type CardTableDef = z.output<typeof cardTableSchema>;

Source: packages/engine/src/api/cards.ts

CardTableInput

type CardTableInput = z.input<typeof cardTableSchema>;

Source: packages/engine/src/api/cards.ts

CreatureDef

type CreatureDef = z.output<typeof creatureSchema>;

Source: packages/engine/src/api/collector.ts

CreatureInput

type CreatureInput = z.input<typeof creatureSchema>;

Source: packages/engine/src/api/collector.ts

Curve

type Curve = z.output<typeof curveSchema>;

Source: packages/engine/src/api/schemas.ts

CurveInput

type CurveInput = z.input<typeof curveSchema>;

Source: packages/engine/src/api/schemas.ts

DecalPreset

type DecalPreset = (typeof DECAL_PRESETS)[number];

Source: packages/engine/src/api/schemas.ts

DirectorDef

type DirectorDef = z.output<typeof directorSchema>;

Source: packages/engine/src/api/schemas.ts

DirectorInput

type DirectorInput = z.input<typeof directorSchema>;

Source: packages/engine/src/api/schemas.ts

DungeonLayout

interface DungeonLayout {
  readonly field: { readonly halfSize: number; readonly pillars: [number, number, number][]; readonly walls: Box[]; readonly floors: Box[] };
  readonly rooms: readonly DungeonRoom[];
  readonly start: DungeonRoom;
  readonly boss: DungeonRoom;
  roomAt(x: number, z: number): number;
}

Source: packages/engine/src/api/dungeon.ts

DungeonRoom

interface DungeonRoom {
  readonly id: number;
  readonly x: number;
  readonly z: number;
  readonly hx: number;
  readonly hz: number;
  readonly depth: number;
  readonly links: readonly number[];
}

Source: packages/engine/src/api/dungeon.ts

DungeonSpec

type DungeonSpec = z.input<typeof dungeonSchema>;

Source: packages/engine/src/api/dungeon.ts

EarnPotDef

type EarnPotDef = z.output<typeof earnPotSchema>;

Source: packages/engine/src/api/schemas.ts

EarnPotInput

type EarnPotInput = z.input<typeof earnPotSchema>;

Source: packages/engine/src/api/schemas.ts

EarnRuleDef

type EarnRuleDef = z.output<typeof earnRuleSchema>;

Source: packages/engine/src/api/schemas.ts

EarnRuleInput

type EarnRuleInput = z.input<typeof earnRuleSchema>;

Source: packages/engine/src/api/schemas.ts

EarnStakeDef

type EarnStakeDef = z.output<typeof earnStakeSchema>;

Source: packages/engine/src/api/schemas.ts

EarnStakeInput

type EarnStakeInput = z.input<typeof earnStakeSchema>;

Source: packages/engine/src/api/schemas.ts

EconomyDef

type EconomyDef = z.output<typeof economySchema>;

Source: packages/engine/src/api/schemas.ts

EconomyInput

type EconomyInput = z.input<typeof economySchema>;

Source: packages/engine/src/api/schemas.ts

EdgeSide

Where spawnEdge places enemies around the target player's screen.

type EdgeSide = "any" | "ahead" | "behind" | "north" | "south" | "east" | "west";

Source: packages/engine/src/api/registry.ts

Element

type Element = (typeof ELEMENTS)[number];

Source: packages/engine/src/api/collector.ts

FeelDef

type FeelDef = z.output<typeof feelSchema>;

Source: packages/engine/src/api/schemas.ts

FunMetrics

How fun the opening and the run felt to the bots, measured (GAME-DESIGN.md). Horde games (survivor-like) are measured over the first run; arena games over every life. Fields that do not apply to the genre are null.

interface FunMetrics {
  readonly genre: "horde" | "arena" | "race";
  readonly firstThreatSeconds: number | null;
  readonly firstRewardSeconds: number | null;
  readonly levelAt: { readonly "60": number | null; readonly "180": number | null; readonly "360": number | null; readonly "540": number | null };
  readonly deathsBeforeMinute: number | null;
  readonly onScreenAt30: number | null;
  readonly contactHitsFirstMinute: number | null;
  readonly telegraphedDeathShare: number | null;
  readonly spawnsOnScreen: number | null;
  readonly survivalSeconds: number | null;
  readonly spawnToDamageSeconds: number | null;
  readonly spawnDeathShare: number | null;
  readonly killSpread: number | null;
  readonly leadChanges: number | null;
  readonly bossKills: readonly { readonly prefab: string; readonly seconds: number }[];
  readonly downsBySource: Readonly<Record<string, number>>;
  readonly firstHitSeconds?: number | null;
  readonly lowestHealthBy120?: number | null;
  readonly firstEliteSeconds?: number | null;
  readonly firstBossSeconds?: number | null;
  readonly downTimeShare?: number | null;
  readonly finishSeconds?: number | null;
  readonly finishRate?: number | null;
  readonly mishapsPerRound?: number | null;
  readonly firstCoinSeconds?: number | null;
  readonly routes?: readonly { readonly course: number; readonly found: boolean; readonly seconds: number | null }[];
}

Source: packages/engine/src/api/harness.ts

GameDef

type GameDef = z.output<typeof gameSchema>;

Source: packages/engine/src/api/schemas.ts

GameInput

type GameInput = z.input<typeof gameSchema>;

Source: packages/engine/src/api/schemas.ts

GameManifest

interface GameManifest {
  readonly game: GameDef;
  readonly prefabs: ReadonlyMap<string, PrefabDef>;
  readonly weapons: ReadonlyMap<string, WeaponDef>;
  readonly upgrades: ReadonlyMap<string, UpgradeDef>;
  readonly systems: ReadonlyMap<string, SystemSetup>;
  readonly earnRules: ReadonlyMap<string, EarnRuleDef>;
  readonly stake: EarnStakeDef;
  readonly pot: EarnPotDef | null;
  readonly skus: ReadonlyMap<string, SkuDef>;
  readonly director: DirectorDef | null;
  readonly keepers: ReadonlyMap<string, KeeperDef>;
  readonly achievements: ReadonlyMap<string, AchievementDef>;
  readonly missions: ReadonlyMap<string, MissionDef>;
  readonly titles: ReadonlyMap<string, TitleDef>;
  readonly economy: EconomyDef;
  readonly metaUpgrades: ReadonlyMap<string, MetaUpgradeDef>;
  readonly content: ReadonlyMap<string, unknown>;
}

Source: packages/engine/src/api/registry.ts

HarnessAssertion

Headless test harness: run a game on the server sim with bot players and report what happened.

When a game module has been declared (game(), prefabs, weapons, systems, earn rules), it runs that game exactly as the room server does: compiled content in engine-sim, the systems on the GameRunner, earn rules counted per player. With no game declared it runs the week-2 engine-sim arena (the built-in chaser spawner) with scripted bots.

interface HarnessAssertion {
  readonly name: string;
  readonly check: (report: HarnessReport) => boolean;
}

Source: packages/engine/src/api/harness.ts

HarnessOptions

interface HarnessOptions {
  readonly ticks: number;
  readonly bots: number;
  readonly enemies?: number;
  readonly seed?: number;
  readonly tickRate?: number;
  readonly assert?: readonly HarnessAssertion[];
  readonly bot?: "basic" | "human";
  readonly picks?: "random" | "greedy";
  readonly enemyMix?: boolean;
}

Source: packages/engine/src/api/harness.ts

HarnessReport

interface HarnessReport {
  readonly ticks: number;
  readonly bots: number;
  readonly deaths: number;
  readonly kills: number;
  readonly wave: number;
  readonly runs: { readonly won: number; readonly lost: number };
  readonly maxLevel: number;
  readonly peakEnemies: number;
  readonly topScore: number;
  readonly scorers: number;
  readonly earned: Readonly<Record<string, number>>;
  readonly msPerTick: number;
  readonly p99MsPerTick: number;
  readonly earnEmitted: number;
  readonly softlock: boolean;
  readonly fun?: FunMetrics;
  readonly rules?: { readonly template: string; readonly checks: readonly { readonly ok: boolean; readonly line: string }[]; readonly progress: number };
  readonly failed: readonly string[];
}

Source: packages/engine/src/api/harness.ts

KeeperDef

type KeeperDef = z.output<typeof keeperSchema>;

Source: packages/engine/src/api/schemas.ts

KeeperInput

type KeeperInput = z.input<typeof keeperSchema>;

Source: packages/engine/src/api/schemas.ts

LookDef

type LookDef = z.output<typeof lookSchema>;

Source: packages/engine/src/api/schemas.ts

LookInput

type LookInput = z.input<typeof lookSchema>;

Source: packages/engine/src/api/schemas.ts

LookPreset

type LookPreset = (typeof LOOK_PRESETS)[number];

Source: packages/engine/src/api/schemas.ts

MarshDef

type MarshDef = z.output<typeof marshSchema>;

Source: packages/engine/src/api/collector.ts

MarshInput

type MarshInput = z.input<typeof marshSchema>;

Source: packages/engine/src/api/collector.ts

MetaStat

type MetaStat = (typeof META_STATS)[number];

Source: packages/engine/src/api/schemas.ts

MetaUpgradeDef

type MetaUpgradeDef = z.output<typeof metaUpgradeSchema>;

Source: packages/engine/src/api/schemas.ts

MetaUpgradeInput

type MetaUpgradeInput = z.input<typeof metaUpgradeSchema>;

Source: packages/engine/src/api/schemas.ts

MissionDef

type MissionDef = z.output<typeof missionSchema>;

Source: packages/engine/src/api/schemas.ts

MissionInput

type MissionInput = z.input<typeof missionSchema>;

Source: packages/engine/src/api/schemas.ts

MoveDef

type MoveDef = z.output<typeof moveSchema>;

Source: packages/engine/src/api/collector.ts

MoveInput

type MoveInput = z.input<typeof moveSchema>;

Source: packages/engine/src/api/collector.ts

ParticlePreset

type ParticlePreset = (typeof PARTICLE_PRESETS)[number];

Source: packages/engine/src/api/schemas.ts

PlantDef

type PlantDef = z.output<typeof plantSchema>;

Source: packages/engine/src/api/idle.ts

PlantInput

type PlantInput = z.input<typeof plantSchema>;

Source: packages/engine/src/api/idle.ts

PlayerView

A read-only view of one player, as game logic sees it.

interface PlayerView {
  readonly id: number;
  readonly position: readonly [number, number, number];
  readonly health: number;
  readonly alive: boolean;
  readonly kills: number;
  readonly deaths: number;
  readonly bot: boolean;
}

Source: packages/engine/src/api/registry.ts

PrefabDef

type PrefabDef = z.output<typeof prefabSchema>;

Source: packages/engine/src/api/schemas.ts

PrefabInput

type PrefabInput = z.input<typeof prefabSchema>;

Source: packages/engine/src/api/schemas.ts

SaltFlatDef

type SaltFlatDef = z.output<typeof saltFlatSchema>;

Source: packages/engine/src/api/idle.ts

SaltFlatInput

type SaltFlatInput = z.input<typeof saltFlatSchema>;

Source: packages/engine/src/api/idle.ts

SkuDef

type SkuDef = z.output<typeof skuSchema>;

Source: packages/engine/src/api/schemas.ts

SkuGrant

type SkuGrant = z.output<typeof skuGrantSchema>;

Source: packages/engine/src/api/schemas.ts

SkuInput

type SkuInput = z.input<typeof skuSchema>;

Source: packages/engine/src/api/schemas.ts

SoundCue

type SoundCue = (typeof SOUND_CUES)[number];

Source: packages/engine/src/api/schemas.ts

SpawnEdgeOptions

interface SpawnEdgeOptions {
  readonly count: number;
  readonly around?: number;
  readonly side?: EdgeSide;
  readonly spread?: number;
  readonly scale?: { readonly health?: number; readonly damage?: number; readonly xp?: number };
  readonly elite?: boolean;
}

Source: packages/engine/src/api/registry.ts

SpawnRingOptions

interface SpawnRingOptions {
  readonly count: number;
  readonly radius: number;
  readonly around?: number;
}

Source: packages/engine/src/api/registry.ts

Style

type Style = (typeof STYLES)[number];

Source: packages/engine/src/api/schemas.ts

SystemContext

What a system can do. Deliberately small: no renderer, no network, no physics handles. Systems run only on the authoritative side (the room server and the headless harness); clients receive the results in snapshots. Everything here is still deterministic (tick timers and the sim's own random), because run verification replays it.

interface SystemContext {
  readonly tick: () => number;
  readonly time: () => number;
  readonly players: () => readonly PlayerView[];
  readonly every: (seconds: number, fn: (n: number) => void) => void;
  readonly after: (seconds: number, fn: () => void) => void;
  readonly onTick: (fn: () => void) => void;
  readonly spawn: (prefab: string, at: readonly [number, number, number], opts?: { readonly elite?: boolean }) => void;
  readonly spawnRing: (prefab: string, opts: SpawnRingOptions) => void;
  readonly spawnEdge: (prefab: string, opts: SpawnEdgeOptions) => number;
  readonly emit: (event: string, players?: readonly number[]) => void;
  readonly random: () => number;
  readonly alive: (prefab?: string) => number;
  readonly on: (event: string, fn: (players: readonly number[]) => void) => void;
  readonly respawnDead: () => void;
  readonly end: (outcome: "won" | "lost") => void;
  readonly spawnPickup: (prefab: string, at: readonly [number, number, number]) => void;
  readonly announce: (text: string, opts?: { readonly tone?: "info" | "danger" | "reward" }) => void;
  readonly bossAlive: () => boolean;
  readonly pauseDirector: (seconds: number) => void;
  readonly surge: (multiplier: number, seconds: number) => void;
  readonly upcoming: (label: string, seconds: number) => void;
  readonly xpBoost: (multiplier: number, seconds: number) => void;
  readonly scatter: (prefab: string, count: number) => number;
  readonly clear: (prefab: string) => number;
  readonly onScreen: (x: number, z: number) => boolean;
}

Source: packages/engine/src/api/registry.ts

SystemSetup

type SystemSetup = (ctx: SystemContext) => void;

Source: packages/engine/src/api/registry.ts

Template

type Template = (typeof TEMPLATES)[number];

Source: packages/engine/src/api/schemas.ts

TitleDef

type TitleDef = z.output<typeof titleSchema>;

Source: packages/engine/src/api/schemas.ts

TitleInput

type TitleInput = z.input<typeof titleSchema>;

Source: packages/engine/src/api/schemas.ts

TitleStat

type TitleStat = (typeof TITLE_STATS)[number];

Source: packages/engine/src/api/schemas.ts

TowerBoardDef

type TowerBoardDef = z.output<typeof towerBoardSchema>;

Source: packages/engine/src/api/tower.ts

TowerBoardInput

type TowerBoardInput = z.input<typeof towerBoardSchema>;

Source: packages/engine/src/api/tower.ts

TowerDef

type TowerDef = z.output<typeof towerSchema>;

Source: packages/engine/src/api/tower.ts

TowerInput

type TowerInput = z.input<typeof towerSchema>;

Source: packages/engine/src/api/tower.ts

UpgradeDef

type UpgradeDef = z.output<typeof upgradeSchema>;

Source: packages/engine/src/api/schemas.ts

UpgradeInput

type UpgradeInput = z.input<typeof upgradeSchema>;

Source: packages/engine/src/api/schemas.ts

WavesDef

type WavesDef = z.output<typeof wavesSchema>;

Source: packages/engine/src/api/tower.ts

WavesInput

type WavesInput = z.input<typeof wavesSchema>;

Source: packages/engine/src/api/tower.ts

WeaponDef

type WeaponDef = z.output<typeof weaponSchema>;

Source: packages/engine/src/api/schemas.ts

WeaponInput

type WeaponInput = z.input<typeof weaponSchema>;

Source: packages/engine/src/api/schemas.ts