The .drft container · interface

DrftStreamHandlers

Called as each kind of thing finishes arriving. Every one is optional.

Explained in The .drft container.

interface DrftStreamHandlers
import type { DrftStreamHandlers } from '@driftengine/drft';

In depth

A consumer that wants the whole asset at once should use readDrft; these exist so a scene can put a coarse thing on screen and improve it, which is the point of streaming at all.

Properties

NameTypeDescription
onManifestreadonlyoptional(manifest: DrftManifest) => voidThe table has arrived, so what is coming is now known. Fires once, before anything else.
onHeadreadonlyoptional(head: DrftHead) => void
onLodreadonlyoptional(mesh: MeshData, level: number) => voidA coarse whole-model level, with its level ordinal: 0 is the coarsest.
More

Fires before any part on a file the baker laid out, which is the whole point of it — a complete object on screen while the parts are still arriving. A caller that draws it must stop drawing it in the same frame it starts drawing the model, or the two are both there.

onMeshreadonlyoptional(mesh: MeshData, ordinal: number) => voidOne mesh, in the order the file lays them out, with its ordinal in that order. A kit piece is not one — it goes to onPiece — and an assembly is one only where onAssembly is absent, in which case it arrives here expanded.
onKitreadonlyoptional(pieces: readonly number[]) => voidThe ordinals of the kit's pieces, once, when KITS lands — ahead of the geometry, so a consumer knows which meshes are drawn only as copies before any of them arrives.
onPiecereadonlyoptional(mesh: MeshData, ordinal: number) => voidOne kit piece, as it lands. The stream keeps it for the assemblies that copy it.
onAssemblyreadonlyoptional(assembly: DrftAssembly, ordinal: number, piece: PieceLookup) => voidOne assembly as the file carried it, with a lookup for its pieces, which have all arrived. A consumer that pages its world keeps it this small and expands it (expandAssembly) when it is needed; without this handler the stream expands it and calls onMesh.
onSplatsreadonlyoptional(block: DrftSplatBlock, ordinal: number) => voidOne block of a Gaussian splat capture, with its ordinal.
More

Every block is a sparse version of the whole capture, so the first one is already worth drawing — that is what the writer's coarse-first ordering buys and it is the reason splats are in this container rather than in a file of their own. A consumer allocates from block.totalCount on the first call and appends after that; the drawn count rises and nothing is re-allocated or re-sorted.

onNodesreadonlyoptional(nodes: readonly DrftNode[]) => voidThe asset's hierarchy, once, when its NODE chunk lands.
More

Handed over whole rather than a node at a time: a hierarchy is one chunk and a partial one is not useful — a child whose parent has not arrived cannot be placed.

onInstancesreadonlyoptional(groups: readonly DrftInstanceGroup[]) => voidThe asset's instance groups, once, when INST lands — ahead of the meshes, where the writer puts it, so a consumer knows a mesh is drawn many times before that mesh arrives.
onRegionreadonlyoptional(region: DrftRegion) => voidOne region of a streamed world, when its REGN lands — ahead of the meshes it introduces, so a consumer knows a mesh is a region's level or prop before it arrives. See drftRegions.ts.
onLightVolumereadonlyoptional(volume: DrftLightVolume) => voidA world's summed lights, once, when LVOL lands. See drftLightVolume.ts.
onLightsreadonlyoptional(lights: readonly DrftLight[]) => voidThe lights the scene was authored with, once, when LITE lands. See drftLights.ts.
onFieldsreadonlyoptional(fields: readonly DrftSdfvEntry[]) => voidThe distance fields indirect light is traced against, once, when SDFV lands. Each names the mesh it belongs to, or SDFV_WHOLE_FILE for one over all of the file's static geometry.
onMorphreadonlyoptional(morph: DrftMorph) => voidOne mesh's morph deltas, naming the mesh ordinal they belong to.
onSkinreadonlyoptional(skin: DrftSkin, ordinal: number) => voidOne skin, as its SKIN chunk lands. Several arrive for an asset with several.
onClipreadonlyoptional(clip: AnimationClip, ordinal: number) => voidOne clip, as its ANIM chunk lands.
More

Per chunk rather than collected, for the reason onSplats is: a consumer that can start a character on the first clip should not wait for the last. The writer puts all three ahead of the geometry so this is usually possible.

onCollidersreadonlyoptional(hulls: readonly Float32Array[]) => voidThe convex hulls the asset collides as, once, when COLL lands. See drftColliders.ts.
More

These three — collision, the navigation mesh and the entities — were readDrft's alone, so a scene that streamed its geometry had to fetch the file again, whole, to learn where it could walk and what stood in it.

onNavigationreadonlyoptional(navigation: NavPolyMesh) => voidThe navigation mesh, once, when NAVM lands. See navm.ts.
onEntitiesreadonlyoptional(entities: EntsScene) => voidThe serialised entities, once, when ENTS lands. See ents.ts.
onMaterialsreadonlyoptional(materials: readonly DrftMaterial[]) => void
onTexturereadonlyoptional(texture: DrftTexture, ordinal: number) => void