structures-and-spaces-world-model
Structures and Spaces World Model
This note describes how outer-world structure anchors attach to authored spaces, how ownership works, how metadata and amenities are represented, and how snapshots, the player chain, and the preview canvas stay aligned.
Deprecated: tool-derived map layout
@deprecated (world map v3): LangChain tool names no longer create map structures. Removed APIs:
syncPlayerStructuresFromTools, SSEworld:structures, tool-derivedWorldStructuretiles.langchainRegistrationstill validateschat_toolandassist_*for watch UI only. Spatial inventory is authored as spaces with explicit owners. See World map v3.
Naming
- Journey step
type: "structure"(in@types/world.ts) refers to LLM tool-call steps on an agent path. That is unrelated to map occupantkind: "structure".
Snapshot shape
Space catalog (snapshot.spaces)
Canonical metadata for each space, deduped by id. Defined as SpaceCatalogEntryJson in packages/web-ui/src/server/agent-play/preview-serialize.ts:
id,name,description,designKeyowner:{ displayName, playerId?, nodeId? }— required for acquisition; declares who holds the spaceamenities: ordered array ofsupermarket|shop|car_wash(seespace-amenity.ts)- Optional
activityObjectIds,amenityContent, purchase sidecar data
Normalized with normalizePreviewSnapshot: missing spaces is treated as [].
Structure occupant (worldMap.occupants)
Map anchors use occupant kind: "structure" (PreviewWorldMapStructureOccupantJson):
id,name,x,y,worldId,spaceIds- Denormalized for clients:
primaryAmenity,amenities(derived from attached catalog rows for rendering)
@deprecated: Caller-supplied
x/yonregisterStructureNodeare ignored; anchors are auto-placed from the worldLayout space zone (seeresolveStructureAnchorsAtRuntimeingrid-allocate.ts).
Ownership and acquisition
Spaces are acquired when an individual or node authors them with owner metadata:
| Path | How ownership is set |
|---|---|
registerSpaceNode |
owner.displayName required; optional playerId, nodeId |
AQL CREATE SPACE |
OWNER "Display Name" (and optional structure name) after CONNECT |
In-amenity purchases (purchase RPC) are the primary commerce action on amenity slots.
Structure sprites are visual entry points into owned catalog rows—they do not themselves confer ownership without a matching snapshot.spaces entry.
Player chain leaves
In packages/web-ui/src/server/agent-play/player-chain/index.ts:
- Occupants use
stableOccupantSortKey: includesstructure:{id}for structure rows. - After occupants, catalog rows are hashed as separate leaves:
space:{id}(sorted byid), digest of canonicalstableStringify(spaceRow).
readPlayerChainNode resolves space:{id} keys to catalog rows (kind: "space" in the RPC response).
PlayWorld APIs
packages/web-ui/src/server/agent-play/play-world.ts:
registerSpaceNode/registerStructureNodepersist viarunStoredWorldMutationintosnapshot.spacesand structure occupants.listSpaceNodes/listStructureNodesread from the snapshot (async).enterStructureSpaceresolves the structure from snapshot occupants and emitsworld:space_transition.- Player location remains tracked in-memory (
locationsByPlayerId) for transitions.
Registration requires at least one amenity per space.
Preview canvas (Pixi)
packages/play-ui/src/main.ts (mirrored under packages/web-ui/src/canvas/vendor/):
collectStructuresForRendermerges MCP tool stalls (kind: "tool") withkind: "structure"occupants.syncStructureNodesdraws amenity-specific vector art (drawSupermarketStructure,drawShopStructure,drawCarWashStructureinstructure-art.ts).- Primary facade uses
primaryAmenity(defaultshop). Multiple amenities append a short parenthetical caption.
SDK
packages/sdk/src/public-types.ts exposes AgentPlayWorldMapStructureOccupant, AgentPlaySpaceCatalogEntry, optional AgentPlaySnapshot.spaces, and player-chain node variants for space:{id}. Parsing lives in parse-occupant-row.ts, remote-play-world.ts, and player-chain-merge.ts.
Follow-ups
- REST routes for authoring topology from external tools.
leaveSpaceand nested context stack if needed.- Persist player location in snapshot or settings if reconnect must restore interior state.