Skip to content

Configuration ​

SHAG has three distinct configuration concerns: build-time game code, loose-asset paths, and server/lobby environment.

Build-time game selection ​

vite.config.ts selects the Vite @game alias from GAME, falling back to public/engine.json.defaultGame.

powershell
$env:GAME = 'fps'
npm run dev

Game selection is only partly generic: tsconfig.json maps @game/* to src/games/fps/*, and src/main.ts directly composes the FPS game. A new selected game therefore needs bootstrap and TypeScript wiring, not just an environment variable.

Engine code should not import @game; keep that dependency in application/game composition.

Game-owned HUD styling ​

The FPS HUD theme lives in src/games/fps/client/hud/styles/WashikiTheme.css. FPSHud imports it as a raw stylesheet and injects it through UIStyles before creating the widgets. Edit game HUD appearance there. The engine's generic HUD manager separately loads src/engine/ui/hud/styles/HUD.css.

Shared font assets remain under /engine/fonts/. Engine UI components can consume the game's CSS variables through their existing fallbacks; the engine does not import the FPS stylesheet.

engine.json and GamePaths ​

public/engine.json is required by browser startup and is injected explicitly by the headless composition:

text
defaultGame: fps
engineAssetsPath: /engine

The file is JSON; the values above describe the currently committed configuration.

GamePaths builds:

HelperCurrent shape
game(path)/games/<id>/<path>
engine(path)/engine/<path> by default
maps/textures/prefabs/data/music/fontsconvenience paths below the loose game root
ts
// From src/main.ts
import { GamePaths } from './engine/core/GamePaths';

const paths = GamePaths.getInstance();
await paths.init();
console.log(paths.game('models/example.glb'));

The FPS PK3 pipeline is separate and primarily reads public/data/. Do not change PK3 lookup to GamePaths.data().

External game data ​

text
public/data/
  *.pk3
  pk3_manifest.json
  ktx2cache/
bash
npm run tools:manifest
npm run tools:textures

public/data/, public/games/, PK3 files, and generated media are ignored. A clean checkout needs external compatible assets.

Browser preferences ​

Saved cvars and binding overrides are validated when loaded. Invalid entries fall back to declared defaults; other valid preferences remain usable. Explicit empty binding arrays still mean unbound. Storage failures leave changes working for the session, and Settings displays "Session only · could not save" until the affected preferences can be saved successfully. These preferences are separate from account-key recovery; heed Profile's account-key warning too.

Networking environment ​

Copy and review .env.example, which lists every variable below.

VariableOwnerWhat it does
VITE_LOBBY_URLbrowserLobby socket the client connects to
VITE_PK3_MIRROR_URLbrowserHTTP mirror pk3 packages are downloaded from when it has them; unset, they come from the game's own server (PK3 filesystem)
SHAG_PUBLIC_GAME_PROTOCOL / SHAG_PUBLIC_GAME_HOSTlobbyThe address the lobby advertises for spawned game servers
SERVER_DATA_DIRlobby, bot serverWhere players.db and the shared bot secret live; --data-dir wins over it
BOT_SECRETlobby, bot serverProves a bot connection; written into the data directory when unset
BOT_SERVER_URLlobbyBot control socket the lobby asks for bots
LOBBY_BOT_CONNECT_URLlobbyLobby URL a spawned bot connects back to
SHAG_SPAWN_TIMEOUT_MSlobbyHow long to wait for a spawned server to report ready (default 45s, clamped to 5s–5min)
SHAG_LOBBY_MAX_PLAYERSlobbyPlayers online at once, bots not counted; 0 for no cap (default 64). --max-players wins over it
SHAG_MATCH_ADMISSION / SHAG_MATCH_RESULT_SECRET / SHAG_MATCH_RESULT_OUTBOXspawned serverThat match's seat manifest, the secret its result line is signed with, and the file the signed result is also written to; the lobby sets all three per match
SHAG_TIMELIMIT / SHAG_WARMUP / SHAG_SCORELIMITgame serverMatch rule overrides; a bare number is minutes for the time limit and seconds for warmup, and either takes an s/m suffix
SHAG_GAME_CERT_PATH / SHAG_GAME_KEY_PATHspawned serverTLS files for a direct wss:// socket
GAME_PATHheadlessAsset-directory override
BOT_NAV_CACHE_DIR / BOT_GOAL_ARBITERbot serverNavigation cache directory and goal-arbiter selection
VITE_SHAGGED_API_URL, SHAGGED_*editor, map serviceThe SHAGGED map service address, map root and compiler paths, each described in .env.example

Only VITE_* variables are exposed to browser code; the rest are read by Node processes only.

UI and game metadata ​

src/games/fps/game.json contains FPS metadata. Optional loose game config/UI/HUD paths exist in GamePaths, but the active direct FPS bootstrap does not imply every optional file is loaded.

Keep secrets and machine-local paths out of Vite-exposed variables and source-controlled configuration.

Released under the MIT License.