Godot Export Pipeline
The @world-forge/export-godot package converts a WorldProject into a structured content pack with .tscn scene generation for Godot 4.
Pipeline Overview
Section titled “Pipeline Overview”- Validate —
validateProject()runs structural checks. Invalid projects fail with detailed error context. - Convert zones —
Zone[]becomes Godot spatial resources with 2D coordinate transform (grid → Godot 2D). - Convert content — entities, items, connections, dialogues, loot tables, spawn markers, and transitions.
- Convert tiles + interiors —
TileLayer[]→TileMapLayer+TileSet(bakedtile_map_datafor image tilesets), non-walkable cells → wallStaticBody2Dcollision, and props → aNode2Dcontainer. - Convert town — markets + crafting stations, and buildings / hubs / strongholds (
convert-economy,convert-structures). - Convert world modeling — vertical strata + links (
convert-strata), typed hazards (convert-hazards), and zone entry gates (convert-gates). - Build scene —
buildWorldScene()generates a single playable.tscnfrom all of the above. - Build asset bindings — sprites, portraits, and backgrounds mapped to Godot resource paths.
- Fidelity report — structured tracking of lossless, approximated, and dropped data.
Output
Section titled “Output”The export produces a GodotContentPack containing:
- Per-zone resources with spatial data
- Entity manifest with placement coordinates
- Navigation links between zones
- Transition nodes for scene changes
- Loot tables and spawn markers
- Dialogue resources
- District groupings with faction/economy data
- Asset binding manifest
- A world
.tscnscene (optional, controlled by export options)
Playable Scene Structure
Section titled “Playable Scene Structure”buildWorldScene() emits a single .tscn that opens navigable in the Godot 4
editor — not a metadata graph. The root Node2D (y-sort enabled) contains:
- A framed
Camera2Dso the scene is visible the moment it opens. - Per zone: a
Node2Dwith aStaticBody2Dcollision hull, aNavigationRegion2Dnavmesh,y_sort_enabled, and az_indexderived from its stratum band (+ elevation). TileMapLayernodes per tile layer (image tilesets baketile_map_datacells; color-only layers carry aTileSetscaffold + metadata), each with per-cell wallStaticBody2Dcollision for non-walkable tiles.- A
Propscontainer (Node2Dplacements). - Town:
Markets/CraftingStationscontainers, plusBuildings(StaticBody2Dfootprints with aCollisionShape2D),Hubs, andStrongholds. Strata+StratumLinkscontainers (metadata; zones carrystratum_idand az_indexband so surface layers sort over the cellar).Hazards— oneArea2Dper (zone, hazard) with an inlineCollisionShape2Dregion; the hazard’s effects ride as metadata, read onbody_entered.- Gated zones carry
entry_gate/entry_gate_mode/entry_gate_reasonmetadata for the runtime to evaluate against party state on entry.
Every node is a textureless, self-contained engine primitive — the export loads
clean in real Godot 4.7 headless (the dogfood smoke asserts 36 facts about the
generated scene, from zone collision to the cellar’s underground z_index band).
npx world-forge-export-godot project.json --out ./GodotPacknpx world-forge-export-godot project.json --validate-onlynpx world-forge-export-godot project.json --out ./GodotPack --no-world-tscn--out writes a loadable Godot 4 project root (File → Open Project):
| Path | What |
|---|---|
project.godot |
config_version=5, features 4.x, run/main_scene="res://world.tscn" |
world.tscn |
playable scene; ExtResource entries point at .tres under res://world_data/ |
world_data/ |
stamped .tres bodies (zones, items, dialogues, …) |
assets/ |
copied authored textures (tilesets / sprites / props); URI paths warn and are skipped |
scripts/player.gd |
CharacterBody2D move script for the player pawn |
pack.json / fidelity.json |
data pack + lossless / approximated / dropped report |
--out requires a path that does not start with -. Exit 1 on validation or write failure, with path + message + a fix hint.
Programmatic Usage
Section titled “Programmatic Usage”import { exportToGodot } from '@world-forge/export-godot';
const result = exportToGodot(project);
if (!result.success) { // GodotExportError — validation or conversion failed console.error(result.errors);} else { // GodotExportResult const pack = result.contentPack; // GodotContentPack const scene = pack.worldSceneTscn; // single playable .tscn, not per-zone const { warnings, fidelity } = result;}Editor Export Options
Section titled “Editor Export Options”When exporting from the editor’s Export modal, the Godot 4 target options panel provides:
| Option | Default | Effect |
|---|---|---|
| Entity scene prefix | res://entities/ |
Resource path prefix for entity scenes |
| Transition scene prefix | res://transitions/ |
Resource path prefix for transition scenes |
| Include world .tscn | ✓ enabled | Whether to generate the top-level world scene |
| Asset binding mode | manifest |
How assets are referenced: manifest (centralized) or manual (inline paths) |
These settings are embedded in the exported bundle’s exportSettings field for downstream tooling to consume.
Coordinate Transform
Section titled “Coordinate Transform”World Forge grid coordinates are converted to Godot 2D coordinates:
- Grid position → Godot
Vector2in pixels - Zone dimensions map to scene node bounds
- Entity placements become positioned child nodes
The Three Grids
Section titled “The Three Grids”A 2.5D world is described by three grids at once, and the exporter converts between none of them. Mixing them is how a harbour ends up with a person drawn in a room the simulation says they are not in.
| Grid | Unit | Who owns it | Hashed? |
|---|---|---|---|
| Sim occupancy | zone id | the engine’s WorldState |
yes — authoritative |
| Dimetric cell | 256x128 diamond, span 3 | the client’s isometric view, via presentation |
never |
| Forge cartesian | gridX / gridY in tiles |
the editor and this .tscn |
never |
The Godot export writes the cartesian grid: zone origins, tile cells, and
the CharacterBody2D pawn all live there, and a sandbox scale may multiply the
whole thing. The optional WorldProject.presentation block holds the
dimetric grid — zone anchor cells, floor plates, and an occupancy row per
actor — and is carried through the export untouched, never scaled and never
recomputed from gridX/gridY. The zone id is the only thing the two
share, and it is what a client joins on.
exportToGodot pushes presentationAdvisories() onto warnings[], so a block
whose cells fall outside a zone’s span, or whose actor stands in a room the sim
places elsewhere, is reported at export time rather than discovered on screen.
The stage-fixture lane (dogfood/export-stage-fixture.ts) can promote those
advisories to a hard failure with --strict.
Fidelity Reporting
Section titled “Fidelity Reporting”Every export produces a structured fidelity report tracking what was preserved, approximated, or dropped:
- Lossless — zones, entities, items, connections, dialogues, spawn points, tile cells (image tilesets), wall collision
- Approximated — town economy + structures, vertical strata, hazards, and entry gates (emitted as nodes + metadata the runtime drives); parallax (no
ParallaxBackgroundnode emitted yet); position-default fallbacks - Dropped — references with no matching definition (e.g. a zone hazardRef with no
HazardDefinition), reported with the offending id
Fidelity is grouped by domain (zones, tiles, props, economy,
structures, navigation, …) so you can see exactly what each subsystem
contributed.
Format Version
Section titled “Format Version”GODOT_PACK_FORMAT_VERSION — currently 1.1.0.
Bump rules (keep in sync with packages/export-godot/src/migrations.ts):
- Major — required field added/removed, or field semantics change in a way a loader must see.
- Minor — optional field added. Old loaders ignore it; new loaders may read it.
- Patch — clarifications, doc-only changes.
migrateGodotPack() walks that chain. 1.1.0 added files (each stamped resourcePath → .tres body) and zoneGates on the JSON pack so a data-driven loader does not need to parse the .tscn.
