@netforge/engine API reference
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.
| Kind | Count |
|---|---|
| Functions | 23 |
| Classes | 1 |
| Constants | 38 |
| Types | 83 |
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>;