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.

SignatureDescription
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.
Note Your game's art, music, maps, and scripts are configured separately with 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.

SignatureDescription
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).

SignatureDescription
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.tierRead-only membership tier, set from the player's Verge account (never an attribute).
Note A client script can also update a player attribute (via 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.

SignatureDescription
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.

SignatureDescription
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.

MemberDescription
player.namePlayer name (read-only, live per-frame).
player.xPlayer tile X (read-only, live per-frame).
player.yPlayer tile Y (read-only, live per-frame).
player.mapCurrent map name (read-only, live per-frame).
player.setAttribute(key, value)Updates a saved player attribute from the client (pushed to the server).
Pattern These are low-level primitives. A common convention (the one LoreWorld uses) is to wrap them in a single UI module so feature scripts don’t draw panels or labels directly. But that’s a project choice you make.