import type { Bounds, Vec3 } from './types'; /** * Spatial clustering of many placed assets into Scene v2 streaming cells and * 'distance'-mode stream groups. * * The single-sheet importer put every node in one eager cell: correct for one * baked mesh, wasteful for a pack of N individually placed props where a player * only ever stands near a few of them. Cells follow the ground-plane grid model * proven by the Helsinki mosaic tiles — square regions of world X/Z, each * holding the nodes whose centroids fall inside them — so the runtime can * activate only the neighbourhood a player is actually in. */ /** * Platform Scene caps, re-exported straight from the shared contract. Copying * the numbers here would let the CLI and the validator drift apart silently and * the CLI's "named offender" errors would start naming the wrong limit. */ export declare const SCENE_V2_MAX_CELLS: 1024; export declare const SCENE_V2_MAX_STREAM_GROUPS: 256; export declare const SCENE_V2_MAX_NODES: 4096; export declare const SCENE_V2_MAX_RESOURCES: 2048; export declare const SCENE_V2_MAX_NODES_PER_CELL: 1024; /** Ground-plane grid cells below this stop earning their streaming overhead. */ export declare const MIN_CELL_SIZE_M = 16; /** Above this, cell activation latency outweighs any residency saving. */ export declare const MAX_CELL_SIZE_M = 128; export type Placement = { id: string; name: string; transform: { position: Vec3; rotation: [number, number, number, number]; scale: Vec3; }; /** World-space bounds of the placed instance (local bounds after its transform). */ worldBounds: Bounds; detailResourceKey: string; proxyResourceKey: string; }; export type StreamCellPlan = { id: string; bounds: Bounds; /** Placement ids whose nodes live in this cell. */ placementIds: string[]; }; export type StreamGroupPlan = { id: string; priority: number; mode: 'distance'; cells: StreamCellPlan[]; /** * Sum of unique resource MiB referenced by this group's nodes and colliders. * Deliberately ignores sharing across groups: the validator's residency union * adds group estimates, so crediting a shared resource twice would promise * memory the residency check does not know is shared. */ estimatedMemoryMiB: number; }; export type PlannedPlacement = Placement & { cellId: string; groupId: string; }; export type StreamLayoutPlan = { cellSizeM: number; streamRadiusM: number; groups: StreamGroupPlan[]; placements: PlannedPlacement[]; }; export declare function centroidOf(bounds: Bounds): Vec3; /** * Cell size from the pack's own asset scale: four median horizontal extents, * clamped to the band where streaming pays for itself, then grown until the * plan fits the platform cell cap. */ export declare function chooseCellSizeM(placements: readonly Placement[]): number; /** * Clusters placements into grid cells, chunks spatially coherent cells into at * most SCENE_V2_MAX_STREAM_GROUPS distance-mode groups, and estimates each * group's decoded memory from the unique resources its nodes reference. * * `resourceMiB` maps resource keys (the same keys carried on placements) to the * decoded size the runtime must hold for that resource. Group memory is the sum * over the detail AND proxy keys its placements reference — proxies included, * because LOD selection can swap them in while the rest of the group streams. */ export declare function planStreamLayout(input: { placements: readonly Placement[]; resourceMiB: ReadonlyMap; cellSizeM?: number; }): StreamLayoutPlan; /** * The activation radius a player needs before a distance group streams in: * half the largest cell diagonal plus the largest asset radius, so a group is * resident before anything inside it can be seen, not after. */ export declare function deriveStreamRadiusM(placements: readonly Placement[], cellSizeM: number): number;