Run request analysis on demand on the VPS
This commit is contained in:
parent
9f9b13aa01
commit
d899e902a0
21 changed files with 2485 additions and 4 deletions
107
docs/kb/README.md
Normal file
107
docs/kb/README.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# Worldshaper KB Scaffold
|
||||
|
||||
This folder is the first pass of an internal knowledge base for Worldshaper.
|
||||
|
||||
It is meant to support three jobs:
|
||||
|
||||
1. Human onboarding.
|
||||
2. Faster request triage.
|
||||
3. Grounded local-LLM analysis for the Requests queue.
|
||||
|
||||
The goal is to give request-processing tools stable system summaries instead of asking a model to infer editor behavior from raw user text alone.
|
||||
|
||||
## Layout
|
||||
|
||||
- `systems.json`
|
||||
- Machine-readable system index.
|
||||
- `request-analysis-schema.json`
|
||||
- JSON schema for structured request parsing output.
|
||||
- `queue-workflow.md`
|
||||
- First-pass automation and review flow.
|
||||
- `systems/*.md`
|
||||
- Human-readable system notes, organized by editor subsystem.
|
||||
|
||||
## Current System Coverage
|
||||
|
||||
The scaffold currently covers:
|
||||
|
||||
- Launcher home and tabbed board
|
||||
- Requests intake and request state handling
|
||||
- Studio bootstrap and world loading
|
||||
- Chunk storage and neighborhood streaming
|
||||
- Layers and tile editing
|
||||
- Graphics Painter
|
||||
- Rendering and viewport behavior
|
||||
- World Overview
|
||||
- Persistence and save pipeline
|
||||
- Floating windows and popout shell
|
||||
- Content catalog and record APIs
|
||||
|
||||
## How To Use This For Request Analysis
|
||||
|
||||
Suggested queue flow:
|
||||
|
||||
1. Pull a raw request submission from the launcher request store.
|
||||
2. Retrieve likely systems from `systems.json` using tags, aliases, and file names.
|
||||
3. Provide the matching `systems/*.md` files to the local model as context.
|
||||
4. Ask the model to split the submission into atomic requests.
|
||||
5. Require output that matches `request-analysis-schema.json`.
|
||||
6. Validate the JSON before storing anything back into the app.
|
||||
7. Auto-promote only high-confidence items. Keep low-confidence items in review.
|
||||
|
||||
## Recommended Next Additions
|
||||
|
||||
- Add concrete file-level notes for major controllers as they evolve.
|
||||
- Add a small extractor script that refreshes endpoint lists from `server.js`.
|
||||
- Add examples of well-tagged historical requests for few-shot prompting.
|
||||
- Add confidence thresholds and retry rules for malformed model output.
|
||||
|
||||
## Current Automation Entry Point
|
||||
|
||||
Use the queue worker with:
|
||||
|
||||
```bash
|
||||
npm run analyze:requests
|
||||
```
|
||||
|
||||
The worker expects:
|
||||
|
||||
- the Worldshaper API server to be running
|
||||
- a model endpoint and API key
|
||||
- KB files from this folder
|
||||
|
||||
### DeepSeek Setup
|
||||
|
||||
The worker now supports DeepSeek directly.
|
||||
|
||||
Recommended environment:
|
||||
|
||||
```powershell
|
||||
$env:DEEPSEEK_API_KEY="your-key-here"
|
||||
```
|
||||
|
||||
Defaults when `DEEPSEEK_API_KEY` is present:
|
||||
|
||||
- provider: `deepseek`
|
||||
- base URL: `https://api.deepseek.com`
|
||||
- model: `deepseek-v4-flash`
|
||||
- JSON mode: enabled
|
||||
- thinking: disabled
|
||||
|
||||
You can override the model if you want:
|
||||
|
||||
```powershell
|
||||
$env:REQUEST_ANALYZER_MODEL="deepseek-v4-pro"
|
||||
```
|
||||
|
||||
## Suggested Review Rules
|
||||
|
||||
- If the model produces multiple atomic requests from one submission, keep the original submission id on every derived item.
|
||||
- If a request touches multiple systems, prefer one primary category and many tags.
|
||||
- If the request is really a bug report, preserve the problem statement and write the implementation note as a likely fix path, not a promise.
|
||||
- If the model cannot confidently map a request, store it as `needs_review` instead of forcing a category.
|
||||
|
||||
## Notes
|
||||
|
||||
- This scaffold is grounded to the repo layout on 2026-06-26.
|
||||
- It is intentionally incomplete. Treat it as a maintained map, not generated truth.
|
||||
130
docs/kb/queue-workflow.md
Normal file
130
docs/kb/queue-workflow.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# Request Queue Workflow
|
||||
|
||||
This document describes a practical first pass for automated request analysis using the KB scaffold.
|
||||
|
||||
## Goal
|
||||
|
||||
Turn raw launcher submissions into structured request items that are:
|
||||
|
||||
- titled
|
||||
- categorized
|
||||
- tagged
|
||||
- explained in plain language
|
||||
- paired with a realistic implementation approach
|
||||
|
||||
## Recommended Pipeline
|
||||
|
||||
1. Read one pending submission.
|
||||
2. Split it into candidate atomic requests.
|
||||
3. Retrieve likely systems from `docs/kb/systems.json`.
|
||||
4. Load the matching `docs/kb/systems/*.md` files.
|
||||
5. Ask the local model for JSON that matches `docs/kb/request-analysis-schema.json`.
|
||||
6. Validate the JSON.
|
||||
7. Promote high-confidence items and hold low-confidence items for review.
|
||||
|
||||
## Suggested Confidence Rules
|
||||
|
||||
- `>= 0.85`
|
||||
- auto-promote to active
|
||||
- `0.65 - 0.84`
|
||||
- store as needs review
|
||||
- `< 0.65`
|
||||
- keep as pending or send to manual triage
|
||||
|
||||
## Retrieval Hints
|
||||
|
||||
Search `systems.json` using:
|
||||
|
||||
- request text
|
||||
- obvious UI words like "layer", "chunk", "overview", "graphics", "animation"
|
||||
- aliases
|
||||
- past tags from similar requests
|
||||
|
||||
If a submission touches multiple subsystems, feed the model the top two to four matching docs instead of the whole KB.
|
||||
|
||||
## Prompt Skeleton
|
||||
|
||||
Use a strict instruction similar to this:
|
||||
|
||||
```text
|
||||
You are processing Worldshaper editor requests.
|
||||
|
||||
You must:
|
||||
- split the submission into one or more atomic requests
|
||||
- assign one primary category per item
|
||||
- assign tags grounded in the provided KB
|
||||
- write a short descriptive title
|
||||
- explain the user intent in plain language
|
||||
- propose a likely implementation path
|
||||
- avoid inventing systems that are not in the KB
|
||||
- return only valid JSON matching the provided schema
|
||||
|
||||
If you are unsure, lower confidence and use statusRecommendation = "needs_review".
|
||||
```
|
||||
|
||||
Then provide:
|
||||
|
||||
- the raw submission
|
||||
- the JSON schema
|
||||
- the retrieved KB docs
|
||||
|
||||
## Good First Storage Shape
|
||||
|
||||
Keep the existing launcher request record, but add optional analysis metadata:
|
||||
|
||||
- `analysisStatus`
|
||||
- `analysisConfidence`
|
||||
- `analysisModel`
|
||||
- `analysisCreatedAt`
|
||||
- `analysisUpdatedAt`
|
||||
- `analysisPayload`
|
||||
|
||||
This lets you keep the current user-facing `pending` and `active` states while adding a back-office workflow.
|
||||
|
||||
## First Implementation Target
|
||||
|
||||
The simplest useful worker would:
|
||||
|
||||
1. read pending requests from the launcher request API/store
|
||||
2. analyze one request at a time
|
||||
3. write structured analysis back to the same store
|
||||
4. never delete the original `sourceText`
|
||||
|
||||
The current first-pass implementation is:
|
||||
|
||||
```bash
|
||||
npm run analyze:requests
|
||||
```
|
||||
|
||||
Useful environment variables:
|
||||
|
||||
- `REQUEST_ANALYZER_API_BASE`
|
||||
- `REQUEST_ANALYZER_PROVIDER`
|
||||
- `REQUEST_ANALYZER_MODEL_BASE_URL`
|
||||
- `REQUEST_ANALYZER_MODEL`
|
||||
- `REQUEST_ANALYZER_API_KEY`
|
||||
- `REQUEST_ANALYZER_MAX_TOKENS`
|
||||
- `REQUEST_ANALYZER_THINKING`
|
||||
- `REQUEST_ANALYZER_PROMOTE_THRESHOLD`
|
||||
- `DEEPSEEK_API_KEY`
|
||||
|
||||
DeepSeek path:
|
||||
|
||||
- set `DEEPSEEK_API_KEY`
|
||||
- leave the provider on its default auto-detect setting
|
||||
- the worker will use DeepSeek-hosted chat completions automatically
|
||||
|
||||
Behavior:
|
||||
|
||||
- high-confidence all-active results replace the pending submission with active request rows
|
||||
- mixed or lower-confidence results stay on the pending submission as review metadata
|
||||
- failures are stored as analysis errors instead of silently disappearing
|
||||
|
||||
## What Not To Automate First
|
||||
|
||||
- automatic deletion
|
||||
- automatic deduplication with destructive merges
|
||||
- direct code generation
|
||||
- automatic schema migrations
|
||||
|
||||
The first win is dependable triage, not full autonomy.
|
||||
115
docs/kb/request-analysis-schema.json
Normal file
115
docs/kb/request-analysis-schema.json
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://worldshaper.local/schemas/request-analysis.schema.json",
|
||||
"title": "Worldshaper Request Analysis Result",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"submissionId",
|
||||
"sourceText",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"submissionId": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"sourceText": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"title",
|
||||
"primaryCategory",
|
||||
"tags",
|
||||
"statusRecommendation",
|
||||
"parsedInterpretation",
|
||||
"implementationApproach",
|
||||
"confidence"
|
||||
],
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 3,
|
||||
"maxLength": 120
|
||||
},
|
||||
"primaryCategory": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"statusRecommendation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"active",
|
||||
"needs_review",
|
||||
"duplicate",
|
||||
"blocked"
|
||||
]
|
||||
},
|
||||
"parsedInterpretation": {
|
||||
"type": "string",
|
||||
"minLength": 20
|
||||
},
|
||||
"implementationApproach": {
|
||||
"type": "string",
|
||||
"minLength": 20
|
||||
},
|
||||
"affectedSystems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"affectedFiles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"problemType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"feature",
|
||||
"bug",
|
||||
"workflow",
|
||||
"performance",
|
||||
"ux",
|
||||
"content",
|
||||
"unknown"
|
||||
]
|
||||
},
|
||||
"rawExcerpt": {
|
||||
"type": "string"
|
||||
},
|
||||
"confidence": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
138
docs/kb/systems.json
Normal file
138
docs/kb/systems.json
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"generatedFromRepoDate": "2026-06-26",
|
||||
"systems": [
|
||||
{
|
||||
"id": "launcher-home",
|
||||
"name": "Launcher Home",
|
||||
"docPath": "docs/kb/systems/launcher-home.md",
|
||||
"aliases": ["launcher", "main page", "home page", "landing page"],
|
||||
"tags": ["Launcher", "News", "Requests", "Presentation"],
|
||||
"uiSurfaces": ["Launcher hero", "News tab", "Requests tab"],
|
||||
"keyFiles": ["src/WorldshaperLauncher.tsx", "src/index.css", "src/worldshaperStudio/windowing.ts"],
|
||||
"apiEndpoints": ["/api/world-default", "/api/launcher-requests"],
|
||||
"relatedSystems": ["request-board", "floating-window-shell"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "request-board",
|
||||
"name": "Request Board",
|
||||
"docPath": "docs/kb/systems/request-board.md",
|
||||
"aliases": ["requests", "request queue", "request intake", "request board"],
|
||||
"tags": ["Requests", "Launcher", "Workflow", "Moderation"],
|
||||
"uiSurfaces": ["Launcher Requests tab"],
|
||||
"keyFiles": ["src/WorldshaperLauncher.tsx", "server.js", "data/launcher_requests.json"],
|
||||
"apiEndpoints": ["/api/launcher-requests", "/api/launcher-requests/:requestId"],
|
||||
"relatedSystems": ["launcher-home"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "world-bootstrap",
|
||||
"name": "Studio Bootstrap",
|
||||
"docPath": "docs/kb/systems/world-bootstrap.md",
|
||||
"aliases": ["bootstrap", "startup", "world load", "initial load"],
|
||||
"tags": ["Bootstrap", "Worlds", "Chunks", "Startup"],
|
||||
"uiSurfaces": ["Studio window"],
|
||||
"keyFiles": ["src/worldshaperStudio/bootstrap.ts", "src/worldshaperStudio/main.ts", "src/worldshaperStudio/runtime.ts"],
|
||||
"apiEndpoints": ["/api/world-default", "/api/world/:worldId", "/api/world/:worldId/bookmarks", "/api/world/:worldId/chunks"],
|
||||
"relatedSystems": ["chunk-storage-streaming", "floating-window-shell", "content-catalog-records"],
|
||||
"priorityForRequestTriage": "medium"
|
||||
},
|
||||
{
|
||||
"id": "chunk-storage-streaming",
|
||||
"name": "Chunk Storage And Streaming",
|
||||
"docPath": "docs/kb/systems/chunk-storage-streaming.md",
|
||||
"aliases": ["chunks", "chunk loading", "world streaming", "chunk cache", "world neighborhood"],
|
||||
"tags": ["Chunks", "Streaming", "Worlds", "Performance"],
|
||||
"uiSurfaces": ["World editor viewport", "World mode"],
|
||||
"keyFiles": ["server.js", "src/worldChunking.ts", "src/worldshaperStudio/bootstrap.ts", "src/worldshaperStudio/runtime.ts"],
|
||||
"apiEndpoints": ["/api/world/:worldId/chunk/:chunkX/:chunkY", "/api/world/:worldId/chunks", "/api/world/:worldId/chunks/batch-save"],
|
||||
"relatedSystems": ["world-bootstrap", "rendering-viewport", "persistence-save-pipeline", "world-overview"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "layers-tile-editing",
|
||||
"name": "Layers And Tile Editing",
|
||||
"docPath": "docs/kb/systems/layers-tile-editing.md",
|
||||
"aliases": ["layers", "tile painting", "height layers", "brushes", "eraser"],
|
||||
"tags": ["Layers", "Tiling", "Editing", "Height Layers"],
|
||||
"uiSurfaces": ["Layers sidebar", "Canvas tools", "Viewport"],
|
||||
"keyFiles": ["src/worldshaperStudio/interactionController.ts", "src/worldshaperStudio/runtime.ts", "src/worldshaperStudio/sidebarController.ts", "src/worldshaperStudio/mapDocumentController.ts", "src/worldshaperStudio/popupSessionStore.ts"],
|
||||
"apiEndpoints": ["/api/world/:worldId/chunks/batch-save"],
|
||||
"relatedSystems": ["chunk-storage-streaming", "rendering-viewport", "content-catalog-records"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "graphics-painter",
|
||||
"name": "Graphics Painter",
|
||||
"docPath": "docs/kb/systems/graphics-painter.md",
|
||||
"aliases": ["graphic painter", "graphics painter", "tile art", "sprite painter", "animation painter"],
|
||||
"tags": ["Graphics Painter", "Animation", "Tiles", "Sprites"],
|
||||
"uiSurfaces": ["Graphic Painter window", "Animation preview"],
|
||||
"keyFiles": ["src/worldshaperStudio/tileArtEditorWindowController.ts", "src/worldshaperStudio/graphicsDocumentHelpers.ts", "src/worldshaperStudio/importController.ts", "src/worldshaperStudio/dom.ts"],
|
||||
"apiEndpoints": ["/api/content/images", "/api/content/sprites", "/api/content/tiles", "/api/images", "/api/images/:filename"],
|
||||
"relatedSystems": ["content-catalog-records", "floating-window-shell", "rendering-viewport"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "rendering-viewport",
|
||||
"name": "Rendering And Viewport",
|
||||
"docPath": "docs/kb/systems/rendering-viewport.md",
|
||||
"aliases": ["renderer", "pixi", "viewport", "camera", "draw", "chunk culling"],
|
||||
"tags": ["Rendering", "Viewport", "Pixi", "Performance"],
|
||||
"uiSurfaces": ["World canvas", "Debug overlay"],
|
||||
"keyFiles": ["src/worldshaperStudio/renderController.ts", "src/worldshaperStudio/pixiTileStageController.ts", "src/worldshaperStudio/pixiSceneRebuildHelpers.ts", "src/worldshaperStudio/pixiChunkSurfaceHelpers.ts", "src/worldshaperStudio/overlayRenderer.ts"],
|
||||
"apiEndpoints": [],
|
||||
"relatedSystems": ["chunk-storage-streaming", "layers-tile-editing", "world-overview"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "world-overview",
|
||||
"name": "World Overview",
|
||||
"docPath": "docs/kb/systems/world-overview.md",
|
||||
"aliases": ["overview", "world overview", "chunk overview", "overview map"],
|
||||
"tags": ["World Overview", "Chunks", "Bookmarks", "Navigation"],
|
||||
"uiSurfaces": ["World Overview window"],
|
||||
"keyFiles": ["src/worldshaperStudio/worldOverviewWindowController.ts", "src/worldshaperStudio/dom.ts", "server.js"],
|
||||
"apiEndpoints": ["/api/world/:worldId/overview", "/api/world/:worldId/bookmarks"],
|
||||
"relatedSystems": ["chunk-storage-streaming", "layers-tile-editing", "floating-window-shell"],
|
||||
"priorityForRequestTriage": "high"
|
||||
},
|
||||
{
|
||||
"id": "persistence-save-pipeline",
|
||||
"name": "Persistence And Save Pipeline",
|
||||
"docPath": "docs/kb/systems/persistence-save-pipeline.md",
|
||||
"aliases": ["save", "saving", "persist", "world save", "content save"],
|
||||
"tags": ["Persistence", "Saving", "APIs", "Worlds", "Content"],
|
||||
"uiSurfaces": ["Toolbar save flow", "Status messages"],
|
||||
"keyFiles": ["src/worldshaperStudio/persistenceController.ts", "src/worldshaperStudio/historyController.ts", "src/worldshaperStudio/historyStateStore.ts", "server.js"],
|
||||
"apiEndpoints": ["/api/world/:worldId/chunks/batch-save", "/api/content/:type", "/api/editor-settings", "/api/catalog-meta"],
|
||||
"relatedSystems": ["chunk-storage-streaming", "content-catalog-records"],
|
||||
"priorityForRequestTriage": "medium"
|
||||
},
|
||||
{
|
||||
"id": "floating-window-shell",
|
||||
"name": "Floating Window Shell",
|
||||
"docPath": "docs/kb/systems/floating-window-shell.md",
|
||||
"aliases": ["floating window", "popout", "windowing", "tool windows"],
|
||||
"tags": ["Windows", "UI", "Launcher", "Tooling"],
|
||||
"uiSurfaces": ["Studio popout", "Tool windows", "Overlay layer"],
|
||||
"keyFiles": ["src/worldshaperStudio/windowing.ts", "src/worldshaperStudio/floatingWindowUtils.ts", "src/worldshaperStudio/toolWindowController.ts", "src/worldshaperStudio/changelogSplashWindowController.ts", "src/worldshaperStudio/engineOverrideWindowController.ts"],
|
||||
"apiEndpoints": [],
|
||||
"relatedSystems": ["launcher-home", "graphics-painter", "world-overview"],
|
||||
"priorityForRequestTriage": "medium"
|
||||
},
|
||||
{
|
||||
"id": "content-catalog-records",
|
||||
"name": "Content Catalog And Records",
|
||||
"docPath": "docs/kb/systems/content-catalog-records.md",
|
||||
"aliases": ["content", "tiles", "sprites", "images", "catalog", "records"],
|
||||
"tags": ["Content", "Tiles", "Sprites", "Images", "Schemas"],
|
||||
"uiSurfaces": ["Content records", "Graphic Painter inputs", "Tile palette"],
|
||||
"keyFiles": ["server.js", "src/App.tsx", "src/components/worldshaperShared.ts", "src/worldshaperStudio/graphicsDocumentHelpers.ts", "src/worldshaperStudio/importController.ts"],
|
||||
"apiEndpoints": ["/api/content/:type", "/api/content/tiles/:tileId/delete", "/api/content/sprites/:spriteId/delete", "/api/catalog-meta", "/api/images", "/api/images/:filename"],
|
||||
"relatedSystems": ["graphics-painter", "layers-tile-editing", "persistence-save-pipeline"],
|
||||
"priorityForRequestTriage": "medium"
|
||||
}
|
||||
]
|
||||
}
|
||||
48
docs/kb/systems/chunk-storage-streaming.md
Normal file
48
docs/kb/systems/chunk-storage-streaming.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Chunk Storage And Streaming
|
||||
|
||||
## What It Does
|
||||
|
||||
World data is stored as per-chunk JSON files and loaded into the editor as chunk neighborhoods around a center chunk. The runtime caches chunk payloads, shifts neighborhoods as the viewport moves, and saves dirty chunks in batches.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `server.js`
|
||||
- `src/worldChunking.ts`
|
||||
- `src/worldshaperStudio/bootstrap.ts`
|
||||
- `src/worldshaperStudio/runtime.ts`
|
||||
- `src/worldshaperStudio/persistenceController.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/world/:worldId/chunk/:chunkX/:chunkY`
|
||||
- `POST /api/world/:worldId/chunk/:chunkX/:chunkY`
|
||||
- `GET /api/world/:worldId/chunks`
|
||||
- `POST /api/world/:worldId/chunks/batch-save`
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- chunks are stored as `content/worlds/<worldId>/chunks/<x>_<y>.json`
|
||||
- world neighborhoods are requested as a square around a center chunk
|
||||
- runtime keeps a chunk cache and tracks dirty chunk keys
|
||||
- chunk payloads include `roomLayers`, `heightLayers`, `instances`, and optional `backgroundTileId`
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- Exact chunk lookup is grid-based and direct.
|
||||
- The editor does not load the entire world for normal editing.
|
||||
- Small tile edits must sync back into the correct cached chunk.
|
||||
- Save flow should preserve chunk-local edits without rebuilding unrelated chunks.
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- chunk loading speed
|
||||
- chunk streaming behavior
|
||||
- per-chunk backgrounds
|
||||
- chunk transforms, duplication, deletion
|
||||
- performance questions around indexing and caching
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the request about storage, fetch patterns, cache behavior, or save behavior?
|
||||
- Does it affect only visible chunks or the full world?
|
||||
- Is the user asking for chunk-local data, or freeform world overlays that break chunk assumptions?
|
||||
51
docs/kb/systems/content-catalog-records.md
Normal file
51
docs/kb/systems/content-catalog-records.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Content Catalog And Records
|
||||
|
||||
## What It Does
|
||||
|
||||
This subsystem manages tiles, sprites, images, and related metadata. It is the bridge between authored graphics data and the editor features that paint, preview, import, and delete those records.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `server.js`
|
||||
- `src/App.tsx`
|
||||
- `src/components/worldshaperShared.ts`
|
||||
- `src/worldshaperStudio/graphicsDocumentHelpers.ts`
|
||||
- `src/worldshaperStudio/importController.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/content/:type`
|
||||
- `POST /api/content/:type`
|
||||
- `POST /api/content/tiles/:tileId/delete`
|
||||
- `POST /api/content/sprites/:spriteId/delete`
|
||||
- `GET /api/catalog-meta`
|
||||
- `POST /api/catalog-meta`
|
||||
- `GET /api/images`
|
||||
- `GET /api/images/:filename`
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- tiles and sprites are content records, not world chunk records
|
||||
- tile symbols are used heavily by painting and rendering paths
|
||||
- deleting tiles or sprites can require scrubbing world references
|
||||
- catalog metadata can influence grouping and presentation
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- content ids must stay stable if worlds reference them
|
||||
- deletion flows need to consider world data cleanup
|
||||
- image availability affects painter previews and imports
|
||||
- schema drift here can break multiple editor systems at once
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- better tile metadata
|
||||
- sprite or tile deletion behavior
|
||||
- import and catalog organization
|
||||
- richer animation metadata on graphics records
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the request about the content record itself, or how it is used in-world?
|
||||
- Will this require schema changes to tiles or sprites?
|
||||
- Could this impact rendering, painting, and save behavior all at once?
|
||||
44
docs/kb/systems/floating-window-shell.md
Normal file
44
docs/kb/systems/floating-window-shell.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# Floating Window Shell
|
||||
|
||||
## What It Does
|
||||
|
||||
Worldshaper relies on separate floating windows and internal popout shells for several tools. This subsystem defines how the main studio window opens, how internal tool windows are placed, and how overlay-layer tools are managed inside the editor.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/windowing.ts`
|
||||
- `src/worldshaperStudio/floatingWindowUtils.ts`
|
||||
- `src/worldshaperStudio/toolWindowController.ts`
|
||||
- `src/worldshaperStudio/changelogSplashWindowController.ts`
|
||||
- `src/worldshaperStudio/engineOverrideWindowController.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- none directly
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- the launcher opens the studio in a new browser window
|
||||
- many studio tools use internal popout shells layered above the editor
|
||||
- floating window state may be persisted per tool
|
||||
- focus, z-index, clamp-to-viewport, and drag behavior all live here
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- popup blocking can break launch
|
||||
- tool windows should stay usable on small screens
|
||||
- tool windows should not render behind the main viewport layer
|
||||
- window persistence should not trap a tool off-screen forever
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- docking and undocking
|
||||
- better positioning behavior
|
||||
- tool window focus bugs
|
||||
- opening or closing auxiliary windows
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the request about the external studio window, or internal tool popouts?
|
||||
- Does it depend on persisted window coordinates?
|
||||
- Does it affect one tool window or the shared shell behavior?
|
||||
48
docs/kb/systems/graphics-painter.md
Normal file
48
docs/kb/systems/graphics-painter.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Graphics Painter
|
||||
|
||||
## What It Does
|
||||
|
||||
The Graphics Painter is the tile and sprite art editing window. It handles pixel editing, frame management, animation timeline editing, preview playback, and import-oriented art workflows.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/tileArtEditorWindowController.ts`
|
||||
- `src/worldshaperStudio/graphicsDocumentHelpers.ts`
|
||||
- `src/worldshaperStudio/importController.ts`
|
||||
- `src/worldshaperStudio/dom.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/images`
|
||||
- `GET /api/images/:filename`
|
||||
- `POST /api/content/images`
|
||||
- `POST /api/content/sprites`
|
||||
- `POST /api/content/tiles`
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- graphics records may include animation frame data and playback metadata
|
||||
- preview behavior is maintained in painter-local UI state
|
||||
- art changes eventually flow into tile and sprite content records
|
||||
- imports and previews are tightly tied to painter usability
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- the painter is a floating tool window, not a docked pane
|
||||
- animation preview should reflect current frame ordering and speed settings
|
||||
- save behavior must preserve frame structure and timing metadata
|
||||
- painter workflows often depend on tile and sprite schema conventions
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- move or selection tools
|
||||
- frame duplication and frame management
|
||||
- animation controls
|
||||
- import workflow improvements
|
||||
- better preview behavior
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is this request about art authoring, record storage, or runtime playback?
|
||||
- Does it affect tiles, sprites, or both?
|
||||
- Is the requested behavior inside the painter window only?
|
||||
42
docs/kb/systems/launcher-home.md
Normal file
42
docs/kb/systems/launcher-home.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Launcher Home
|
||||
|
||||
## What It Does
|
||||
|
||||
The launcher is the public-facing entry point for Worldshaper. It presents the hero card, opens the editor in its own floating window, links to the repo, and hosts the News and Requests tabs.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/WorldshaperLauncher.tsx`
|
||||
- `src/index.css`
|
||||
- `src/worldshaperStudio/windowing.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/world-default`
|
||||
- `GET /api/launcher-requests`
|
||||
|
||||
## Important State
|
||||
|
||||
- launch state: ready, opening, opened, blocked, error
|
||||
- active board tab: news or requests
|
||||
- request list, filters, and expanded request rows
|
||||
- resolved default world id
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- The editor is intended to open in a separate popup-style window.
|
||||
- The launcher should still work if the default world lookup fails by falling back to `overworld`.
|
||||
- Browser popup blocking is a real failure mode and must be surfaced to the user.
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- page styling and presentation
|
||||
- launch flow and popup behavior
|
||||
- repo button or external links
|
||||
- tab layout and launcher information architecture
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is this about the launcher page itself, or the studio window after launch?
|
||||
- Does it affect only presentation, or also request API behavior?
|
||||
- Does it depend on popup/window behavior?
|
||||
47
docs/kb/systems/layers-tile-editing.md
Normal file
47
docs/kb/systems/layers-tile-editing.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Layers And Tile Editing
|
||||
|
||||
## What It Does
|
||||
|
||||
This subsystem handles normal tile painting, erasing, selection, visible layer management, sparse height layers, and the mapping between visible document edits and stored chunk data.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/interactionController.ts`
|
||||
- `src/worldshaperStudio/runtime.ts`
|
||||
- `src/worldshaperStudio/sidebarController.ts`
|
||||
- `src/worldshaperStudio/mapDocumentController.ts`
|
||||
- `src/worldshaperStudio/popupSessionStore.ts`
|
||||
- `src/worldshaperStudio/dom.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- primarily saved through `POST /api/world/:worldId/chunks/batch-save`
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- room layer `0` is the base layer
|
||||
- non-base layers use sparse or transparent-style fill semantics
|
||||
- height layers are separate structures from room layers
|
||||
- visibility is tracked in popup session state
|
||||
- painting in world mode must mark affected chunks dirty
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- layer ordering matters to rendering and selection behavior
|
||||
- layer visibility must not destroy layer data
|
||||
- tile edits in world mode must map local viewport coordinates back to world chunk coordinates
|
||||
- height layers are not the same thing as standard room layers
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- better layer reordering
|
||||
- more precise tiling tools
|
||||
- height/elevation features
|
||||
- snapping or unsnapped placement
|
||||
- erase or selection behavior
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is this about normal room layers or height layers?
|
||||
- Does the request affect paint semantics, visibility, ordering, or storage?
|
||||
- Does it apply to map mode, world mode, or both?
|
||||
49
docs/kb/systems/persistence-save-pipeline.md
Normal file
49
docs/kb/systems/persistence-save-pipeline.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Persistence And Save Pipeline
|
||||
|
||||
## What It Does
|
||||
|
||||
This subsystem turns editor state into saved content and world data. It persists content records, world metadata, bookmarks, and dirty chunks, while keeping save state and toolbar status in sync.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/persistenceController.ts`
|
||||
- `src/worldshaperStudio/historyController.ts`
|
||||
- `src/worldshaperStudio/historyStateStore.ts`
|
||||
- `server.js`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `POST /api/world/:worldId/chunks/batch-save`
|
||||
- `POST /api/content/:type`
|
||||
- `GET /api/editor-settings`
|
||||
- `POST /api/editor-settings`
|
||||
- `GET /api/catalog-meta`
|
||||
- `POST /api/catalog-meta`
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- world save batches metadata, bookmarks, and dirty chunks together
|
||||
- content saves are per content type
|
||||
- successful world saves clear dirty chunk keys
|
||||
- save failures surface through status messages and toolbar state
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- save must not lose dirty chunk edits
|
||||
- content records and world chunks have different persistence paths
|
||||
- history state should know when a save succeeds
|
||||
- partial failures need clear error reporting
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- save reliability
|
||||
- auto-save ideas
|
||||
- validation before save
|
||||
- batch save size or performance
|
||||
- stale content vs world metadata mismatches
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the failure on world save, content save, or both?
|
||||
- Are we persisting the right data, but at the wrong time?
|
||||
- Does the request need new API support or just better client save orchestration?
|
||||
45
docs/kb/systems/rendering-viewport.md
Normal file
45
docs/kb/systems/rendering-viewport.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Rendering And Viewport
|
||||
|
||||
## What It Does
|
||||
|
||||
This subsystem draws the active world or map, manages Pixi chunk surfaces, keeps chunk visibility in sync with the viewport, and overlays debug and selection information on top of the scene.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/renderController.ts`
|
||||
- `src/worldshaperStudio/pixiTileStageController.ts`
|
||||
- `src/worldshaperStudio/pixiSceneRebuildHelpers.ts`
|
||||
- `src/worldshaperStudio/pixiChunkSurfaceHelpers.ts`
|
||||
- `src/worldshaperStudio/overlayRenderer.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- none directly; it consumes already-loaded document and chunk data
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- chunk surfaces are built per layer and per chunk
|
||||
- viewport movement drives visible chunk culling
|
||||
- Pixi visibility is separate from data caching
|
||||
- debug snapshots expose visible chunk counts and renderer state
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- rendering changes must respect layer visibility
|
||||
- the viewport can hide chunk sprites without unloading their cached data
|
||||
- background tile behavior is special for base-layer rendering
|
||||
- performance work needs profiling because rendering cost and fetch cost are different problems
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- rendering performance
|
||||
- chunk culling
|
||||
- animation playback in-world
|
||||
- background drawing behavior
|
||||
- viewport glitches on very large worlds
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the request about data load, or only about drawing what is already loaded?
|
||||
- Is the issue specific to Pixi chunk surfaces?
|
||||
- Does it reproduce only at certain zoom levels or viewport sizes?
|
||||
54
docs/kb/systems/request-board.md
Normal file
54
docs/kb/systems/request-board.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Request Board
|
||||
|
||||
## What It Does
|
||||
|
||||
The request board lives on the launcher and stores lightweight user submissions. It currently supports pending and active request states, filtering, expansion of active items, and deletion with confirmation.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/WorldshaperLauncher.tsx`
|
||||
- `server.js`
|
||||
- `data/launcher_requests.json`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/launcher-requests`
|
||||
- `POST /api/launcher-requests`
|
||||
- `PATCH /api/launcher-requests/:requestId`
|
||||
- `DELETE /api/launcher-requests/:requestId`
|
||||
|
||||
## Important Data Shape
|
||||
|
||||
Current request records include:
|
||||
|
||||
- `id`
|
||||
- `sourceSubmissionId`
|
||||
- `title`
|
||||
- `status`
|
||||
- `category`
|
||||
- `tags`
|
||||
- `sourceText`
|
||||
- `summary`
|
||||
- `implementationNotes`
|
||||
- `createdAt`
|
||||
- `updatedAt`
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- New submissions enter as pending unless promoted.
|
||||
- One raw submission may contain multiple real feature requests.
|
||||
- Active requests should be normalized, titled, and tagged.
|
||||
- Deletion is destructive and should remain explicit.
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- parse and split user submissions
|
||||
- request tags and filtering
|
||||
- moderation and cleanup
|
||||
- queue automation and confidence review
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the user asking to change request storage, presentation, or parsing behavior?
|
||||
- Should one submission become many active requests?
|
||||
- Is the request really a bug report or a feature idea?
|
||||
45
docs/kb/systems/world-bootstrap.md
Normal file
45
docs/kb/systems/world-bootstrap.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Studio Bootstrap
|
||||
|
||||
## What It Does
|
||||
|
||||
Bootstrap prepares the initial studio session. It resolves the target world, loads world metadata, bookmarks, and the first chunk neighborhood, then composes the initial editable document shown in the studio window.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/bootstrap.ts`
|
||||
- `src/worldshaperStudio/main.ts`
|
||||
- `src/worldshaperStudio/runtime.ts`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/world-default`
|
||||
- `GET /api/world/:worldId`
|
||||
- `GET /api/world/:worldId/bookmarks`
|
||||
- `GET /api/world/:worldId/chunks`
|
||||
|
||||
## Important State
|
||||
|
||||
- current world id and world metadata
|
||||
- chunk width and height
|
||||
- source chunk list
|
||||
- bookmark-derived initial camera position
|
||||
- initial composed document layers and height layers
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- World mode starts from a chunk neighborhood, not a full-world payload.
|
||||
- Bookmarks can influence the initial view center.
|
||||
- Bootstrap has to hydrate enough content catalogs for tiles and sprites to render correctly.
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- startup performance
|
||||
- opening the wrong world or stale world state
|
||||
- incorrect first camera position
|
||||
- missing tiles or sprites on first load
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the problem visible only at startup?
|
||||
- Does the issue disappear after movement or reload?
|
||||
- Is it a missing bootstrap dependency, or a later runtime bug?
|
||||
45
docs/kb/systems/world-overview.md
Normal file
45
docs/kb/systems/world-overview.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# World Overview
|
||||
|
||||
## What It Does
|
||||
|
||||
World Overview is a separate window that displays a coarse map of all known chunks, supports bookmark navigation, and exposes chunk operations such as move, duplicate, rotate, flip, delete, and background adjustments.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `src/worldshaperStudio/worldOverviewWindowController.ts`
|
||||
- `src/worldshaperStudio/dom.ts`
|
||||
- `server.js`
|
||||
|
||||
## Endpoints It Uses
|
||||
|
||||
- `GET /api/world/:worldId/overview`
|
||||
- `GET /api/world/:worldId/bookmarks`
|
||||
- bookmark writes flow through the world save path
|
||||
|
||||
## Important Data And Rules
|
||||
|
||||
- overview currently requests the full set of world chunks from the server
|
||||
- it draws its own chunk preview surfaces
|
||||
- it merges server chunks with cached client chunks to reflect unsaved local state
|
||||
- chunk context menus expose world-level operations
|
||||
|
||||
## Invariants And Constraints
|
||||
|
||||
- overview is only available in world mode
|
||||
- overview actions should not silently discard unsaved chunk edits
|
||||
- chunk transform actions must preserve chunk addressing rules
|
||||
- the full overview payload can become a performance hotspot on larger worlds
|
||||
|
||||
## Common Request Themes
|
||||
|
||||
- chunk operations
|
||||
- world navigation
|
||||
- bookmark workflows
|
||||
- overview performance
|
||||
- better high-level visualization
|
||||
|
||||
## Triage Questions
|
||||
|
||||
- Is the issue specific to the overview window, or all world editing?
|
||||
- Does it affect overview drawing only, or also chunk save/load behavior?
|
||||
- Is the request about overview scale, navigation, or chunk manipulation?
|
||||
52
docs/request-analysis-vps.md
Normal file
52
docs/request-analysis-vps.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Request Analysis On Debian 12 VPS
|
||||
|
||||
This setup runs the request-analysis worker on the VPS only when needed.
|
||||
|
||||
## How It Works
|
||||
|
||||
- the API server accepts pending launcher requests
|
||||
- when a new pending request is created, the server schedules the worker
|
||||
- only one worker run is active at a time
|
||||
- if more pending requests remain after a run finishes, the server schedules another pass
|
||||
- you can also trigger a run manually through `POST /api/launcher-requests/process-pending`
|
||||
|
||||
The worker itself still uses DeepSeek's hosted API, so the VPS is coordinating queue work instead of doing local inference.
|
||||
|
||||
## Required Environment
|
||||
|
||||
Recommended env file:
|
||||
|
||||
`/srv/worldshaper/shared/worldshaper.env`
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
DEEPSEEK_API_KEY=your-key-here
|
||||
REQUEST_ANALYZER_AUTORUN=1
|
||||
REQUEST_ANALYZER_PROVIDER=deepseek
|
||||
REQUEST_ANALYZER_MODEL=deepseek-v4-flash
|
||||
REQUEST_ANALYZER_PROMOTE_THRESHOLD=0.85
|
||||
REQUEST_ANALYZER_THINKING=disabled
|
||||
```
|
||||
|
||||
## PM2 Deploy Hook
|
||||
|
||||
The sample post-receive hook in [scripts/vps-post-receive.sample.sh](../scripts/vps-post-receive.sample.sh) now:
|
||||
|
||||
- loads `/srv/worldshaper/shared/worldshaper.env` if present
|
||||
- restarts PM2 with `--update-env`
|
||||
- passes the request-analysis environment through on restart/start
|
||||
|
||||
## Manual Trigger
|
||||
|
||||
If you want to force a queue run:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:5180/api/launcher-requests/process-pending
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- autorun is opt-in through `REQUEST_ANALYZER_AUTORUN=1`
|
||||
- the worker only launches if pending requests exist
|
||||
- DeepSeek credentials stay on the VPS in the shared env file, not in the repo
|
||||
312
docs/runtime-api-proposal.md
Normal file
312
docs/runtime-api-proposal.md
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
# 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`
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue