@aosengine/splat
Classes
AnimatedSplat
A dynamic splat: SplatSink plus lifecycle.
Implements
Constructors
Constructor
ts
new AnimatedSplat(renderer, options): AnimatedSplat;Use createAnimatedSplat; the GPU buffers must be acquired before the object is usable, and that needs an initialised renderer.
Parameters
| Parameter | Type | Description |
|---|---|---|
renderer | WebGPURenderer | An initialised WebGPURenderer on the WebGPU backend. |
options | CreateAnimatedSplatOptions | Capacity, bounds and draw order. |
Returns
Properties
buffers
ts
readonly buffers: SplatGPUBuffers;The four GPU buffers, in the layout documented in backendBuffers.ts.
Implementation of
capacity
ts
readonly capacity: number;Total gaussians this sink can hold. Fixed for its lifetime.
Implementation of
splat
ts
readonly splat: AnimatedGaussianSplat;The fork instance. Typed as the fork, not as Object3D, for object3D consumers.
Accessors
available
Get Signature
ts
get available(): number;Slots not handed out. Named available, because free is the method above.
Returns
number
The count.
object3D
Get Signature
ts
get object3D(): Object3D;The scene object.
Returns
Object3D
The fork instance, which is an ordinary Object3D.
The scene object. Add it to a scene, move it, parent it — it is an ordinary Object3D.
Implementation of
used
Get Signature
ts
get used(): number;Slots currently handed out.
Returns
number
The count.
Methods
allocate()
ts
allocate(count): SlotRange;Reserve a contiguous run of slots.
Parameters
| Parameter | Type | Description |
|---|---|---|
count | number | How many gaussians. |
Returns
The range.
Implementation of
clearSlots()
ts
clearSlots(range?): void;Zero a slot range, which makes it invisible: a colour word of 0 is alpha 0.
This is a queue.writeBuffer of zeros, which is allowed here precisely because it is not a per-frame operation — it runs when a branch is allocated or retired. A producer must never upload gaussian data this way; that is what the compute pass is for.
Parameters
| Parameter | Type | Description |
|---|---|---|
range? | SlotRange | The range to clear. Defaults to the whole capacity. |
Returns
void
Nothing.
dispose()
ts
dispose(): void;Detach from the scene and release the geometry, material and storage buffers.
Returns
void
Nothing.
free()
ts
free(range): void;Give a range back.
Parameters
| Parameter | Type | Description |
|---|---|---|
range | SlotRange | A range from AnimatedSplat.allocate. |
Returns
void
Nothing.
Implementation of
markGaussiansChanged()
ts
markGaussiansChanged(): void;Force a re-sort on the next frame.
Returns
void
Nothing.
Implementation of
SplatSink.markGaussiansChanged
setBoundingSphere()
ts
setBoundingSphere(center, radius): void;Declare where the gaussians are, in local space.
Parameters
| Parameter | Type | Description |
|---|---|---|
center | Vec3Tuple | Local-space centre. |
radius | number | Local-space radius. |
Returns
void
Nothing.
Implementation of
SlotAllocationError
An allocation request that cannot be satisfied.
Extends
Error
Constructors
Constructor
ts
new SlotAllocationError(
message,
requested,
largestFree
): SlotAllocationError;Build a slot allocation error.
Parameters
| Parameter | Type | Description |
|---|---|---|
message | string | What went wrong. |
requested | number | Slots requested. |
largestFree | number | Largest free run at the time. |
Returns
Overrides
ts
Error.constructorProperties
largestFree
ts
readonly largestFree: number;The largest run available at the time.
requested
ts
readonly requested: number;Slots that were asked for.
SplatLoadError
A splat file that could not be decoded.
Extends
Error
Constructors
Constructor
ts
new SplatLoadError(
url,
message,
options?
): SplatLoadError;Build a splat load error.
Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | The URL that failed. |
message | string | What went wrong. |
options? | ErrorOptions | Standard Error options, used to keep the cause. |
Returns
Overrides
ts
Error.constructorProperties
url
ts
readonly url: string;The URL that failed.
Interfaces
CreateAnimatedSplatOptions
Options accepted by createAnimatedSplat.
Properties
autoSort?
ts
readonly optional autoSort?: boolean;Sort in onBeforeRender. Defaults to true, which is what a producer wants: paired with markGaussiansChanged it gives exactly one sort per frame.
boundingSphere?
ts
readonly optional boundingSphere?: object;Where the gaussians will be, in local space. Defaults to a unit sphere at the origin, which is almost certainly wrong; set it as soon as the producer knows.
center
ts
readonly center: Vec3Tuple;radius
ts
readonly radius: number;capacity
ts
readonly capacity: number;Gaussians to allocate. Fixed for the object's lifetime.
renderOrder?
ts
readonly optional renderOrder?: number;Draw order. Defaults to SPLAT_RENDER_ORDER.
CreateSplatObjectOptions
Options accepted by createSplatObject.
Properties
autoSort?
ts
readonly optional autoSort?: boolean;Re-sort in onBeforeRender when the camera turns far enough. Defaults to true. Turn it off only if you drive updateSort yourself.
renderOrder?
ts
readonly optional renderOrder?: number;Draw order. Defaults to SPLAT_RENDER_ORDER.
GltfLoaderLike
The subset of GLTFLoader this package needs, so the loader itself is not imported.
Methods
register()
ts
register(callback): unknown;three's plugin hook.
Parameters
| Parameter | Type | Description |
|---|---|---|
callback | (parser) => unknown | Builds the plugin from the parser. |
Returns
unknown
The loader, for chaining.
LoadSplatOptions
Options accepted by loadSplat.
Properties
fetch?
ts
readonly optional fetch?: {
(input, init?): Promise<Response>;
(input, init?): Promise<Response>;
};Replaces globalThis.fetch, for tests and for an asset-manager transport.
Call Signature
ts
(input, init?): Promise<Response>;Parameters
| Parameter | Type |
|---|---|
input | URL | RequestInfo |
init? | RequestInit |
Returns
Promise<Response>
Call Signature
ts
(input, init?): Promise<Response>;Parameters
| Parameter | Type |
|---|---|
input | string | URL | Request |
init? | RequestInit |
Returns
Promise<Response>
format?
ts
readonly optional format?: SplatFormatOption;Force a decoder instead of sniffing. Defaults to 'auto'.
signal?
ts
readonly optional signal?: AbortSignal;Aborts the fetch. The decode itself is synchronous and is not interruptible.
SlotAllocator
Hands out and reclaims slot ranges inside a fixed capacity.
Properties
available
ts
readonly available: number;Slots not handed out. Equals capacity - used.
Named available rather than free because free is the method next to it, and a property cannot be both.
capacity
ts
readonly capacity: number;Total slots.
freeRuns
ts
readonly freeRuns: readonly SlotRange[];The free runs, low offset first. Exposed for tests and for the debug overlay.
largestFree
ts
readonly largestFree: number;The largest range allocate could satisfy right now.
used
ts
readonly used: number;Slots currently handed out.
Methods
allocate()
ts
allocate(count): SlotRange;Take the first free run large enough.
Parameters
| Parameter | Type | Description |
|---|---|---|
count | number | How many slots. Must be a positive integer. |
Returns
The range.
Throws
When nothing is large enough, or RangeError when count is not a positive integer.
free()
ts
free(range): void;Give a range back, coalescing with either neighbour.
Parameters
| Parameter | Type | Description |
|---|---|---|
range | SlotRange | A range from allocate. |
Returns
void
Nothing.
Throws
When the range was not allocated, or was already freed.
reset()
ts
reset(): void;Drop every allocation and return to one free run.
Returns
void
Nothing.
SlotRange
A contiguous run of gaussian slots.
Properties
count
ts
readonly count: number;How many slots. Always at least 1.
offset
ts
readonly offset: number;Index of the first slot.
SplatAsset
A decoded splat file.
Properties
boundingSphere
ts
readonly boundingSphere: Sphere;Bounds of the centres, in the file's own coordinate system.
count
ts
readonly count: number;Gaussians in the file.
format
ts
readonly format: SplatFormat;Which decoder ran.
geometry
ts
readonly geometry: BufferGeometry;Geometry with position (f32x3), covariance (f32x6), color (u8x4) and optional SH.
shDegree
ts
readonly shDegree: number;Spherical-harmonics degree, 0 to 3. Degree 0 is flat colour.
url
ts
readonly url: string;Where it came from.
SplatGPUBuffers
The four storage buffers behind a GaussianSplat, as real GPUBuffers.
Properties
center
ts
readonly center: GPUBuffer;array<vec4<f32>>: xyz = centre in local space, w unused.
color
ts
readonly color: GPUBuffer;array<u32>: pack4x8unorm(vec4(r, g, b, a)).
covarianceA
ts
readonly covarianceA: GPUBuffer;array<vec4<f32>>: (c00, c01, c02, c11).
covarianceB
ts
readonly covarianceB: GPUBuffer;array<vec4<f32>>: (c12, c22, 0, 0).
SplatModuleOptions
Options accepted by splat.
Properties
format?
ts
readonly optional format?: SplatFormat;Force a decoder for every splat asset instead of sniffing each one. Leave unset unless your assets are served from URLs with no useful extension.
SplatService
What engine.get('splat') returns.
Properties
loaded
ts
readonly loaded: ReadonlyMap<string, SplatAsset>;Every splat asset loaded through the registry, by asset id.
Assets are cached by the registry, so this is a view of it, not a second cache.
Methods
add()
ts
add(id): object;Add a loaded asset to the scene as a GaussianSplat, with the right draw order.
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Asset id, as declared in assets.json. |
Returns
object
The object that was added.
SplatSink
What a producer writes into.
Deliberately small and three-free: a lift shader needs slots, buffers and a way to say the gaussians moved, and nothing else.
Properties
buffers
ts
readonly buffers: SplatGPUBuffers;The four GPU buffers, in the layout documented in backendBuffers.ts.
capacity
ts
readonly capacity: number;Total gaussians this sink can hold. Fixed for its lifetime.
object3D
ts
readonly object3D: Object3D;The scene object. Add it to a scene, move it, parent it — it is an ordinary Object3D.
Methods
allocate()
ts
allocate(count): SlotRange;Reserve a contiguous run of slots.
Parameters
| Parameter | Type | Description |
|---|---|---|
count | number | How many gaussians. |
Returns
The range, as { offset, count }.
free()
ts
free(range): void;Give a range back. The slots are not cleared; call clearSlots first if the caller is not about to overwrite them.
Parameters
| Parameter | Type | Description |
|---|---|---|
range | SlotRange | A range from allocate. |
Returns
void
Nothing.
markGaussiansChanged()
ts
markGaussiansChanged(): void;Tell the splat its gaussians moved, so the next frame re-sorts.
Call it once per frame after the compute pass. Without it the sort only runs when the camera turns more than about 1.81 degrees, and a moving avatar seen from a still camera renders in a stale depth order.
Returns
void
Nothing.
setBoundingSphere()
ts
setBoundingSphere(center, radius): void;Declare where the gaussians are, in the object's local space.
The sort quantises depth into 4096 bins across this sphere, so a sphere that does not contain the splats costs precision, and frustum culling is off precisely because this value is a promise rather than a measurement.
Parameters
| Parameter | Type | Description |
|---|---|---|
center | Vec3Tuple | Local-space centre. |
radius | number | Local-space radius. |
Returns
void
Nothing.
Type Aliases
SplatFormat
ts
type SplatFormat = "spz" | "ply" | "splat" | "ksplat";Container formats loadSplat understands.
SplatFormatOption
ts
type SplatFormatOption = SplatFormat | "auto";SplatFormat, or 'auto' to sniff.
Vec3Tuple
ts
type Vec3Tuple = [number, number, number];A centre as a plain triple, so producers need no three import.
Variables
BYTES_PER_GAUSSIAN
ts
const BYTES_PER_GAUSSIAN: number;Bytes one gaussian occupies across the four storage buffers.
PACKAGE
ts
const PACKAGE: "@aosengine/splat";Package identity marker.
Example
ts
import { PACKAGE } from '@aosengine/splat';
console.log(PACKAGE); // '@aosengine/splat'SPLAT_RENDER_ORDER
ts
const SPLAT_RENDER_ORDER: 1000 = 1000;Splats draw after opaque geometry.
The material is transparent with depthWrite: false, so three already puts it in the transparent pass; the render order pins splats after ordinary transparent meshes, because a splat cloud has no single depth to sort by and would otherwise be interleaved by its object centre.
SUPPORTED_THREE_VERSION
ts
const SUPPORTED_THREE_VERSION: "0.186.0" = '0.186.0';The three version this file's private-surface knowledge was written against.
Functions
acquireSplatGPUBuffers()
ts
function acquireSplatGPUBuffers(renderer, splat): SplatGPUBuffers;Materialise a splat's four storage attributes as real GPUBuffers and hand them back.
Idempotent in both directions: createStorageAttribute early-returns when the buffer already exists, and the same GPUBuffer objects come back on every call for the lifetime of the splat. The buffers are owned by three — do not destroy them; dispose the splat.
Parameters
| Parameter | Type | Description |
|---|---|---|
renderer | WebGPURenderer | An initialised WebGPURenderer. |
splat | object | A GaussianSplat or AnimatedGaussianSplat. |
Returns
The four buffers, in the layout documented at the top of this file.
Throws
When the backend is WebGL, the renderer is not initialised, or three's internals moved.
Example
ts
const buffers = acquireSplatGPUBuffers(renderer, splat);
console.log(buffers.center.size / 16); // gaussian capacitycreateAnimatedSplat()
ts
function createAnimatedSplat(renderer, options): Promise<AnimatedSplat>;Build a dynamic splat on an initialised renderer.
Asynchronous by contract rather than by need: acquiring the buffers is synchronous today, but the call sits on the boundary where a backend could have to be asked for something, and every caller already awaits.
Parameters
| Parameter | Type | Description |
|---|---|---|
renderer | WebGPURenderer | An initialised WebGPURenderer on the WebGPU backend. |
options | CreateAnimatedSplatOptions | Capacity, bounds and draw order. |
Returns
Promise<AnimatedSplat>
The sink, with its GPU buffers already acquired.
Throws
When the renderer is not initialised or fell back to WebGL.
Example
ts
import { createAnimatedSplat } from '@aosengine/splat';
const sink = await createAnimatedSplat(renderer, {
capacity: 250_000,
boundingSphere: { center: [0, 1, 0], radius: 1.4 },
});
scene.add(sink.object3D);
const head = sink.allocate(120_000);
// ... compute pass writes sink.buffers.* over [head.offset, head.offset + head.count)
sink.markGaussiansChanged();createSlotAllocator()
ts
function createSlotAllocator(capacity): SlotAllocator;Build a slot allocator over capacity slots.
Parameters
| Parameter | Type | Description |
|---|---|---|
capacity | number | Total slots. Must be a positive integer. |
Returns
An allocator with one free run covering everything.
Example
ts
import { createSlotAllocator } from '@aosengine/splat';
const slots = createSlotAllocator(1000);
const head = slots.allocate(400);
console.log(head.offset, head.count); // 0 400
slots.free(head);
console.log(slots.available); // 1000createSplatObject()
ts
function createSplatObject(asset, options?): GaussianSplat;Turn a decoded asset into a scene object.
Uses three's own GaussianSplat — the fork exists for the dynamic path and would be the wrong tool here, because a static splat wants exactly the one-time repack the fork skips.
Parameters
| Parameter | Type | Description |
|---|---|---|
asset | SplatAsset | A decoded asset. |
options | CreateSplatObjectOptions | Sort behaviour and draw order. |
Returns
GaussianSplat
The object, with its bounds computed and its render order set.
Example
ts
const splat = createSplatObject(asset, { autoSort: true });
splat.position.y = -1;
scene.add(splat);getGPUDevice()
ts
function getGPUDevice(renderer): GPUDevice;The one GPUDevice in the process — the renderer's.
AGENTS.md hard rule 7: nothing calls navigator.gpu.requestAdapter(). The device only exists after await renderer.init(), and the backend object is replaced when the renderer falls back to WebGL, so never cache either across init.
Parameters
| Parameter | Type | Description |
|---|---|---|
renderer | WebGPURenderer | An initialised WebGPURenderer. |
Returns
GPUDevice
The device the renderer owns.
Throws
When the renderer is not initialised, or fell back to WebGL.
Example
ts
await renderer.init();
const device = getGPUDevice(renderer);
device.createShaderModule({ code });isWebGPUBackend()
ts
function isWebGPUBackend(renderer): boolean;Whether this renderer got a real WebGPU backend rather than the WebGL fallback.
Parameters
| Parameter | Type | Description |
|---|---|---|
renderer | WebGPURenderer | A renderer, initialised or not. |
Returns
boolean
True for the WebGPU backend.
Example
ts
await renderer.init();
if (!isWebGPUBackend(renderer)) console.warn('static splats only');loadSplat()
ts
function loadSplat(url, options?): Promise<SplatAsset>;Fetch and decode a splat file.
Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | SPZ, PLY, SPLAT or KSPLAT. |
options | LoadSplatOptions | Format override, abort signal, custom fetch. |
Returns
Promise<SplatAsset>
The decoded asset.
Throws
On a non-2xx response, an unrecognised format or a decoder failure.
Example
ts
import { createSplatObject, loadSplat } from '@aosengine/splat';
const asset = await loadSplat('/models/arena.spz');
scene.add(createSplatObject(asset));parseSplat()
ts
function parseSplat(
buffer,
url,
format?
): Promise<SplatAsset>;Decode a buffer that has already been fetched.
Separated from loadSplat so tests can drive every decoder from memory, and so an asset pipeline that already holds the bytes does not fetch twice.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
buffer | ArrayBuffer | undefined | The file. |
url | string | undefined | Where it came from, for sniffing and error messages. |
format | SplatFormatOption | 'auto' | Decoder to use, or 'auto'. |
Returns
Promise<SplatAsset>
The decoded asset.
Example
ts
import { parseSplat } from '@aosengine/splat';
const asset = await parseSplat(bytes, 'arena.spz');
console.log(asset.count, asset.shDegree);registerGltfSplatExtension()
ts
function registerGltfSplatExtension(gltfLoader): void;Teach a GLTFLoader to read KHR_gaussian_splatting.
Register it before the first load; meshes carrying the extension then come back as GaussianSplat nodes inside the glTF scene graph. Their render order is not set for you, because the glTF author owns that graph — walk the result and set SPLAT_RENDER_ORDER if splats are interleaving with your transparent meshes.
Parameters
| Parameter | Type | Description |
|---|---|---|
gltfLoader | GltfLoaderLike | The loader to extend. |
Returns
void
Nothing.
Example
ts
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { registerGltfSplatExtension } from '@aosengine/splat';
const loader = new GLTFLoader();
registerGltfSplatExtension(loader);
const gltf = await loader.loadAsync('/models/scene.glb');sniffSplatFormat()
ts
function sniffSplatFormat(url, bytes): SplatFormat;Guess the container format from the URL and the first bytes.
The extension wins when it is one we know, because .ksplat has no magic number and .splat has no header at all. Content sniffing is the fallback, and it can only recognise the two formats that are self-describing: SPZ (gzip, or NGSP for v4) and PLY (ply\n).
Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | The URL the bytes came from. Query and hash are ignored. |
bytes | Uint8Array | At least the first 8 bytes of the file. |
Returns
The format.
Throws
When neither the extension nor the content identifies it.
Example
ts
import { sniffSplatFormat } from '@aosengine/splat';
sniffSplatFormat('/models/arena.spz', new Uint8Array(8)); // 'spz'splat()
ts
function splat(options?): EngineModule;The splat EngineModule.
Registers the splat asset type, so { "id": "arena", "type": "splat", "src": "arena.spz" } in assets.json resolves to a SplatAsset, and publishes a small service for putting one in the scene.
Parameters
| Parameter | Type | Description |
|---|---|---|
options | SplatModuleOptions | Optional format override. |
Returns
The module, to be passed in createEngine({ modules }).
Example
ts
import { createEngine } from '@aosengine/core';
import { splat } from '@aosengine/splat';
const engine = await createEngine({ canvas, manifest: '/assets.json', modules: [splat()] });
engine.get('splat').add('arena');
engine.start();