UI

Worldshaper UI System Manual

Shared architecture for the engine, runtime, and editor

Design Manual

UI as a shared language between tools and play.

The editor should author UI definitions, the engine should render and manage them, and the game should supply live data plus behavior bindings. That keeps creation, execution, and meaning cleanly separated while still letting the same assets move directly from tooling into runtime.

Engine Owns runtime behavior: rendering, layout, focus, input, and theme systems.
Editor Owns authoring: visual layout, hierarchy editing, inspectors, and previews.
Game Owns meaning: opening windows, injecting data, and resolving action ids.

Overview

The system should support a workflow where the editor creates and modifies UI visually, saves UI definitions as assets, the game loads those assets at runtime, and the engine provides the shared UI runtime both sides depend on.

Core Rule

UI should be stored as data assets, not embedded directly in the editor and not hardcoded only in game code. The editor authors structure, the runtime executes it, and the game binds it to real gameplay state.

Recommended Split

  • Engine owns how UI works.
  • Editor owns how UI is authored.
  • Game runtime owns what the UI means.

Design Direction

  • Use a retained-mode UI system.
  • Store screens and windows as declarative assets.
  • Render them through shared HTML, CSS, and JavaScript runtime code.

Shared Asset Model

The editor should write structured UI data, and the game should read that same data through the engine runtime. This avoids arbitrary code generation and keeps assets portable, testable, and safe to evolve.

The Editor Should Save

  • layout
  • widget hierarchy
  • theme and style references
  • data-binding keys
  • symbolic action identifiers

The Editor Should Not Save

  • raw executable game logic
  • hardcoded runtime object instances
  • engine-internal transient state
  • function bodies embedded in assets

Package Layout

A package split like this keeps schema, runtime, editor, and game-facing code independent while still sharing a common vocabulary.

/packages
  /ui-schema
  /ui-runtime
  /ui-editor
  /game-runtime

ui-schema

  • UI node definitions
  • validation
  • schema versioning
  • migrations

ui-runtime

  • renderer
  • layout engine
  • window manager
  • widget registry
  • theme system

ui-editor

  • scene or workspace
  • selection tools
  • property inspector
  • asset browser
  • save and load flow

game-runtime

  • game-specific data providers
  • action handlers
  • UI asset loading
  • window orchestration

Engine

The engine should be the single owner of the UI runtime so the editor and game do not drift apart in behavior over time.

Responsibilities

  • window lifecycle
  • widget rendering
  • layout calculation
  • input routing
  • focus management
  • dragging and resizing behavior
  • modal behavior
  • z-order and activation
  • theming and skinning
  • serialization and asset loading hooks

Why It Belongs Here

  • accurate editor preview
  • fewer runtime and editor mismatches
  • one place to fix layout and interaction bugs
  • reusable widgets and themes

Core Runtime Systems

UI Manager

  • open windows
  • focus order
  • active modal
  • hovered and pressed widgets
  • drag and resize operations

Window Manager

  • create
  • close
  • minimize
  • maximize
  • bring to front
  • move
  • resize

Widget Registry

  • window
  • panel
  • label
  • button
  • input
  • list
  • tabs

Theme System

  • fonts
  • spacing
  • borders
  • colors
  • states
  • animation references

Runtime API

The engine should expose stable, high-level APIs that both the editor and the game can consume without caring about rendering internals.

ui.loadAsset("quest-log");
ui.createWindow(windowDefinition, bindings);
ui.closeWindow("quest-log");
ui.updateBindings("quest-log", bindings);
ui.createWindow({
  definition: windowDefinition,
  bindings: {
    data: gameViewModel,
    actions: actionRegistry
  }
});

Editor

The editor should be an authoring tool for UI assets, not a place where gameplay code gets embedded.

Responsibilities

  • create windows and widgets visually
  • arrange hierarchy
  • move and resize elements
  • edit properties
  • assign themes or style references
  • set data-binding keys
  • assign symbolic action identifiers
  • preview final layout using the shared runtime

Recommended Early Features

  • hierarchy tree
  • canvas or workspace
  • property inspector
  • theme picker
  • save and load
  • live preview

Editor Workflow

  1. Create or open a UI asset.
  2. Add a root node such as a window or screen.
  3. Add child widgets like panel, label, list, or button.
  4. Configure properties in an inspector.
  5. Save the asset as JSON.
  6. Preview the result using the same UI runtime the game uses.

Symbolic Actions

Instead of embedding code, a button should store a stable action id and let the game resolve it later.

{
  "action": "inventory.useSelectedItem"
}

Game Runtime

The game runtime consumes UI assets and supplies them with live data and behavior. It decides when a screen opens, what it displays, and how action ids map into actual game systems.

Responsibilities

  • deciding when UI opens or closes
  • selecting which asset to load
  • supplying live data
  • resolving symbolic actions into real functions
  • updating bindings as game state changes

Runtime Mutability

  • visibility
  • enabled state
  • bound text
  • bound lists
  • dynamic styling flags
  • open and closed state of windows

Consumption Flow

  1. Load a UI asset.
  2. Validate it through the shared schema layer.
  3. Create a runtime instance through the engine UI manager.
  4. Inject data bindings and action handlers.
  5. Let the engine handle rendering and interaction.

Example Usage

const definition = await ui.loadAsset("quest-log");

ui.createWindow({
  definition,
  bindings: {
    data: gameViewModel,
    actions: {
      "ui.closeWindow": ({ windowId }) => ui.closeWindow(windowId),
      "inventory.useSelectedItem": () => inventory.useSelectedItem()
    }
  }
});

UI Assets

UI assets should start as serializable JSON files. The format should be stable, versioned, and expressive enough to define hierarchy, layout, binding, and symbolic actions without containing gameplay logic.

Schema Goals

  • schema versioning
  • stable ids
  • nested hierarchy
  • typed widgets
  • layout properties
  • style references
  • data bindings
  • symbolic actions

Recommended Fields

  • schemaVersion
  • id
  • type
  • children
  • title, x, y, width, height
  • bind, visibleWhen, enabledWhen, action
  • theme, variant, className

Asset Example

A typical authored window should look like structured data the engine can interpret consistently in both the editor and the game.

{
  "schemaVersion": 1,
  "id": "quest-log",
  "type": "window",
  "title": "Quest Log",
  "x": 120,
  "y": 80,
  "width": 420,
  "height": 300,
  "flags": {
    "draggable": true,
    "resizable": true,
    "closable": true
  },
  "children": [
    {
      "id": "quest-list",
      "type": "list",
      "bind": "quests.active"
    },
    {
      "id": "close-button",
      "type": "button",
      "text": "Close",
      "action": "ui.closeWindow"
    }
  ]
}

Versioning

Every asset should declare a schema version so the format can evolve without breaking older editor output.

Migration Policy

When the asset format changes, add migration functions in the shared schema layer. The editor can write the newest version, while the game and engine can continue to load older assets by upgrading them during validation.

{
  "schemaVersion": 1
}

Long-Term Extensions

  • prefabs and templates
  • inherited style variants
  • animation descriptors
  • localization keys
  • responsive layout rules
  • asset references to icons and images