diff --git a/docs/runtime-api-proposal.md b/docs/runtime-api-proposal.md deleted file mode 100644 index 3e18d9f..0000000 --- a/docs/runtime-api-proposal.md +++ /dev/null @@ -1,312 +0,0 @@ -# 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` -