Server lifecycle & hooks
Your server-side game logic is JavaScript. system.js runs when your game starts up; it must call server.start() to configure the game, and typically registers the lifecycle hooks below.
| Signature | Description |
|---|---|
server.start({...}) | Required game configuration and startup. Accepts startup options such as tickInterval (how often onTick fires, in milliseconds; default 100) and registration (how new players first join). Players always sign in through their central Verge account. |
server.onTick(fn) | Registers a function called every tick. The tick rate is whatever you set for tickInterval in server.start (default 100ms). |
server.onAfterLogin(fn) | Called for every player at login (new and returning); use to call server.sendAsset(idx, name). |
server.onBeforeLogin(fn) | Called after sign-in succeeds, before the player enters the game; fn(idx, username). Return true/undefined to allow, false to deny, or a string to deny with a custom message. Not called during auto-login right after registration. Allows on error. |
server.onBeforeRegister(fn) | Called before an account is created; fn({username, extra}) where extra is the optional field value from the client. Return true/undefined to allow, false to deny, or a string to deny with a custom message. Allows on error. |
server.onAfterRegister(fn) | Notification hook called after successful registration + auto-login; fn(idx, username). No return value. |
server.onEnterMap(mapName, fnName) | Registers a function called when any player enters that map (fires on login, map change, and warp-to-map). |
server.onChatCommand(fn) | Registers a single handler invoked as fn(idx, text) for any /-command that isn't built in. Inspect the full command text and dispatch it yourself. |
server.env(key, default?) | Reads a per-deployment config value; returns its string value when set, otherwise the default argument unchanged (or undefined if omitted). Use to thread environment-specific settings into system.js. |
server.setEpoch(isoString) | Sets the game-time origin (RFC 3339); the game clock is computed from elapsed real time since this point. If not called, the time the game came online is used. |
server.gameTime() | Returns the current in-game time as {day, hour, minute} (day zero-indexed; hour 0–23). Scale: 1 real minute = 15 game minutes. |
assetsServer.start({menu, files}), where files is either a string or a {path, transport} object.Entities & movement
All entity types (players, NPCs, monsters) share one index space; a slot index (idx) identifies an entity. Coordinates are tile-based everywhere on the server.
| Signature | Description |
|---|---|
server.warpEntity(idx, tileX, tileY) | Warps an entity within its current map. |
server.warpEntityToMap(idx, tileX, tileY, mapName) | Warps an entity to a different map. |
server.setPosition(tileX, tileY) | Sets position, in tile coords. |
server.getEntity(idx) | Returns a read-only entity proxy: type ("player"/"npc"/"unknown"), name, x, y, map, costume. |
server.getPlayer(idx) | Returns a player proxy (null if not a player). See Players & data. |
server.entityCount() | Returns the current entity slot count. |
server.forEachPlayer(fn) | Calls fn(idx) for each player in the game. |
server.forEachNPC(fn) | Calls fn(idx) for each NPC. |
server.forEachMonster(fn) | Calls fn(idx) for each monster. |
Players & data
server.getPlayer(idx) returns a player proxy: read-only props plus the methods below. Player attributes are arbitrary key/value pairs saved with the player. Use them for anything your game wants to remember about someone (level, gold, quest progress).
| Signature | Description |
|---|---|
player.getAttribute(key) | Reads a saved player attribute. |
player.setAttribute(key, value) | Sets a saved player attribute. |
player.setMap(...) | Sets the player's map. |
player.setPosition(...) | Sets the player's position. |
player.save() | Persists the player record. |
player.tier | Read-only membership tier, set from the player's Verge account (never an attribute). |
player.setAttribute in a client script), which pushes the change to the server. Because attributes are client-writable, tier is kept off attributes and read-only.Assets, scripts & client calls
Your game streams to the client the moment a player connects, and the server can push additional assets, scripts, and function calls to a specific client mid-game.
| Signature | Description |
|---|---|
server.sendAsset(idx, name) | Delivers a named asset to a client, using the asset's transport config. Mid-game, bytes are routed by name prefix (script.X, image.X, music.X, map.X, etc.). |
server.sendScript(idx, name, source) | Sends JavaScript source to a client to run there. |
server.callClientFunc(idx, fnName) | Tells a client to call a named global function. |
server.playMusic(idx, trackName) | Tells a player's client to start playing one of your game's music tracks. |
server.getMapInfo(mapName) | Returns map metadata: { width, height, spawnX, spawnY, walls: [int], triggers: [{x,y,name}] }, or null. walls[idx] is a 4-bit mask per tile: bit 0 = N entry blocked, bit 1 = E, bit 2 = S, bit 3 = W. |
A typical login handler wires assets to each connecting player:
server.onAfterLogin(function(idx) {
server.sendAsset(idx, "hud.js");
const info = server.getMapInfo("town");
server.playMusic(idx, "town");
});
Client-side (presentation)
Client scripts run on the player's own machine and are presentation-only: HUD, panels, and overlays. They load with your game at start (from its script.* sections), plus runtime delivery via server.sendScript.
| Signature | Description |
|---|---|
client.onDraw(fn) | Per-frame draw callback with ctx (drawText, fillRect, read-only game state); renders above all game elements (the UI layer). |
client.onDrawWorld(fn) | Per-frame draw callback at the entity/world layer (below UI panels); use for quest markers, entity overlays, etc. |
client.onTick(fn) | Per-frame update callback with delta time. |
client.createPanel(x, y, w, h, opts) | Creates a retained-mode UI panel with addLabel(), addProgressBar(), and addButton(). Buttons support onClick callbacks with mouse hit-testing. |
client.log(msg) | Debug output. |
client.setLocalAccess(level) | Tells the client the player's access level (so it knows when to honour admin-only edit mode). |
The player global
Client scripts have a live player global, updated per-frame.
| Member | Description |
|---|---|
player.name | Player name (read-only, live per-frame). |
player.x | Player tile X (read-only, live per-frame). |
player.y | Player tile Y (read-only, live per-frame). |
player.map | Current map name (read-only, live per-frame). |
player.setAttribute(key, value) | Updates a saved player attribute from the client (pushed to the server). |