# Worldshaper Runtime API Proposal ## Goal Provide a stable HTTP API that a game engine can call to load Worldshaper-authored data without depending directly on editor-only JSON structure. This is different from the current editor API. The editor API is optimized for: - editing - saving - validation - editor UI state - internal content storage The runtime API should be optimized for: - loading the world into a game engine - streaming chunks as the player moves - fetching only the catalog data the engine actually needs - staying stable even if the editor changes internally ## Current State Worldshaper already exposes useful HTTP routes in [server.js](/D:/Programming/Worldshaper/server.js:2004), including: - `GET /api/world-default` - `GET /api/world/:worldId` - `GET /api/world/:worldId/chunks` - `GET /api/content/tiles` - `GET /api/content/sprites` - `GET /api/content/dialogues` - `GET /api/content/npc_templates` - `GET /api/images/:filename` That means the project already has the foundations for a runtime API. ## Why Not Use The Editor API Directly Some current payloads include editor concerns that a game engine should not be forced to understand. Examples: - world definitions contain `editorUi` - images are stored in editor-authored form in `images.json` - some content files may not always exist locally - route naming and response shape are editor-first, not engine-first Using those routes directly would tightly couple the engine to the editor's internal storage format. ## Recommendation Add a separate runtime-facing API namespace: - `GET /api/runtime/worlds` - `GET /api/runtime/worlds/:worldId` - `GET /api/runtime/worlds/:worldId/chunks` - `GET /api/runtime/catalog/tiles` - `GET /api/runtime/catalog/sprites` - `GET /api/runtime/catalog/npc-templates` - `GET /api/runtime/catalog/dialogues` - `GET /api/runtime/bundle/:worldId` This lets Worldshaper keep evolving internally while the engine targets a cleaner contract. ## Recommended V1 V1 should be small and practical. ### Startup Flow The engine should be able to: 1. fetch the default or selected world 2. fetch shared runtime catalogs once 3. fetch chunks on demand as the player moves ### Best First Endpoints #### `GET /api/runtime/worlds` Returns a lightweight world list. Example: ```json { "worlds": [ { "id": "overworld", "name": "Overworld Mock" } ] } ``` #### `GET /api/runtime/worlds/:worldId` Returns runtime-safe world metadata only. Example: ```json { "world": { "id": "overworld", "name": "Overworld Mock", "chunkWidth": 32, "chunkHeight": 32, "tileSize": 32, "backgroundColor": "#060A14", "defaultBackgroundTileId": "tile_5b6206b849", "spawn": { "x": 80, "y": 80 } } } ``` Do not include: - `editorUi` - editor layout metadata - editor-only presentation settings unless the engine truly uses them #### `GET /api/runtime/worlds/:worldId/chunks?chunkX=0&chunkY=0&radius=1` Returns chunk payloads around a center point. Example: ```json { "worldId": "overworld", "center": { "chunkX": 0, "chunkY": 0 }, "radius": 1, "chunks": [ { "chunkX": 0, "chunkY": 0, "width": 32, "height": 32, "backgroundTileId": "tile_5b6206b849", "roomLayers": [ { "layer": 0, "rows": ["................................"] }, { "layer": 1, "rows": [" "] } ], "heightLayers": [], "instances": [] } ] } ``` This is the most important runtime route. #### `GET /api/runtime/catalog/tiles` Returns tile definitions needed for world rendering. Example: ```json { "tiles": [ { "id": "tile_5b6206b849", "symbol": ".", "name": "Grass", "width": 16, "height": 16, "pixelScale": 2, "rows": ["................"] } ] } ``` #### `GET /api/runtime/catalog/sprites` Returns sprite definitions needed for entity rendering. Example: ```json { "sprites": [ { "id": "npc_human_style_01", "name": "Human Style 01 - Wide Hat Coat", "width": 16, "height": 16, "pixelScale": 2, "rows": ["................"] } ] } ``` #### `GET /api/runtime/catalog/npc-templates` Returns entity templates the engine can use to resolve placed instances. Example: ```json { "npcTemplates": [ { "id": "npc_gatekeeper_bubbles", "name": "Bubbles", "faction": "dangerous_gatekeeper", "spriteId": "npc_human_style_13", "defaultDialogueId": "dlg_npc_gatekeeper_bubbles" } ] } ``` #### `GET /api/runtime/catalog/dialogues` Returns runtime dialogue definitions. This may be enough for V1 if the engine can interpret the current dialogue node structure. If not, Worldshaper should add a runtime dialogue normalization step later. #### `GET /api/runtime/bundle/:worldId` Optional convenience endpoint. Returns: - runtime world metadata - tiles - sprites - npc templates - factions - dialogues This is useful for prototypes and early engine work. It may be too large for long-term world streaming, but it is a very good first integration endpoint. ## Suggested Runtime Data Rules The runtime API should follow these rules: - never expose editor layout/state unless the engine truly needs it - prefer explicit IDs over editor-specific structures - keep references stable: `tileId`, `spriteId`, `dialogueId`, `templateId` - return only what the engine needs to simulate and render - keep route names descriptive and runtime-oriented ## What The Engine Likely Needs Minimum likely needs: - world metadata - chunk geometry and layer rows - tile catalog - sprite catalog - instance template catalog - placed instances per chunk - dialogue definitions - factions or other lookup catalogs used by templates Maybe later: - items - abilities - monsters - loot tables - triggers - transitions - quest hooks ## Open Questions For The Engine Developer These should be answered before implementation: 1. Does the engine want raw JSON data from Worldshaper, or a normalized runtime contract? 2. Should the engine load the full world at startup, or stream chunks around the player? 3. Does the engine want graphics as row-based pixel data, or should Worldshaper also expose rendered asset URLs or atlas data? 4. Will the engine consume dialogues in the current node format, or does it need a simpler compiled dialogue format? 5. Does the engine need polling or version info so it can hot-reload changed data? ## Recommended Answer Unless the engine developer strongly objects, the best answer is: - normalized runtime contract - chunk streaming - row-based tile/sprite data first - existing dialogue format first - optional bundle endpoint for fast early integration ## Practical Next Step Before implementation, send your friend this exact question: > I can expose Worldshaper as a runtime API. Do you want a clean engine-facing contract with world metadata, chunk streaming, tiles, sprites, NPC templates, and dialogues, or do you want direct access to the raw editor JSON? If he says "clean engine-facing contract", V1 should target: - `GET /api/runtime/worlds/:worldId` - `GET /api/runtime/worlds/:worldId/chunks` - `GET /api/runtime/catalog/tiles` - `GET /api/runtime/catalog/sprites` - `GET /api/runtime/catalog/npc-templates` - `GET /api/runtime/catalog/dialogues` - optional `GET /api/runtime/bundle/:worldId`