@playcanvas/splat-transform
v1.7.0
Published
Library and CLI tool for 3D Gaussian splat format conversion and transformation
Maintainers
Readme
SplatTransform - 3D Gaussian Splat Converter
| 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.
Installation
Install or update to the latest version:
npm install -g @playcanvas/splat-transformFor library usage, install as a dependency:
npm install @playcanvas/splat-transformCLI Usage
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
nullas output to discard file output
Supported Formats
| 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
Actions can be repeated and applied in any order:
-t, --translate <x,y,z> Translate splats by (x, y, z)
-r, --rotate <x,y,z> Rotate splats by Euler angles (x, y, z) in degrees
-s, --scale <factor> Uniformly scale splats by factor
-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 <x,y,z,X,Y,Z> Remove Gaussians outside box (min, max corners)
-S, --filter-sphere <x,y,z,radius> Remove Gaussians outside sphere (center, radius)
-V, --filter-value <name,cmp,value> Keep splats where <name> <cmp> <value>
cmp ∈ {lt,lte,gt,gte,eq,neq}
-F, --filter-visibility <n|n%> Keep the n most visible splats (by opacity * volume)
Use n% to keep a percentage of splats
-p, --params <key=val,...> Pass parameters to .mjs generator script
-l, --lod <n> Specify the level of detail of this model, n >= 0.
-m, --summary Print per-column statistics to stdout
-M, --morton-order Reorder Gaussians by Morton code (Z-order curve)Global Options
-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 <n> Iterations for SOG SH compression (more=better). Default: 10
-L, --list-gpus List all available GPU adapters and exit
-g, --gpu <n|cpu> Select device for SOG compression: GPU adapter index | 'cpu'
-E, --viewer-settings <settings.json> HTML viewer settings JSON file
-U, --unbundled Generate unbundled HTML viewer with separate files
-O, --lod-select <n,n,...> Comma-separated LOD levels to read from LCC input
-C, --lod-chunk-count <n> Approx number of Gaussians per LOD chunk in K. Default: 512
-X, --lod-chunk-extent <n> Approx size of an LOD chunk in world units (m). Default: 16[!NOTE] See the SuperSplat Viewer Settings Schema for details on how to pass data to the
-Eoption.
Examples
Basic Operations
# Simple format conversion
splat-transform input.ply output.csv
# Convert from .splat format
splat-transform input.splat output.ply
# Convert from .ksplat format
splat-transform input.ksplat output.ply
# Convert to compressed PLY
splat-transform input.ply output.compressed.ply
# Uncompress a compressed PLY back to standard PLY
# (compressed .ply is detected automatically on read)
splat-transform input.compressed.ply output.ply
# Convert to SOG bundled format
splat-transform input.ply output.sog
# Convert to SOG unbundled format
splat-transform input.ply output/meta.json
# Convert from SOG (bundled) back to PLY
splat-transform scene.sog restored.ply
# Convert from SOG (unbundled folder) back to PLY
splat-transform output/meta.json restored.ply
# Convert to standalone HTML viewer (bundled, single file)
splat-transform input.ply output.html
# Convert to unbundled HTML viewer (separate CSS, JS, and SOG files)
splat-transform -U input.ply output.html
# Convert to HTML viewer with custom settings
splat-transform -E settings.json input.ply output.htmlTransformations
# Scale and translate
splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply
# Rotate by 90 degrees around Y axis
splat-transform input.ply -r 0,90,0 output.ply
# Chain multiple transformations
splat-transform input.ply -s 2 -t 1,0,0 -r 0,0,45 output.plyFiltering
# Remove entries containing NaN and Inf
splat-transform input.ply --filter-nan output.ply
# Filter by opacity values (keep only splats with opacity > 0.5)
splat-transform input.ply -V opacity,gt,0.5 output.ply
# Strip spherical harmonic bands higher than 2
splat-transform input.ply --filter-harmonics 2 output.ply
# Keep only the 50000 most visible splats
splat-transform input.ply --filter-visibility 50000 output.ply
# Keep the top 25% most visible splats
splat-transform input.ply -F 25% output.plyAdvanced Usage
# Combine multiple files with different transforms
splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply
# Apply final transformations to combined result
splat-transform input1.ply input2.ply output.ply -t 0,0,10 -s 0.5Statistical Summary
Generate per-column statistics for data analysis or test validation:
# Print summary, then write output
splat-transform input.ply --summary output.ply
# Print summary without writing a file (discard output)
splat-transform input.ply -m null
# Print summary before and after a transform
splat-transform input.ply --summary -s 0.5 --summary output.plyThe summary includes min, max, median, mean, stdDev, nanCount and infCount for each column in the data.
Generators (Beta)
Generator scripts can be used to synthesize gaussian splat data. See gen-grid.mjs for an example.
splat-transform gen-grid.mjs -p width=10,height=10,scale=10,color=0.1 scenes/grid.ply -wDevice Selection for SOG Compression
When compressing to SOG format, you can control which device (GPU or CPU) performs the compression:
# List available GPU adapters
splat-transform --list-gpus
# Let WebGPU automatically choose the best GPU (default behavior)
splat-transform input.ply output.sog
# Explicitly 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 adapter
# Use CPU for compression instead (much slower but always available)
splat-transform -g cpu input.ply output.sog[!NOTE] When
-gis not specified, WebGPU automatically selects the best available GPU. Use-Lto list available adapters with their indices and names. The order and availability of adapters depends on your system and GPU drivers. Use-g <index>to select a specific adapter, or-g cputo 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
# Show version
splat-transform --version
# Show help
splat-transform --helpLibrary Usage
SplatTransform exposes a programmatic API for reading, processing, and writing Gaussian splat data.
Basic Import
import {
readFile,
writeFile,
getInputFormat,
getOutputFormat,
DataTable,
processDataTable
} from '@playcanvas/splat-transform';Key Exports
| 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 |
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 buffersZipReadFileSystem- Read from ZIP archives
Writing:
MemoryFileSystem- Write to in-memory buffersZipFileSystem- Write to ZIP archives
Example: Reading and Processing
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');Processing Actions
The processDataTable function accepts 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: 'filterVisibility'; count: number | null; percent: number | null }
| { kind: 'lod'; value: number }
| { kind: 'summary' }
| { kind: 'mortonOrder' };Custom Logging
Configure the logger for your environment:
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