Skip to main content

Library Usage

splat-transform exposes a programmatic API for reading, processing, and writing Gaussian splat data. Scenes flow through lazy, chunked ChunkSources, so resident memory is bounded by chunk size rather than scene size — the same pipeline the CLI uses to process scenes of hundreds of millions of Gaussians.

API Reference

This page is an overview of the main entry points. The full TypeDoc reference for every export lives at api.playcanvas.com/splat-transform.

Basic Import

import {
readFile,
writeSource,
getInputFormat,
getOutputFormat,
createChunkDataPool,
processSourceBridged
} from '@playcanvas/splat-transform';

Key Exports

Chunk-source pipeline (the primary API):

ExportDescription
readFileRead a splat file as lazy ChunkSources
readFileInfoHeader-only structural metadata (validate/inspect without decoding)
getInputFormatDetect input format from filename
getOutputFormatDetect output format from filename
ChunkSourceThe streaming contract: chunked/gathered reads over one scene
createChunkDataPoolPooled read buffers shared across a pipeline
processSource, processSourceBridgedApply a sequence of processing actions to a source
selectLod, stackLods, concatSource, bakeTransformStructural combinators (lazy views)
decimateSourceChunk-native, memory-bounded decimation to an exact target count
writeSourceStream a source to any single-scene output format
writeLodSourceWrite streamed SOG (lod-meta.json + chunked units) from a multi-LOD source
computeStatsStreaming per-LOD, per-column statistics for a source or table

DataTable compat (secondary; every entry materializes the whole scene in memory):

ExportDescription
DataTable, ColumnLegacy whole-scene table
combineMerge multiple DataTables into one
processDataTableApply processing actions to a DataTable
dataTableToChunkSource, materializeToDataTableBridges between the DataTable and chunk-source worlds
writeFileWrite a DataTable to any output format
writeVoxelWrite sparse voxel octree files
writeImageRender a camera view to a lossless WebP image (requires GPU)

File System Abstractions

The library uses abstract file system interfaces for maximum flexibility:

Reading:

  • UrlReadFileSystem - Read from URLs (browser/Node.js)
  • MemoryReadFileSystem - Read from in-memory buffers
  • ZipReadFileSystem - Read from ZIP archives

Writing:

  • MemoryFileSystem - Write to in-memory buffers
  • ZipFileSystem - Write to ZIP archives

Example: Reading and Processing

import { Vec3 } from 'playcanvas';
import {
readFile,
writeSource,
getInputFormat,
getOutputFormat,
createChunkDataPool,
processSourceBridged,
UrlReadFileSystem,
MemoryFileSystem
} from '@playcanvas/splat-transform';

// Read a PLY file from a URL as a lazy, chunked source
const fileSystem = new UrlReadFileSystem('https://example.com/');
const [source] = await readFile({
filename: 'scene.ply',
inputFormat: getInputFormat('scene.ply'),
fileSystem
});

// Apply actions: transforms compose lazily, filters stream chunk-by-chunk
const pool = createChunkDataPool();
const processed = await processSourceBridged(source, [
{ kind: 'scale', value: 0.5 },
{ kind: 'translate', value: new Vec3(0, 1, 0) },
{ kind: 'filterNaN' }
], pool);

// Stream the result to an in-memory PLY
const memFs = new MemoryFileSystem();
await writeSource({
filename: 'output.ply',
outputFormat: getOutputFormat('output.ply', {}),
source: processed,
pool,
options: {}
}, memFs);
await processed.close();

// Get the output data
const outputBuffer = memFs.results.get('output.ply');

Consumers still on the DataTable API can bridge in either direction with materializeToDataTable(source, pool) and dataTableToChunkSource(dataTable) — both materialize the full scene, so prefer staying on sources for large inputs.

Processing Actions

processSource / processSourceBridged (and the compat processDataTable) accept an array of actions:

type ProcessAction =
| { kind: 'translate'; value: Vec3 }
| { kind: 'rotate'; value: Vec3 } // Euler angles in degrees
| { kind: 'scale'; value: number }
| { kind: 'filterNaN' }
| { kind: 'filterByValue'; columnName: string; comparator: 'lt'|'lte'|'gt'|'gte'|'eq'|'neq'; value: number }
| { kind: 'filterBands'; value: 0|1|2|3 }
| { kind: 'filterBox'; min: Vec3; max: Vec3 }
| { kind: 'filterSphere'; center: Vec3; radius: number }
| { kind: 'filterFloaters'; voxelResolution?: number; opacityCutoff?: number; minContribution?: number } // GPU
| { kind: 'filterCluster'; voxelResolution?: number; seed?: Vec3; opacityCutoff?: number; minContribution?: number } // GPU
| { kind: 'decimate'; count: number | null; percent: number | null }
| { kind: 'param'; name: string; value: string }
| { kind: 'stats'; format?: 'text' | 'json' }
| { kind: 'info'; format?: 'text' | 'json' }
| { kind: 'mortonOrder' };
note

filterFloaters and filterCluster require a GPU device — pass createDevice via the ProcessOptions argument. processSource streams and throws on actions that need the DataTable bridge (decimate, mortonOrder, the GPU voxel filters); processSourceBridged handles every action, materializing only those runs.

Custom Logging

Configure the logger for your environment:

import { logger, TextRenderer } from '@playcanvas/splat-transform';

// Route status output (scopes, progress bars, messages) to stderr and
// pipeable output (e.g. JSON stats) to stdout
logger.setRenderer(new TextRenderer({
write: process.stderr.write.bind(process.stderr),
output: process.stdout.write.bind(process.stdout)
}));

logger.setVerbosity('quiet'); // 'quiet' | 'normal' | 'verbose'