Skip to content

Schema & Types

The @world-forge/schema package defines every type in a world project. This page covers the key types and validation rules.

The top-level container that holds an entire authored world:

interface WorldProject {
id: string;
name: string;
description: string;
version: string;
genre: string;
mode?: AuthoringMode; // dungeon | district | world | ocean | space | interior | wilderness
tones: string[];
difficulty: string;
narratorTone: string;
map: WorldMap;
zones: Zone[];
connections: ZoneConnection[];
districts: District[];
landmarks: Landmark[];
dialogues: DialogueDefinition[];
playerTemplate?: PlayerTemplate;
buildCatalog?: BuildCatalogDefinition;
progressionTrees: ProgressionTreeDefinition[];
factionPresences: FactionPresence[];
pressureHotspots: PressureHotspot[];
entityPlacements: EntityPlacement[];
itemPlacements: ItemPlacement[];
encounterAnchors: EncounterAnchor[];
spawnPoints: SpawnPoint[];
assets: AssetEntry[];
assetPacks: AssetPack[];
// ... crafting, market, visual layers
}

World Forge separates genre (fantasy, cyberpunk) from mode (dungeon, ocean, space). Genre is flavor — mode is scale. They are orthogonal: a cyberpunk dungeon and a pirate ocean are both valid.

type AuthoringMode = 'dungeon' | 'district' | 'world' | 'ocean' | 'space' | 'interior' | 'wilderness';

The mode field on WorldProject is optional — projects without it default to 'dungeon' everywhere. Mode governs:

  • Grid defaultscreateEmptyProject(mode) applies mode-specific width, height, and tile size
  • Connection vocabulary — each mode suggests relevant connection kinds (e.g., ocean uses channel/route, space uses docking/warp)
  • Object creation defaults — connections default to the mode’s primary kind (dungeon→door, ocean→channel), entities default to mode-appropriate role (dungeon→enemy, district→npc), encounters use mode-relevant types, and zones use mode-specific name patterns (Chamber, Waters, Sector, etc.)
  • Preset filtering — presets with modes arrays are hidden when incompatible with the current mode
  • Guide text — the checklist adapts step labels per mode (e.g., “Add a chamber” vs “Add a sea zone”)
  • Advisory validation — mode-specific suggestions (e.g., “Consider adding secret connections” for dungeons)
  • Speed Panel suggestions — mode-specific quick actions appear in a dedicated MODE section (e.g., “Add Secret Connection” for dungeons)
ModeGridTileKey Connections
dungeon30×2532door, stairs, passage, secret, hazard
district50×4032road, door, passage, portal
world80×6048road, portal, passage
ocean60×5048channel, route, portal, hazard
space100×8064docking, warp, passage, portal
interior20×1524door, stairs, passage, secret
wilderness60×5048trail, road, passage, hazard

A distinct area in the world with spatial coordinates, neighbors, and environmental properties:

  • gridX, gridY, gridWidth, gridHeight — position on the spatial grid
  • neighbors — IDs of adjacent zones
  • exits — labeled transitions with target zone IDs
  • light (0-10) and noise (0-10) — ambient levels
  • hazards — environmental dangers
  • interactables — objects players can inspect or use
  • parentDistrictId — which district this zone belongs to

Places an entity in a zone with optional authored data:

  • entityId, zoneId, role — identity, location, and role (npc/enemy/merchant/boss/companion)
  • name — display name (defaults to entityId)
  • stats — authored stat block (e.g., { vigor: 4, instinct: 3, will: 1 })
  • resources — resource pools (e.g., { hp: 12, stamina: 4 })
  • ai — AI profile override (e.g., { profileId: 'aggressive', goals: ['guard-crypt'] })
  • tags — additional tags merged with role defaults
  • dialogueId — links to a dialogue tree
  • custom — freeform metadata for companion abilities, personal goals, etc.

A branching conversation tree:

  • id — unique identifier
  • speakers — entity IDs involved in the conversation
  • entryNodeId — where the conversation starts
  • nodes — map of node ID to DialogueNode

Each DialogueNode has a speaker, text, and optional choices. Each DialogueChoice can have conditions (gates) and effects (state changes). Effects use DialogueEffect with a type, optional target (actor/target/zone), and params.

Defines the player character’s starting state:

  • name — display name (e.g., “Wanderer”)
  • baseStats, baseResources — starting stat/resource pools
  • startingInventory — item IDs placed in inventory at game start
  • startingEquipment — slot-to-item-ID map for equipped items
  • spawnPointId — where the player starts
  • defaultArchetypeId, defaultBackgroundId — optional build catalog refs

Character creation data for the engine:

  • archetypes — class-like choices with stat priorities, progression trees, granted verbs
  • backgrounds — origin stories with stat modifiers and faction modifiers
  • traits — perks and flaws with effects (stat-modifier, resource-modifier, grant-tag, verb-access, faction-modifier)
  • disciplines — specialized abilities with granted verbs, passives, and drawbacks
  • crossTitles — special titles granted by archetype + discipline combinations
  • entanglements — synergy effects between archetype and discipline

