Library and CLI tool for 3D Gaussian splat format conversion and transformation
npm install @playcanvas/splat-transform





| User Guide | API Reference | Blog | Forum |
SplatTransform is an open source library and CLI tool for converting and editing Gaussian splats. It can:
š„ Read PLY, Compressed PLY, SOG, SPLAT, KSPLAT, SPZ and LCC formats
š¤ Write PLY, Compressed PLY, SOG, CSV, HTML Viewer and LOD (streaming) formats
š Generate statistical summaries for data analysis
š Merge multiple splats
š Apply transformations to input splats
šļø Filter out Gaussians or spherical harmonic bands
š Reorder splats for improved spatial locality
āļø Procedurally generate splats using JavaScript generators
The library is platform-agnostic and can be used in both Node.js and browser environments.
Install or update to the latest version:
``bash`
npm install -g @playcanvas/splat-transform
For library usage, install as a dependency:
`bash`
npm install @playcanvas/splat-transform
`bash`
splat-transform [GLOBAL] input [ACTIONS] ... output [ACTIONS]
Key points:
- Input files become the working set; ACTIONS are applied in order
- The last file is the output; actions after it modify the final result
- Use null as output to discard file output
| Format | Input | Output | Description |
| ------ | ----- | ------ | ----------- |
| .ply | ā
| ā
| Standard PLY format |.sog
| | ā
| ā
| Bundled super-compressed format (recommended) |meta.json
| | ā
| ā
| Unbundled super-compressed format (accompanied by .webp textures) |.compressed.ply
| | ā
| ā
| Compressed PLY format (auto-detected and decompressed on read) |.lcc
| | ā
| ā | LCC file format (XGRIDS) |.ksplat
| | ā
| ā | Compressed splat format (mkkellogg format) |.splat
| | ā
| ā | Compressed splat format (antimatter15 format) |.spz
| | ā
| ā | Compressed splat format (Niantic format) |.mjs
| | ā
| ā | Generate a scene using an mjs script (Beta) |.csv
| | ā | ā
| Comma-separated values spreadsheet |.html
| | ā | ā
| HTML viewer app (single-page or unbundled) based on SOG |
Actions can be repeated and applied in any order:
`none`
-t, --translate
-r, --rotate
-s, --scale
-H, --filter-harmonics <0|1|2|3> Remove spherical harmonic bands > n
-N, --filter-nan Remove Gaussians with NaN or Inf values
-B, --filter-box
-S, --filter-sphere
-V, --filter-value
cmp ā {lt,lte,gt,gte,eq,neq}
-F, --filter-visibility
Use n% to keep a percentage of splats
-p, --params
-l, --lod
-m, --summary Print per-column statistics to stdout
-M, --morton-order Reorder Gaussians by Morton code (Z-order curve)
`none`
-h, --help Show this help and exit
-v, --version Show version and exit
-q, --quiet Suppress non-error output
-w, --overwrite Overwrite output file if it exists
-i, --iterations
-L, --list-gpus List all available GPU adapters and exit
-g, --gpu
-E, --viewer-settings
-U, --unbundled Generate unbundled HTML viewer with separate files
-O, --lod-select
-C, --lod-chunk-count
-X, --lod-chunk-extent
> [!NOTE]
> See the SuperSplat Viewer Settings Schema for details on how to pass data to the -E option.
`bashSimple format conversion
splat-transform input.ply output.csv
$3
`bash
Scale and translate
splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.plyRotate by 90 degrees around Y axis
splat-transform input.ply -r 0,90,0 output.plyChain multiple transformations
splat-transform input.ply -s 2 -t 1,0,0 -r 0,0,45 output.ply
`$3
`bash
Remove entries containing NaN and Inf
splat-transform input.ply --filter-nan output.plyFilter by opacity values (keep only splats with opacity > 0.5)
splat-transform input.ply -V opacity,gt,0.5 output.plyStrip spherical harmonic bands higher than 2
splat-transform input.ply --filter-harmonics 2 output.plyKeep only the 50000 most visible splats
splat-transform input.ply --filter-visibility 50000 output.plyKeep the top 25% most visible splats
splat-transform input.ply -F 25% output.ply
`$3
`bash
Combine multiple files with different transforms
splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.plyApply final transformations to combined result
splat-transform input1.ply input2.ply output.ply -t 0,0,10 -s 0.5
`$3
Generate per-column statistics for data analysis or test validation:
`bash
Print summary, then write output
splat-transform input.ply --summary output.plyPrint summary without writing a file (discard output)
splat-transform input.ply -m nullPrint summary before and after a transform
splat-transform input.ply --summary -s 0.5 --summary output.ply
`The summary includes min, max, median, mean, stdDev, nanCount and infCount for each column in the data.
$3
Generator scripts can be used to synthesize gaussian splat data. See gen-grid.mjs for an example.
`bash
splat-transform gen-grid.mjs -p width=10,height=10,scale=10,color=0.1 scenes/grid.ply -w
`$3
When compressing to SOG format, you can control which device (GPU or CPU) performs the compression:
`bash
List available GPU adapters
splat-transform --list-gpusLet WebGPU automatically choose the best GPU (default behavior)
splat-transform input.ply output.sogExplicitly select a GPU adapter by index
splat-transform -g 0 input.ply output.sog # Use first listed adapter
splat-transform -g 1 input.ply output.sog # Use second listed adapterUse CPU for compression instead (much slower but always available)
splat-transform -g cpu input.ply output.sog
`> [!NOTE]
> When
-g is not specified, WebGPU automatically selects the best available GPU. Use -L to list available adapters with their indices and names. The order and availability of adapters depends on your system and GPU drivers. Use -g to select a specific adapter, or -g cpu to force CPU computation.> [!WARNING]
> CPU compression can be significantly slower than GPU compression (often 5-10x slower). Use CPU mode only if GPU drivers are unavailable or problematic.
Getting Help
`bash
Show version
splat-transform --versionShow help
splat-transform --help
`---
Library Usage
SplatTransform exposes a programmatic API for reading, processing, and writing Gaussian splat data.
$3
`typescript
import {
readFile,
writeFile,
getInputFormat,
getOutputFormat,
DataTable,
processDataTable
} from '@playcanvas/splat-transform';
`$3
| Export | Description |
| ------ | ----------- |
|
readFile | Read splat data from various formats |
| writeFile | Write splat data to various formats |
| getInputFormat | Detect input format from filename |
| getOutputFormat | Detect output format from filename |
| DataTable, Column | Core data structures for splat data |
| combine | Merge multiple DataTables into one |
| transform | Apply spatial transformations |
| processDataTable | Apply a sequence of processing actions |
| computeSummary | Generate statistical summary of data |
| sortMortonOrder | Sort indices by Morton code for spatial locality |
| sortByVisibility | Sort indices by visibility score for filtering |$3
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 archivesWriting:
-
MemoryFileSystem - Write to in-memory buffers
- ZipFileSystem - Write to ZIP archives$3
`typescript
import { Vec3 } from 'playcanvas';
import {
readFile,
writeFile,
getInputFormat,
getOutputFormat,
processDataTable,
UrlReadFileSystem,
MemoryFileSystem
} from '@playcanvas/splat-transform';// Read a PLY file from URL
const fileSystem = new UrlReadFileSystem();
const inputFormat = getInputFormat('scene.ply');
const dataTables = await readFile({
filename: 'https://example.com/scene.ply',
inputFormat,
options: { iterations: 10 },
params: [],
fileSystem
});
// Apply transformations
const processed = processDataTable(dataTables[0], [
{ kind: 'scale', value: 0.5 },
{ kind: 'translate', value: new Vec3(0, 1, 0) },
{ kind: 'filterNaN' }
]);
// Write to in-memory buffer
const memFs = new MemoryFileSystem();
const outputFormat = getOutputFormat('output.ply', {});
await writeFile({
filename: 'output.ply',
outputFormat,
dataTable: processed,
options: {}
}, memFs);
// Get the output data
const outputBuffer = memFs.files.get('output.ply');
`$3
The
processDataTable function accepts an array of actions:`typescript
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: 'filterVisibility'; count: number | null; percent: number | null }
| { kind: 'lod'; value: number }
| { kind: 'summary' }
| { kind: 'mortonOrder' };
`$3
Configure the logger for your environment:
`typescript
import { logger } from '@playcanvas/splat-transform';logger.setLogger({
log: console.log,
warn: console.warn,
error: console.error,
debug: console.debug,
progress: (text) => process.stdout.write(text),
output: console.log
});
logger.setQuiet(true); // Suppress non-error output
``