import { type EditorDocumentDiagnostic } from "./document.js"; import type { EditorDocument } from "./types.js"; /** * A sharded **world**: a scene that is no longer one monolithic `editor.scene.json` but a manifest * plus spatially-partitioned shard documents. A single-file game is the degenerate one-shard case, * so nothing pays for scale it does not have. The shard/overlay documents are the exact * {@link EditorDocument} format loaders already consume — this module is composition over * `mergeEditorDocuments` / `extractEditorFragment` / `editorDocumentBounds`, not a new format. */ /** The manifest `kind` discriminator — a world folder's `world.json`. */ export declare const WORLD_MANIFEST_KIND = "world"; /** Whether a shard is always loaded (terrain, always-resident hero content) or streamed by proximity. */ export type WorldShardResidency = "always" | "streamed"; /** A shard's XZ world-space footprint, `[minX, minZ]`..`[maxX, maxZ]`, used to route/stream loads. */ export interface WorldShardBounds { min: [number, number]; max: [number, number]; } /** One entry in a world manifest: a shard document, its footprint, residency, and optional overlay. */ export interface WorldManifestShard { /** Stable shard id (also the merge/stream unit). */ id: string; /** Path to the shard's `EditorDocument` JSON, relative to the world folder. */ file: string; /** XZ footprint used to cull the shard against a streaming query; absent = always resident. */ bounds?: WorldShardBounds; /** `"always"` keeps the shard resident regardless of the query; default `"streamed"` when bounded. */ residency?: WorldShardResidency; /** Path to a sparse overlay document applied on top of this shard (hand-tweaks over materialized content). */ overlay?: string; } /** The world grid the shards partition space on. */ export interface WorldGrid { /** Cell edge length in meters. */ cellSize: number; } /** Proximity streaming radii, in meters. */ export interface WorldStreamingConfig { /** Load shards whose footprint is within this distance of the query center. */ loadRadius: number; /** Keep already-loaded shards resident until they fall outside this (larger) distance — hysteresis. */ keepRadius: number; } /** A world manifest — the `world.json` at the root of a world folder. */ export interface WorldManifest { kind: typeof WORLD_MANIFEST_KIND; /** Manifest schema version; defaults to 1 when absent. */ version?: number; grid?: WorldGrid; shards: WorldManifestShard[]; streaming?: WorldStreamingConfig; } /** A spatial query used to select which shards a neighborhood needs. */ export interface WorldQuery { /** Query center in world space (typically the camera/player position). */ center: { x: number; z: number; }; /** Selection radius in meters; 0 (default) selects only shards whose footprint contains the center. */ radius?: number; } /** Resolves a shard/overlay file path to a decoded document, or null when it cannot be read. */ export type WorldShardResolver = (file: string) => EditorDocument | null; /** * True when a shard should be resident for a query: always-resident shards always, bounded shards * only when the query disc (`center` ± `radius`) overlaps their footprint. * @capability world-shards select shards for a neighborhood by spatial query */ export declare function shardMatchesQuery(shard: WorldManifestShard, query: WorldQuery): boolean; /** * The shards a query needs — always-resident shards plus every bounded shard whose footprint the * query disc overlaps, in manifest order. With no query every shard is selected (load the planet), * so a one-shard game and an unqueried load behave exactly as a monolithic document does today. * @capability world-shards select shards for a neighborhood by spatial query */ export declare function selectWorldShards(manifest: WorldManifest, query?: WorldQuery): WorldManifestShard[]; /** * Loads the live neighborhood document for a query: reads each selected shard through `resolve`, * applies its overlay (if any) on top, then merges them into one {@link EditorDocument} downstream * consumers (`placeAuthoredObjects`, `collectAuthoredTriggers`, scatter, …) read unchanged. The * monolith becomes an internal detail of the loader; a one-shard world yields exactly that shard. * @capability world-shards merge the shards for a neighborhood into one live document */ export declare function loadWorldDocument(manifest: WorldManifest, resolve: WorldShardResolver, query?: WorldQuery): EditorDocument; /** The always-resident base shard id used by {@link splitEditorDocumentIntoShards}. */ export declare const WORLD_BASE_SHARD_ID = "base"; /** Options controlling how a monolithic document is partitioned into shards. */ export interface SplitWorldOptions { /** Grid cell edge length in meters. Default 256. */ cellSize?: number; /** Directory prefix for generated shard files. Default `"shards"`. */ shardDir?: string; } /** The result of splitting a document: a manifest plus the shard documents keyed by their file path. */ export interface SplitWorldResult { manifest: WorldManifest; /** Shard file path → document, for a caller to serialize into a world folder. */ shards: Record; } /** * Splits a monolithic document into a sharded world: placeable objects (markers, volumes, paths, * notes) are bucketed into `cellSize`-meter grid cells by a representative point and extracted into * per-cell shard documents; the non-placeable extras (terrain, catalogs, prefabs, collections, * grids, HUD layout) go into one always-resident `base` shard. Round-trips through * {@link loadWorldDocument} to the same object set — the reverse of monolith authoring, so a large * scene can be sharded once and streamed thereafter. Cell shards carry their exact object footprint * as bounds; empty cells are omitted; order is deterministic (row-major by grid coordinate). * @capability world-shards split a monolithic scene document into spatial shards */ export declare function splitEditorDocumentIntoShards(doc: EditorDocument, options?: SplitWorldOptions): SplitWorldResult; /** * The backward-compatible degenerate manifest: one always-resident shard pointing at a single scene * document file. `loadWorldDocument(singleShardWorldManifest(file), resolve)` returns exactly that * document — the migration path for a game that has one `editor.scene.json` and wants the world API * without sharding yet. * @capability world-shards wrap a single scene document as a one-shard world */ export declare function singleShardWorldManifest(file: string, shardId?: string): WorldManifest; /** Result of {@link decodeWorldManifest}: a typed manifest, or every diagnostic collected decoding it. */ export type DecodeWorldManifestResult = { ok: true; manifest: WorldManifest; } | { ok: false; errors: EditorDocumentDiagnostic[]; }; /** * The authoritative decoder for a `world.json` manifest arriving from disk or an agent: validates * `kind`, the shard list, and each shard's fields with a path-specific diagnostic on failure, so a * malformed manifest fails loudly at the boundary instead of streaming a broken world. * @capability world-shards decode an untrusted world manifest with per-field diagnostics */ export declare function decodeWorldManifest(raw: unknown): DecodeWorldManifestResult; /** Serializes a world manifest to pretty JSON for writing `world.json`. */ export declare function exportWorldManifestJson(manifest: WorldManifest, pretty?: boolean): string;