Skill/ability trees with:

  • currency — what resource is spent to unlock nodes (e.g., “xp”)
  • nodes — each with cost, optional requires (prerequisite node IDs), and effects

A single entry in the project’s asset manifest:

  • id — unique identifier
  • kindportrait, sprite, background, icon, or tileset
  • label — display name
  • path — relative path or URI to the media file
  • tags — freeform tags for filtering
  • packId — optional reference to an AssetPack.id
  • provenance — optional metadata (source, author, license, createdAt)

A named, versioned grouping of assets for portability:

  • id, label, version — identity and semver version
  • description — what this pack contains
  • tags, theme — categorization (e.g., dark-fantasy)
  • source — provenance (hand-drawn, ai-generated, stock)
  • license, author — ownership metadata
  • compatibility — optional PackCompatibility with minSchemaVersion and engineVersion

Assets reference their pack via packId. Deleting a pack cascades by clearing packId on all member assets.

assembleSceneData(zoneId, project) is a pure function that extracts all visual data bound to a zone into a single SceneData structure:

  • background/tileset — resolved asset or { id, missing: true } marker
  • entities — placements with resolved portrait/sprite assets and missing flags
  • landmarks — with resolved icon assets and missing flags
  • items — with resolved icon assets and missing flags
  • spawns — spawn points in this zone
  • ambient — ambient layers that include this zone
  • connections — connected zone names with optional conditions
  • light — the zone’s light level (0-10)

This is the data source for the editor’s Scene Preview component and can be used independently for testing or tooling.

The viewport.ts module provides pure math functions for 2D viewport transforms. No React, no DOM — just coordinate math.

interface ViewportState { panX: number; panY: number; zoom: number; }
interface WorldBounds { minX: number; minY: number; maxX: number; maxY: number; }

Transform model: screenX = (worldX - panX) * zoom, applied via ctx.setTransform(zoom, 0, 0, zoom, -panX * zoom, -panY * zoom).

FunctionPurpose
screenToWorldConvert screen pixel to world pixel coordinates
worldToScreenConvert world pixel to screen pixel coordinates
screenToGridConvert screen pixel to tile grid coordinates
computeContentBoundsCompute world-pixel bounding box of all authored content
fitBoundsToViewportCompute viewport that fits bounds into a canvas, centered
centerOnPointCompute viewport centered on a world point at current zoom
centerOnZoneCompute viewport that frames a specific zone with padding
zoomAtPointApply zoom delta while keeping cursor world-point stationary

Constants: MIN_ZOOM = 0.1, MAX_ZOOM = 5.0, DEFAULT_VIEWPORT = { panX: 0, panY: 0, zoom: 1 }.

validateProject() runs 54 structural checks:

  1. At least one spawn point exists
  2. At least one default spawn point
  3. Zone ID uniqueness
  4. District ID uniqueness
  5. Zone neighbors reference existing zones
  6. Symmetrical neighbor relationships
  7. District zone references exist
  8. Entity placements reference valid zones
  9. Item placements reference valid zones
  10. Spawn points reference valid zones
  11. Connections reference valid zones
  12. Landmarks reference valid zones
  13. Dialogue ID uniqueness
  14. Entry node exists in dialogue
  15. All nextNodeId references point to existing nodes
  16. No unreachable nodes in dialogue trees
  17. Entity dialogueId references existing dialogue
  18. Player template spawn point exists
  19. Starting inventory items exist in item placements
  20. Starting equipment items exist in item placements
  21. Default archetype exists in build catalog
  22. Default background exists in build catalog
  23. Archetype ID uniqueness + progression tree refs
  24. Background ID uniqueness
  25. Trait ID uniqueness + incompatibility refs
  26. Discipline ID uniqueness
  27. Cross-title archetype + discipline refs
  28. Entanglement archetype + discipline refs
  29. Progression tree ID uniqueness
  30. Node ID uniqueness within tree
  31. Required node refs exist
  32. Root node existence (at least one node without requirements)
  33. Asset ID uniqueness
  34. Asset path non-empty
  35. Zone background/tileset asset ref existence + kind match
  36. Entity portrait/sprite asset ref existence + kind match
  37. Item icon asset ref existence + kind match
  38. Landmark icon asset ref existence + kind match 39-42. Orphaned asset detection
  39. Pack ID uniqueness
  40. Pack label non-empty
  41. Pack version non-empty
  42. Asset packId references existing pack
  43. Orphaned pack detection (no assets reference this pack)
  44. Pack version format (semver x.y.z) 49-54. Encounter, faction, and pressure hotspot structural checks

advisoryValidation(project) returns mode-specific suggestions that never block export. These appear in the editor as a collapsible blue section below hard validation errors.

Each mode generates relevant suggestions — for example, dungeon mode suggests adding secret connections and trap hazards, ocean mode suggests channel connections and port zones. Universal suggestions (e.g., “add at least 2 zones”, “add connections between zones”) apply to all modes.

interface AdvisoryItem {
path: string; // e.g. 'connections' or 'zones'
message: string; // human-readable suggestion
severity: 'info' | 'suggestion';
}