Skip to content

Level Editor

Status: Current Last reviewed: 2026-07-07 Source: client/src/admin/main.ts, client/admin.html, server/src/game/admin.ts, server/src/game/zonestore.ts, shared/src/prefabs.ts, shared/src/world.ts

/admin is a separate editor app, not part of normal gameplay. It is a free-fly scene editor with an object palette, transform tools, a property inspector, zone save/load, and playtest tools. Everything it changes is owned by the server.

Overview

The editor connects as a client, sends admin_login, and then issues admin_cmd messages. The server applies each command to the live ZoneData and broadcasts zone_object_update, so any connected game clients see the edit immediately. The editor renders every object individually (no instancing) so each one is pickable, and draws its own gizmos for invisible marker objects.

Editor Controls

Action Control
Fly W A S D, Q/E down/up, hold Shift for fast
Look Right mouse drag
Place Select a palette prefab, left-click the ground (Shift to place several)
Select Left-click an object
Move Drag a selected object across the ground
Rotate [ / ]
Scale + / -
Duplicate Cmd/Ctrl + D
Delete Delete / Backspace
Undo Cmd/Ctrl + Z
Cancel / deselect Esc

Grid snap (0.5 m) and rotation snap (15°) are toggles in the toolbar. Undo is a stack of inverse commands (create is undone by delete, and so on).

Object Palette

Prefabs are grouped by category, straight from the shared registry: buildings, village props, targets, lights, trees, nature, rocks, camp props, ember, NPCs, mobs, spawns, quest, loot, resources, volumes, audio, and portals. This covers houses, the smithy, bank, healer hut, training dummies, archery and magic targets, weapon racks, fences, crates, barrels, carts, wood piles, wells, banners, fire pits, torches and lanterns, trees, stumps, logs, bushes, mushrooms, rocks and boulders, goblin tents, cook pots, cages, trophy poles, bone piles, barricades, stakes, the ruined arch, the ember relay shrine, the cave gate, and every marker.

View Toggles

Toolbar checkboxes overlay editor-only debug geometry: colliders, marker gizmos, the safe-zone boundary, mob aggro/leash radii, and quest-trigger volumes.

Property Inspector

Selecting an object shows its editable properties: id (read-only), prefab, position X/Z, height offset, yaw in degrees, scale, collider kind, and a free-form JSON props block. The props block is where gameplay data lives, depending on prefab: npcId, npcName, role, dialogue, questIds for NPCs; variant, respawnSeconds for mob spawns; triggerId, radius for quest triggers; radius for safe zones; nodeType for resource nodes; targetZone for portals; plus free fields like faction and notes. Apply commits the change through an update_object command.

Save and Load

Button Effect
Save Zone Validates and writes server/data/zones/<id>.json, keeping a timestamped .bak.json of the prior version.
Reload From Disk Re-reads the file, discarding unsaved edits.
Export JSON Downloads the current in-memory zone.
Import JSON Loads a zone file into the live session (save to persist).

Validation (validateZoneData) checks the schema version, required fields, unique object ids, known prefabs, and finite positions before any write.

Zone Schema

A ZoneData document (schema version 2):

Field Meaning
schemaVersion Bumped when the shape changes; old files are backed up and regenerated.
zoneId, zoneName Identity.
worldSize Terrain extent in metres.
terrain { generator, seed }; the generator is a key into TERRAIN_GENERATORS.
environment Sky/fog colours and distances, sun and hemisphere light settings.
spawnPoint Player spawn { x, z, yaw } (also overridable by a player_spawn object).
villageCenter, campCenter, campLeashRadius Landmarks used by generation and AI.
objects The array of ZoneObjectInstance (see below).
nav Reserved for baked navigation/collision metadata.

Colliders, NPC definitions, mob spawns, quest triggers, target props, the safe zone, and the ember relays are all derived from objects by buildZoneRuntime. The editor never edits those derived lists directly; it edits the objects that produce them.

Prefab Schema

A PrefabDef in shared/src/prefabs.ts:

Field Meaning
id, name, category Identity and palette grouping.
collider null, { kind: 'circle', r }, or { kind: 'aabb', hx, hz } at scale 1.
blockHeight Height used for projectile blocking; 0 lets shots pass over.
instanced Client may batch these into one InstancedMesh.
marker Gameplay-only object, invisible in play, shown as a gizmo in the editor.
emberRelay Marks the relay prefab.
defaults Starting props for new instances.

Security

Auth lives in checkAdminToken:

  • If ADMIN_TOKEN is set on the server, the login token must match it.
  • If ADMIN_TOKEN is not set and NODE_ENV is production, admin is refused entirely.
  • Otherwise (local dev, no token set), connections from 127.0.0.1/::1 are accepted with any token.

Every admin_cmd is gated on conn.isAdmin; a normal player socket that sends one gets an error, not an action.

This is a stopgap

A single shared token is not real access control. The clear TODO is to put the editor behind proper account authentication and role checks once an account service exists. Do not expose /admin on a public build without at least an ADMIN_TOKEN.

Playtest Tools

Tool Command Effect
God Mode god_mode The admin player takes no damage.
Spawn Wave spawn_wave Spawns a ring of goblins at the camp (no respawn).
Reset Camp reset_camp Clears all goblins and respawns the marker-defined camp.
Reset Quests reset_quests Clears the admin's own quest log.
Set Ember set_ember Slider drives Ember pressure directly to any value.
Teleport teleport Fly-to shortcuts to the village, the camp, or the selected object.
Spawn / Despawn spawn_mob / despawn_entity Place or remove a single mob by id.

The performance and network overlays are in the game client (toggle in settings or press F3), not the editor.