{"id":29726236,"url":"https://github.com/playcanvas/splat-transform","last_synced_at":"2026-02-01T13:00:47.844Z","repository":{"id":268915673,"uuid":"905829672","full_name":"playcanvas/splat-transform","owner":"playcanvas","description":"CLI tool for 3D Gaussian splat format conversion and transformation","archived":false,"fork":false,"pushed_at":"2026-01-17T20:18:43.000Z","size":742,"stargazers_count":443,"open_issues_count":14,"forks_count":48,"subscribers_count":9,"default_branch":"main","last_synced_at":"2026-01-28T03:03:36.174Z","etag":null,"topics":["3d-gaussian-splatting","cli","gaussian-splatting","playcanvas","supersplat","typescript"],"latest_commit_sha":null,"homepage":"https://playcanvas.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/playcanvas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-19T15:52:40.000Z","updated_at":"2026-01-27T00:56:03.000Z","dependencies_parsed_at":"2024-12-19T17:40:42.380Z","dependency_job_id":"bd19f7a9-0169-491e-ba29-ccdbf17dc636","html_url":"https://github.com/playcanvas/splat-transform","commit_stats":null,"previous_names":["playcanvas/splat-transform"],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/playcanvas/splat-transform","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playcanvas%2Fsplat-transform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playcanvas%2Fsplat-transform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playcanvas%2Fsplat-transform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playcanvas%2Fsplat-transform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/playcanvas","download_url":"https://codeload.github.com/playcanvas/splat-transform/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playcanvas%2Fsplat-transform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28978716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T12:13:08.691Z","status":"ssl_error","status_checked_at":"2026-02-01T12:13:08.356Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-gaussian-splatting","cli","gaussian-splatting","playcanvas","supersplat","typescript"],"created_at":"2025-07-24T23:21:08.935Z","updated_at":"2026-02-01T13:00:47.836Z","avatar_url":"https://github.com/playcanvas.png","language":"TypeScript","readme":"# SplatTransform - 3D Gaussian Splat Converter\n\n[![NPM Version](https://img.shields.io/npm/v/@playcanvas/splat-transform.svg)](https://www.npmjs.com/package/@playcanvas/splat-transform)\n[![NPM Downloads](https://img.shields.io/npm/dw/@playcanvas/splat-transform)](https://npmtrends.com/@playcanvas/splat-transform)\n[![License](https://img.shields.io/npm/l/@playcanvas/splat-transform.svg)](https://github.com/playcanvas/splat-transform/blob/main/LICENSE)\n[![Discord](https://img.shields.io/badge/Discord-5865F2?style=flat\u0026logo=discord\u0026logoColor=white\u0026color=black)](https://discord.gg/RSaMRzg)\n[![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat\u0026logo=reddit\u0026logoColor=white\u0026color=black)](https://www.reddit.com/r/PlayCanvas)\n[![X](https://img.shields.io/badge/X-000000?style=flat\u0026logo=x\u0026logoColor=white\u0026color=black)](https://x.com/intent/follow?screen_name=playcanvas)\n\n| [User Guide](https://developer.playcanvas.com/user-manual/gaussian-splatting/editing/splat-transform/) | [API Reference](https://api.playcanvas.com/splat-transform/) | [Blog](https://blog.playcanvas.com/) | [Forum](https://forum.playcanvas.com/) |\n\nSplatTransform is an open source library and CLI tool for converting and editing Gaussian splats. It can:\n\n📥 Read PLY, Compressed PLY, SOG, SPLAT, KSPLAT, SPZ and LCC formats  \n📤 Write PLY, Compressed PLY, SOG, CSV, HTML Viewer and LOD (streaming) formats  \n📊 Generate statistical summaries for data analysis  \n🔗 Merge multiple splats  \n🔄 Apply transformations to input splats  \n🎛️ Filter out Gaussians or spherical harmonic bands  \n🔀 Reorder splats for improved spatial locality  \n⚙️ Procedurally generate splats using JavaScript generators\n\nThe library is platform-agnostic and can be used in both Node.js and browser environments.\n\n## Installation\n\nInstall or update to the latest version:\n\n```bash\nnpm install -g @playcanvas/splat-transform\n```\n\nFor library usage, install as a dependency:\n\n```bash\nnpm install @playcanvas/splat-transform\n```\n\n## CLI Usage\n\n```bash\nsplat-transform [GLOBAL] input [ACTIONS]  ...  output [ACTIONS]\n```\n\n**Key points:**\n- Input files become the working set; ACTIONS are applied in order\n- The last file is the output; actions after it modify the final result\n- Use `null` as output to discard file output\n\n## Supported Formats\n\n| Format | Input | Output | Description |\n| ------ | ----- | ------ | ----------- |\n| `.ply` | ✅ | ✅ | Standard PLY format |\n| `.sog` | ✅ | ✅ | Bundled super-compressed format (recommended) |\n| `meta.json` | ✅ | ✅ | Unbundled super-compressed format (accompanied by `.webp` textures) |\n| `.compressed.ply` | ✅ | ✅ | Compressed PLY format (auto-detected and decompressed on read) |\n| `.lcc` | ✅ | ❌ | LCC file format (XGRIDS) |\n| `.ksplat` | ✅ | ❌ | Compressed splat format (mkkellogg format) |\n| `.splat` | ✅ | ❌ | Compressed splat format (antimatter15 format) |\n| `.spz` | ✅ | ❌ | Compressed splat format (Niantic format) |\n| `.mjs` | ✅ | ❌ | Generate a scene using an mjs script (Beta) |\n| `.csv` | ❌ | ✅ | Comma-separated values spreadsheet |\n| `.html` | ❌ | ✅ | HTML viewer app (single-page or unbundled) based on SOG |\n\n## Actions\n\nActions can be repeated and applied in any order:\n\n```none\n-t, --translate        \u003cx,y,z\u003e          Translate splats by (x, y, z)\n-r, --rotate           \u003cx,y,z\u003e          Rotate splats by Euler angles (x, y, z) in degrees\n-s, --scale            \u003cfactor\u003e         Uniformly scale splats by factor\n-H, --filter-harmonics \u003c0|1|2|3\u003e        Remove spherical harmonic bands \u003e n\n-N, --filter-nan                        Remove Gaussians with NaN or Inf values\n-B, --filter-box       \u003cx,y,z,X,Y,Z\u003e    Remove Gaussians outside box (min, max corners)\n-S, --filter-sphere    \u003cx,y,z,radius\u003e   Remove Gaussians outside sphere (center, radius)\n-V, --filter-value     \u003cname,cmp,value\u003e Keep splats where \u003cname\u003e \u003ccmp\u003e \u003cvalue\u003e\n                                          cmp ∈ {lt,lte,gt,gte,eq,neq}\n-p, --params           \u003ckey=val,...\u003e    Pass parameters to .mjs generator script\n-l, --lod              \u003cn\u003e              Specify the level of detail of this model, n \u003e= 0.\n-m, --summary                           Print per-column statistics to stdout\n-M, --morton-order                      Reorder Gaussians by Morton code (Z-order curve)\n```\n\n## Global Options\n\n```none\n-h, --help                              Show this help and exit\n-v, --version                           Show version and exit\n-q, --quiet                             Suppress non-error output\n-w, --overwrite                         Overwrite output file if it exists\n-i, --iterations       \u003cn\u003e              Iterations for SOG SH compression (more=better). Default: 10\n-L, --list-gpus                         List all available GPU adapters and exit\n-g, --gpu              \u003cn|cpu\u003e          Select device for SOG compression: GPU adapter index | 'cpu'\n-E, --viewer-settings  \u003csettings.json\u003e  HTML viewer settings JSON file\n-U, --unbundled                         Generate unbundled HTML viewer with separate files\n-O, --lod-select       \u003cn,n,...\u003e        Comma-separated LOD levels to read from LCC input\n-C, --lod-chunk-count  \u003cn\u003e              Approx number of Gaussians per LOD chunk in K. Default: 512\n-X, --lod-chunk-extent \u003cn\u003e              Approx size of an LOD chunk in world units (m). Default: 16\n```\n\n\u003e [!NOTE]\n\u003e See the [SuperSplat Viewer Settings Schema](https://github.com/playcanvas/supersplat-viewer?tab=readme-ov-file#settings-schema) for details on how to pass data to the `-E` option.\n\n## Examples\n\n### Basic Operations\n\n```bash\n# Simple format conversion\nsplat-transform input.ply output.csv\n\n# Convert from .splat format\nsplat-transform input.splat output.ply\n\n# Convert from .ksplat format\nsplat-transform input.ksplat output.ply\n\n# Convert to compressed PLY\nsplat-transform input.ply output.compressed.ply\n\n# Uncompress a compressed PLY back to standard PLY\n# (compressed .ply is detected automatically on read)\nsplat-transform input.compressed.ply output.ply\n\n# Convert to SOG bundled format\nsplat-transform input.ply output.sog\n\n# Convert to SOG unbundled format\nsplat-transform input.ply output/meta.json\n\n# Convert from SOG (bundled) back to PLY\nsplat-transform scene.sog restored.ply\n\n# Convert from SOG (unbundled folder) back to PLY\nsplat-transform output/meta.json restored.ply\n\n# Convert to standalone HTML viewer (bundled, single file)\nsplat-transform input.ply output.html\n\n# Convert to unbundled HTML viewer (separate CSS, JS, and SOG files)\nsplat-transform -U input.ply output.html\n\n# Convert to HTML viewer with custom settings\nsplat-transform -E settings.json input.ply output.html\n```\n\n### Transformations\n\n```bash\n# Scale and translate\nsplat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply\n\n# Rotate by 90 degrees around Y axis\nsplat-transform input.ply -r 0,90,0 output.ply\n\n# Chain multiple transformations\nsplat-transform input.ply -s 2 -t 1,0,0 -r 0,0,45 output.ply\n```\n\n### Filtering\n\n```bash\n# Remove entries containing NaN and Inf\nsplat-transform input.ply --filter-nan output.ply\n\n# Filter by opacity values (keep only splats with opacity \u003e 0.5)\nsplat-transform input.ply -V opacity,gt,0.5 output.ply\n\n# Strip spherical harmonic bands higher than 2\nsplat-transform input.ply --filter-harmonics 2 output.ply\n```\n\n### Advanced Usage\n\n```bash\n# Combine multiple files with different transforms\nsplat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply\n\n# Apply final transformations to combined result\nsplat-transform input1.ply input2.ply output.ply -t 0,0,10 -s 0.5\n```\n\n### Statistical Summary\n\nGenerate per-column statistics for data analysis or test validation:\n\n```bash\n# Print summary, then write output\nsplat-transform input.ply --summary output.ply\n\n# Print summary without writing a file (discard output)\nsplat-transform input.ply -m null\n\n# Print summary before and after a transform\nsplat-transform input.ply --summary -s 0.5 --summary output.ply\n```\n\nThe summary includes min, max, median, mean, stdDev, nanCount and infCount for each column in the data.\n\n### Generators (Beta)\n\nGenerator scripts can be used to synthesize gaussian splat data. See [gen-grid.mjs](generators/gen-grid.mjs) for an example.\n\n```bash\nsplat-transform gen-grid.mjs -p width=10,height=10,scale=10,color=0.1 scenes/grid.ply -w\n```\n\n### Device Selection for SOG Compression\n\nWhen compressing to SOG format, you can control which device (GPU or CPU) performs the compression:\n\n```bash\n# List available GPU adapters\nsplat-transform --list-gpus\n\n# Let WebGPU automatically choose the best GPU (default behavior)\nsplat-transform input.ply output.sog\n\n# Explicitly select a GPU adapter by index\nsplat-transform -g 0 input.ply output.sog  # Use first listed adapter\nsplat-transform -g 1 input.ply output.sog  # Use second listed adapter\n\n# Use CPU for compression instead (much slower but always available)\nsplat-transform -g cpu input.ply output.sog\n```\n\n\u003e [!NOTE]\n\u003e 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 \u003cindex\u003e` to select a specific adapter, or `-g cpu` to force CPU computation.\n\n\u003e [!WARNING]\n\u003e CPU compression can be significantly slower than GPU compression (often 5-10x slower). Use CPU mode only if GPU drivers are unavailable or problematic.\n\n## Getting Help\n\n```bash\n# Show version\nsplat-transform --version\n\n# Show help\nsplat-transform --help\n```\n\n---\n\n## Library Usage\n\nSplatTransform exposes a programmatic API for reading, processing, and writing Gaussian splat data.\n\n### Basic Import\n\n```typescript\nimport {\n    readFile,\n    writeFile,\n    getInputFormat,\n    getOutputFormat,\n    DataTable,\n    processDataTable\n} from '@playcanvas/splat-transform';\n```\n\n### Key Exports\n\n| Export | Description |\n| ------ | ----------- |\n| `readFile` | Read splat data from various formats |\n| `writeFile` | Write splat data to various formats |\n| `getInputFormat` | Detect input format from filename |\n| `getOutputFormat` | Detect output format from filename |\n| `DataTable`, `Column` | Core data structures for splat data |\n| `combine` | Merge multiple DataTables into one |\n| `transform` | Apply spatial transformations |\n| `processDataTable` | Apply a sequence of processing actions |\n| `computeSummary` | Generate statistical summary of data |\n| `sortMortonOrder` | Sort indices by Morton code for spatial locality |\n\n### File System Abstractions\n\nThe library uses abstract file system interfaces for maximum flexibility:\n\n**Reading:**\n- `UrlReadFileSystem` - Read from URLs (browser/Node.js)\n- `MemoryReadFileSystem` - Read from in-memory buffers\n- `ZipReadFileSystem` - Read from ZIP archives\n\n**Writing:**\n- `MemoryFileSystem` - Write to in-memory buffers\n- `ZipFileSystem` - Write to ZIP archives\n\n### Example: Reading and Processing\n\n```typescript\nimport { Vec3 } from 'playcanvas';\nimport {\n    readFile,\n    writeFile,\n    getInputFormat,\n    getOutputFormat,\n    processDataTable,\n    UrlReadFileSystem,\n    MemoryFileSystem\n} from '@playcanvas/splat-transform';\n\n// Read a PLY file from URL\nconst fileSystem = new UrlReadFileSystem();\nconst inputFormat = getInputFormat('scene.ply');\n\nconst dataTables = await readFile({\n    filename: 'https://example.com/scene.ply',\n    inputFormat,\n    options: { iterations: 10 },\n    params: [],\n    fileSystem\n});\n\n// Apply transformations\nconst processed = processDataTable(dataTables[0], [\n    { kind: 'scale', value: 0.5 },\n    { kind: 'translate', value: new Vec3(0, 1, 0) },\n    { kind: 'filterNaN' }\n]);\n\n// Write to in-memory buffer\nconst memFs = new MemoryFileSystem();\nconst outputFormat = getOutputFormat('output.ply', {});\n\nawait writeFile({\n    filename: 'output.ply',\n    outputFormat,\n    dataTable: processed,\n    options: {}\n}, memFs);\n\n// Get the output data\nconst outputBuffer = memFs.files.get('output.ply');\n```\n\n### Processing Actions\n\nThe `processDataTable` function accepts an array of actions:\n\n```typescript\ntype ProcessAction =\n    | { kind: 'translate'; value: Vec3 }\n    | { kind: 'rotate'; value: Vec3 }       // Euler angles in degrees\n    | { kind: 'scale'; value: number }\n    | { kind: 'filterNaN' }\n    | { kind: 'filterByValue'; columnName: string; comparator: 'lt'|'lte'|'gt'|'gte'|'eq'|'neq'; value: number }\n    | { kind: 'filterBands'; value: 0|1|2|3 }\n    | { kind: 'filterBox'; min: Vec3; max: Vec3 }\n    | { kind: 'filterSphere'; center: Vec3; radius: number }\n    | { kind: 'lod'; value: number }\n    | { kind: 'summary' }\n    | { kind: 'mortonOrder' };\n```\n\n### Custom Logging\n\nConfigure the logger for your environment:\n\n```typescript\nimport { logger } from '@playcanvas/splat-transform';\n\nlogger.setLogger({\n    log: console.log,\n    warn: console.warn,\n    error: console.error,\n    debug: console.debug,\n    progress: (text) =\u003e process.stdout.write(text),\n    output: console.log\n});\n\nlogger.setQuiet(true); // Suppress non-error output\n```\n","funding_links":[],"categories":["Tools \u0026 Utilities"],"sub_categories":["Data Processing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplaycanvas%2Fsplat-transform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplaycanvas%2Fsplat-transform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplaycanvas%2Fsplat-transform/lists"}