A spatial world management platform built on the OpenSpatialWorld API. It provides a single discrete world with spatial data management — users can join, connect, and share the spatial world through a browser-based dashboard backed by a REST + WebSocket API.
packages/
wow-spec/ — OpenAPI schema (single source of truth for types and validation)
wow-backend/ — Express REST + WebSocket server (port 3000)
wow-frontend/ — Browser dashboard (served by the backend at /)
The three packages form a pipeline:
wow-spec ──▶ wow-frontend (openapi-fetch type-safe client)
wow-spec ──▶ wow-backend (express-openapi-validator + typed controllers)
wow-spec must always be built first. Its build step generates TypeScript types from schema.yaml via openapi-typescript, then copies the compiled output to dist/. Both other packages consume @wow/spec from that dist/ folder.
- Node.js 20 or later
- npm 10 or later
From the repository root, install all workspace dependencies in one step:
npm installBuild all three packages in the correct order (spec → frontend → backend):
npm run buildOr build each package individually:
npm run build:spec # generates types + compiles wow-spec
npm run build:frontend # bundles wow-frontend with Vite
npm run build:backend # compiles wow-backend with tscNote:
build:specmust be run beforebuild:frontendorbuild:backend, as both depend on the generated types inpackages/wow-spec/dist/.
Build and start the backend server in one command:
npm run startOr start the already-built backend directly (skips the build step):
npm run start:backendThe server starts on http://localhost:3000.
Opening that URL in a browser loads the frontend dashboard, which is compiled into packages/wow-frontend/dist/ and served as static files by the backend.
For active development, use the watch mode which automatically rebuilds all packages and restarts the server on any source file change:
npm run devThe browser will also reload automatically — when the server restarts after a rebuild, the existing WebSocket connection drops and reconnects, which triggers a full page reload to pick up the latest assets.
Watched file types: .ts, .yaml, .css, .html across all three package src/ directories.
All endpoints are documented in packages/wow-spec/src/schema.yaml.
| Method | Path | Description |
|---|---|---|
GET |
/ |
Browser dashboard (served as static HTML) |
GET |
/wow/world |
World status |
GET |
/wow/user/{userId} |
Get user by ID |
DELETE |
/wow/user/{userId} |
Delete user |
GET |
/wow/view/{viewId} |
Get view by ID |
GET |
/wow/portal/{portalId} |
Get portal by ID |
GET |
/wow/scene/node/{nodeId} |
Get scene node (includes full child subtree) |
POST |
/wow/scene/node/{nodeId} |
Add child nodes to a parent node |
PUT |
/wow/scene/node/{nodeId} |
Update a node |
DELETE |
/wow/scene/node/{nodeId} |
Delete a node and its entire subtree |
WS |
/events |
Real-time event stream |
Events are broadcast as JSON to all connected clients over ws://localhost:3000/events.
type |
Payload | Trigger |
|---|---|---|
user_joined |
{ user } |
A browser connects |
user_left |
{ userId } |
A browser disconnects |
node_created |
{ node } |
A node is added to the scene graph |
node_updated |
{ node } |
A node is updated |
node_deleted |
{ nodeId } |
A node and its subtree are deleted |
World state (nodes, users, views, portals) is persisted to packages/wow-backend/data/world_state.json. It is loaded on server startup and saved on graceful shutdown (SIGINT / SIGTERM).
Users created via WebSocket connections are not persisted — they represent live presence and are removed when the connection closes.
To rebuild individual packages after making changes:
# After editing wow-spec/src/schema.yaml:
npm run build:spec && npm run build:frontend && npm run build:backend
# After editing wow-backend/src/**:
npm run build:backend && npm run start:backend
# After editing wow-frontend/src/**:
npm run build:frontend
# Then reload the browser (no server restart needed)npm run format # check formatting across all packages
npm run format:write # auto-fix formatting