Skip to content

WebSocket and API Reference

chdvg edited this page May 20, 2026 · 1 revision

WebSocket & API Reference


REST Endpoints

Method Route Purpose
GET / DM control panel (requires auth cookie)
GET /map-builder Map Builder
GET /remote/player Player screen
GET /api/scenes Load all scenes
POST /api/scenes Save all scenes
GET /api/players Load player roster
POST /api/players Save player roster
GET /api/audio List audio files grouped by category
GET /api/maps List map files
POST /api/map-builder/save Export map PNG + save editable .map.json state
GET /api/map-builder/states List maps with an editable state file
GET /api/map-builder/state?name= Load editable state for a named map
POST /api/overlay Push timed overlay { title, html, duration } to players
POST /api/stopaudio Stop audio on all player screens
POST /api/blackout Toggle blackout overlay on player screens
POST /api/clear Dismiss open popups on players (scene image preserved)
WS /ws Real-time sync channel

Blocked Routes

The following routes always return 403:

  • /server.js
  • /seeds/*
  • /package.json

WebSocket Connection

Connect at ws://<host>:3000/ws.

All messages are JSON-encoded strings: JSON.stringify({ action|type, ...payload }).


DM → Server (action)

Action Payload Effect
show-scene-view Full scene view payload Broadcast SHOW_SCENE_VIEW; clear tokens / drawing / fog / features
update-tokens { tokens[], mapKey } Store + broadcast UPDATE_TOKENS
update-drawing { strokes[], mapKey } Store + broadcast UPDATE_DRAWING
update-fog { fogKey, cells } Store per fogKey + broadcast UPDATE_FOG
set-fog-key { fogKey } Update active fogKey; broadcast SET_FOG_KEY (runtime fog toggle)
trigger-feature { feature, allFeatures, mapKey, mapMeta } Store featureState + broadcast TRIGGER_FEATURE
reset-feature { featureId, mapKey } Delete featureState + broadcast RESET_FEATURE
update-features { features[], mapMeta } Store feature defs; update currentSceneView
lock-player { name } Per-player movement lock
unlock-player { name } Per-player movement unlock
lock-all — Lock all players globally
unlock-all — Unlock all players globally
blackout { active } Toggle blackout; broadcast BLACKOUT
play-audio { url, loop } Broadcast PLAY_AUDIO
stop-audio — Broadcast STOP_AUDIO
send-overlay { title, data, duration } Broadcast OVERLAY (popup on player screens)
sync-all-tokens { tokenState } Store full tokenState map for all maps; saveState()
trigger-attack { attacker, targets[] } Broadcast ATTACK_ANIMATION
update-objects { objects[], objectStates } Store + broadcast UPDATE_OBJECTS
object-interact { objId, state } Update single object state + broadcast OBJECT_STATE_CHANGE

Player → Server (action)

Action Payload Effect
player-login { name, cls } Sets ws.playerName; sends PLAYER_LOGIN_OK or PLAYER_LOGIN_ERR
move-player-token { id, x, y } Updates token position (ownership validated); auto-triggers features
player-dice-roll { die, result } To DM: PLAYER_DICE_ROLL; to other players: DICE_ROLL
request-sync — Calls sendFullState(ws) — re-delivers all current state
set-target { target } Player sets their own combat target (mob label or '' to clear)

Server → Clients (type)

Scene & Map

Type Payload Recipient
SHOW_SCENE_VIEW { image, audio, audioLoop, fogKey, fit, features, mapMeta } All
UPDATE_FOG { fogKey, cells } All
SET_FOG_KEY { fogKey } All
UPDATE_DRAWING { strokes[] } All
UPDATE_TOKENS { tokens[] } All
CLEAR_SCENE — All
CLEAR — All

Features & Objects

Type Payload Recipient
TRIGGER_FEATURE { feature, allFeatures, mapKey, mapMeta } All
RESET_FEATURE { featureId, mapKey } All
UPDATE_FEATURES { features[] } All
UPDATE_OBJECTS { objects[], objectStates } All
OBJECT_STATE_CHANGE { objId, state } All

Audio

Type Payload Recipient
PLAY_AUDIO { url, loop } All
STOP_AUDIO — All

Player & Movement

Type Payload Recipient
PLAYER_LOGIN_OK { name, cls } That player
PLAYER_LOGIN_ERR { reason } That player
LOGGED_IN_PLAYERS { players: [...names] } DM
MOVEMENT_LOCK { name, locked } All
MOVEMENT_LOCK_ALL { locked } All

Combat

Type Payload Recipient
SET_TARGET { player, target } All
ATTACK_ANIMATION { attacker, targets[] } All
DICE_ROLL { die, result } All players (anonymous)
PLAYER_DICE_ROLL { name, die, result } DM only

UI / Utility

Type Payload Recipient
OVERLAY { title, data, duration } All
BLACKOUT { active } All
DM_STATE_RESTORE Full state snapshot DM on reconnect
clients { count, names[] } DM

Server State Variables

Variable Description
currentSceneView Full SHOW_SCENE_VIEW payload; re-delivered on reconnect
currentTokens / currentTokensMapKey Active token array + map key
currentDrawing / currentDrawingMapKey Freehand strokes array
currentFogStates fogKey → fog grid (cell array)
currentFeatures / currentFeatureStates Feature definitions + triggered states
currentMapMeta { cols, rows } for the active map grid
allTokenStates mapKey → tokens array for all maps; persisted to data/state.json
loggedInPlayers Map of playerName → WebSocket
lockedPlayers Set of locked player names
allPlayersLocked Boolean — global movement lock
clients Set of all WebSocket connections
dmClients Set of authenticated DM WebSocket connections

Reconnect / Full State Restore

sendFullState(ws) re-delivers the complete scene state to a connecting client:

  • SHOW_SCENE_VIEW (current map, audio, fog key, features, map meta)
  • UPDATE_FOG (active fog grid)
  • UPDATE_TOKENS (current tokens)
  • UPDATE_DRAWING (current strokes)
  • UPDATE_FEATURES (feature definitions + triggered states)
  • UPDATE_OBJECTS (object definitions + states)
  • All targeting state (SET_TARGET for each active target)

DMs additionally receive DM_STATE_RESTORE which includes allTokenStates so the full token map is merged into the DM's local state.

Clone this wiki locally