Skip to content

World Streaming

@esengine/world-streaming provides chunk-based world streaming and management for open world games. It handles dynamic loading/unloading of world chunks based on player position.

Terminal window
npminstall@esengine/world-streaming
import {
ChunkManager,
ChunkStreamingSystem,
StreamingAnchorComponent,
ChunkLoaderComponent
} from'@esengine/world-streaming';
// Create chunk manager (512 unit chunks)
const chunkManager = newChunkManager(512);
chunkManager.setScene(scene);
// Add streaming system
const streamingSystem = newChunkStreamingSystem();
streamingSystem.setChunkManager(chunkManager);
scene.addSystem(streamingSystem);
// Create loader entity with config
const loaderEntity = scene.createEntity('ChunkLoader');
const loader = loaderEntity.addComponent(newChunkLoaderComponent());
loader.chunkSize=512;
loader.loadRadius=2;
loader.unloadRadius=4;
// Create player as streaming anchor
const playerEntity = scene.createEntity('Player');
const anchor = playerEntity.addComponent(newStreamingAnchorComponent());
// Update anchor position each frame
functionupdate() {
anchor.x= player.position.x;
anchor.y= player.position.y;
}
importtype { IChunkDataProvider, IChunkCoord, IChunkData } from'@esengine/world-streaming';
classProceduralChunkProviderimplementsIChunkDataProvider {
private seed:number;
constructor(seed:number) {
this.seed= seed;
}
asyncloadChunkData(coord:IChunkCoord):Promise<IChunkData|null> {
// Use deterministic random based on seed + coord
constchunkSeed = this.hashCoord(coord);
constrng = this.createRNG(chunkSeed);
// Generate chunk content
constentities = this.generateEntities(coord, rng);
return {
coord,
entities,
version: 1
};
}
asyncsaveChunkData(data:IChunkData):Promise<void> {
// Optional: persist modified chunks
}
privatehashCoord(coord:IChunkCoord):number {
returnthis.seed^ (coord.x*73856093) ^ (coord.y*19349663);
}
privatecreateRNG(seed:number) {
// Simple seeded random
return()=> {
seed = (seed *1103515245+12345) &0x7fffffff;
return seed /0x7fffffff;
};
}
privategenerateEntities(coord:IChunkCoord, rng:()=>number) {
// Generate resources, trees, etc.
return [];
}
}
// Use provider
chunkManager.setDataProvider(newProceduralChunkProvider(12345));
Unloaded → Loading → Loaded → Unloading → Unloaded
↓ ↓
Failed (on error)

StreamingAnchorComponent marks entities as chunk loading anchors. The system loads chunks around all anchors and unloads chunks outside the combined range.

// StreamingAnchorComponent implements IPositionable
interface IPositionable {
readonly position: { x:number; y:number };
}
PropertyDefaultDescription
chunkSize512Chunk size in world units
loadRadius2Chunks to load around anchor
unloadRadius4Chunks to unload beyond this
maxLoadsPerFrame2Max async loads per frame
unloadDelay3000MS before unloading
bEnablePrefetchtruePrefetch in movement direction

For quick setup, use the module helper:

import { worldStreamingModule } from'@esengine/world-streaming';
const chunkManager = worldStreamingModule.setup(
scene,
services,
componentRegistry,
{ chunkSize: 256, bEnableCulling: true }
);